mirror of
https://github.com/Outer-Wilds-New-Horizons/new-horizons.git
synced 2025-12-11 20:15:44 +01:00
commit
230ab37c42
Binary file not shown.
@ -1,21 +1,43 @@
|
||||
using NewHorizons.External.Modules;
|
||||
using NewHorizons.External.Modules;
|
||||
using NewHorizons.External.Modules.VariableSize;
|
||||
using UnityEngine;
|
||||
namespace NewHorizons.Builder.Atmosphere
|
||||
{
|
||||
public static class SunOverrideBuilder
|
||||
{
|
||||
public static void Make(GameObject planetGO, Sector sector, AtmosphereModule atmo, float surfaceSize)
|
||||
public static void Make(GameObject planetGO, Sector sector, AtmosphereModule atmo, WaterModule water, float surfaceSize)
|
||||
{
|
||||
GameObject overrideGO = new GameObject("SunOverride");
|
||||
overrideGO.SetActive(false);
|
||||
overrideGO.transform.parent = sector?.transform ?? planetGO.transform;
|
||||
|
||||
GiantsDeepSunOverrideVolume GDSOV = overrideGO.AddComponent<GiantsDeepSunOverrideVolume>();
|
||||
GDSOV._sector = sector;
|
||||
GDSOV._cloudsOuterRadius = atmo.size;
|
||||
GDSOV._cloudsInnerRadius = atmo.size * 0.9f;
|
||||
GDSOV._waterOuterRadius = surfaceSize;
|
||||
GDSOV._waterInnerRadius = 0f;
|
||||
if (water != null)
|
||||
{
|
||||
var GDSOV = overrideGO.AddComponent<GiantsDeepSunOverrideVolume>();
|
||||
GDSOV._sector = sector;
|
||||
GDSOV._cloudsOuterRadius = atmo.clouds.outerCloudRadius;
|
||||
GDSOV._cloudsInnerRadius = atmo.clouds.innerCloudRadius;
|
||||
GDSOV._waterOuterRadius = water.size;
|
||||
GDSOV._waterInnerRadius = 0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
var sunOverride = overrideGO.AddComponent<SunOverrideVolume>();
|
||||
sunOverride._sector = sector;
|
||||
|
||||
sunOverride._overrideColor = true;
|
||||
sunOverride._color = Color.black;
|
||||
|
||||
sunOverride._overrideIntensity = true;
|
||||
sunOverride._intensity = 0f;
|
||||
|
||||
sunOverride._overrideShadowStrength = true;
|
||||
sunOverride._shadowStrength = 1f;
|
||||
|
||||
sunOverride.shape = SimpleVolume.Shape.Sphere;
|
||||
sunOverride.height = 2;
|
||||
sunOverride.radius = atmo.clouds.innerCloudRadius;
|
||||
}
|
||||
|
||||
overrideGO.transform.position = planetGO.transform.position;
|
||||
overrideGO.SetActive(true);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
using NewHorizons.Utility;
|
||||
using NewHorizons.Utility;
|
||||
using UnityEngine;
|
||||
using Logger = NewHorizons.Utility.Logger;
|
||||
namespace NewHorizons.Builder.Body.Geometry
|
||||
@ -7,13 +7,6 @@ namespace NewHorizons.Builder.Body.Geometry
|
||||
{
|
||||
public static Mesh Build(int resolution, Texture2D heightMap, float minHeight, float maxHeight, Vector3 stretch)
|
||||
{
|
||||
// It breaks if resolution is greater than 100 I don't know why
|
||||
if (resolution > 100)
|
||||
{
|
||||
Logger.LogWarning($"Can't make CubeSphere's with resolution higher than 100 for some reason");
|
||||
resolution = 100;
|
||||
}
|
||||
|
||||
Mesh mesh = new Mesh();
|
||||
mesh.name = "CubeSphere";
|
||||
|
||||
@ -109,6 +102,12 @@ namespace NewHorizons.Builder.Body.Geometry
|
||||
}
|
||||
}
|
||||
|
||||
// Higher than this and we have to use a different indexFormat
|
||||
if (vertices.Length > 65535)
|
||||
{
|
||||
mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
|
||||
}
|
||||
|
||||
mesh.vertices = vertices;
|
||||
mesh.normals = normals;
|
||||
mesh.uv = uvs;
|
||||
@ -126,7 +125,8 @@ namespace NewHorizons.Builder.Body.Geometry
|
||||
v.y = v2.y * Mathf.Sqrt(1f - x2 / 2f - z2 / 2f + x2 * z2 / 3f);
|
||||
v.z = v2.z * Mathf.Sqrt(1f - x2 / 2f - y2 / 2f + x2 * y2 / 3f);
|
||||
|
||||
var sphericals = CoordinateUtilities.CartesianToSpherical(v);
|
||||
// The shader uses real coords
|
||||
var sphericals = CoordinateUtilities.CartesianToSpherical(v, false);
|
||||
float longitude = sphericals.x;
|
||||
float latitude = sphericals.y;
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Random = UnityEngine.Random;
|
||||
@ -59,9 +59,9 @@ namespace NewHorizons.Builder.Body.Geometry
|
||||
public static Mesh Build(int subdivisions, float minHeight, float maxHeight)
|
||||
{
|
||||
Mesh mesh = new Mesh();
|
||||
mesh.name = "Icosphere";
|
||||
|
||||
if (vertices.Count <= subdivisions)
|
||||
RefineFaces(subdivisions);
|
||||
if (vertices.Count <= subdivisions) RefineFaces(subdivisions);
|
||||
|
||||
var verticesToCopy = vertices[subdivisions];
|
||||
|
||||
@ -89,6 +89,12 @@ namespace NewHorizons.Builder.Body.Geometry
|
||||
uvs[i] = new Vector2(x, y);
|
||||
}
|
||||
|
||||
// Higher than this and we have to use a different indexFormat
|
||||
if (newVertices.Length > 65535)
|
||||
{
|
||||
mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
|
||||
}
|
||||
|
||||
mesh.vertices = newVertices;
|
||||
mesh.triangles = triangles[subdivisions];
|
||||
mesh.normals = normals;
|
||||
|
||||
@ -5,14 +5,13 @@ using OWML.Common;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Logger = NewHorizons.Utility.Logger;
|
||||
using Object = UnityEngine.Object;
|
||||
namespace NewHorizons.Builder.Body
|
||||
{
|
||||
public static class HeightMapBuilder
|
||||
{
|
||||
public static Shader PlanetShader;
|
||||
|
||||
public static void Make(GameObject planetGO, Sector sector, HeightMapModule module, IModBehaviour mod, int resolution = 51)
|
||||
public static void Make(GameObject planetGO, Sector sector, HeightMapModule module, IModBehaviour mod, int resolution)
|
||||
{
|
||||
var deleteHeightmapFlag = false;
|
||||
|
||||
@ -26,8 +25,9 @@ namespace NewHorizons.Builder.Body
|
||||
else
|
||||
{
|
||||
// If we've loaded a new heightmap we'll delete the texture after
|
||||
// Only delete it if it wasnt loaded before (something else is using it)
|
||||
deleteHeightmapFlag = !ImageUtilities.IsTextureLoaded(mod, module.heightMap);
|
||||
heightMap = ImageUtilities.GetTexture(mod, module.heightMap);
|
||||
deleteHeightmapFlag = true;
|
||||
}
|
||||
|
||||
if (module.textureMap == null)
|
||||
@ -74,6 +74,7 @@ namespace NewHorizons.Builder.Body
|
||||
if (superGroup != null) cubeSphere.AddComponent<ProxyShadowCaster>()._superGroup = superGroup;
|
||||
|
||||
// Fix rotation in the end
|
||||
// 90 degree rotation around x is because cube sphere uses Z as up, Unity uses Y
|
||||
cubeSphere.transform.rotation = planetGO.transform.TransformRotation(Quaternion.Euler(90, 0, 0));
|
||||
cubeSphere.transform.position = planetGO.transform.position;
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
using NewHorizons.Components;
|
||||
using NewHorizons.Components;
|
||||
using NewHorizons.Components.SizeControllers;
|
||||
using NewHorizons.Utility;
|
||||
using OWML.Common;
|
||||
@ -45,7 +45,7 @@ namespace NewHorizons.Builder.Body
|
||||
var trigger = ringVolume.AddComponent<OWTriggerVolume>();
|
||||
trigger._shape = ringShape;
|
||||
|
||||
var sfv = ringVolume.AddComponent<SimpleFluidVolume>();
|
||||
var sfv = ringVolume.AddComponent<RingFluidVolume>();
|
||||
var fluidType = FluidVolume.Type.NONE;
|
||||
|
||||
try
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
using NewHorizons.Components.Orbital;
|
||||
using NewHorizons.Components.Orbital;
|
||||
using NewHorizons.External.Modules;
|
||||
using NewHorizons.Utility;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using Logger = NewHorizons.Utility.Logger;
|
||||
namespace NewHorizons.Builder.Orbital
|
||||
@ -13,7 +15,7 @@ namespace NewHorizons.Builder.Orbital
|
||||
return SetInitialMotionFromConfig(initialMotion, primaryBody, secondaryBody, orbit);
|
||||
}
|
||||
|
||||
public static InitialMotion SetInitialMotionFromConfig(InitialMotion initialMotion, AstroObject primaryBody, AstroObject secondaryBody, OrbitModule orbit)
|
||||
public static InitialMotion SetInitialMotionFromConfig(InitialMotion initialMotion, AstroObject primaryBody, AstroObject secondaryBody, OrbitModule orbit, bool isCustom = true)
|
||||
{
|
||||
// This bit makes the initial motion not try to calculate the orbit velocity itself for reasons
|
||||
initialMotion._orbitImpulseScalar = 0f;
|
||||
@ -21,7 +23,12 @@ namespace NewHorizons.Builder.Orbital
|
||||
// Rotation
|
||||
initialMotion._initAngularSpeed = orbit.siderealPeriod == 0 ? 0f : 2f * Mathf.PI / (orbit.siderealPeriod * 60f);
|
||||
var rotationAxis = Quaternion.AngleAxis(orbit.axialTilt, Vector3.right) * Vector3.up;
|
||||
secondaryBody.transform.rotation = Quaternion.FromToRotation(Vector3.up, rotationAxis);
|
||||
|
||||
// For things with children this is broken
|
||||
if (AstroObjectLocator.GetChildren(secondaryBody).Length == 0)
|
||||
{
|
||||
secondaryBody.transform.rotation = Quaternion.FromToRotation(Vector3.up, rotationAxis);
|
||||
}
|
||||
|
||||
if (!orbit.isStatic && primaryBody != null)
|
||||
{
|
||||
@ -36,7 +43,7 @@ namespace NewHorizons.Builder.Orbital
|
||||
return initialMotion;
|
||||
}
|
||||
|
||||
public static void SetInitialMotion(InitialMotion initialMotion, AstroObject primaryBody, AstroObject secondaryBody)
|
||||
private static void SetInitialMotion(InitialMotion initialMotion, AstroObject primaryBody, AstroObject secondaryBody)
|
||||
{
|
||||
var focalPoint = primaryBody.GetComponent<BinaryFocalPoint>();
|
||||
if (focalPoint)
|
||||
|
||||
@ -99,7 +99,18 @@ namespace NewHorizons.Builder.Props
|
||||
{
|
||||
if (component is Sector s)
|
||||
{
|
||||
s._parentSector = sector;
|
||||
s.SetParentSector(sector);
|
||||
}
|
||||
|
||||
if (component is SectorCullGroup sectorCullGroup)
|
||||
{
|
||||
sectorCullGroup._controllingProxy = null;
|
||||
}
|
||||
|
||||
// fix Sector stuff, eg SectorCullGroup (without this, props that have a SectorCullGroup component will become invisible inappropriately)
|
||||
if (component is ISectorGroup sectorGroup)
|
||||
{
|
||||
sectorGroup.SetSector(sector);
|
||||
}
|
||||
|
||||
// TODO: Make this work or smthng
|
||||
@ -119,7 +130,10 @@ namespace NewHorizons.Builder.Props
|
||||
else
|
||||
{
|
||||
var sectorField = component?.GetType()?.GetField("_sector");
|
||||
if (sectorField != null && sectorField.FieldType == typeof(Sector)) Main.Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => sectorField.SetValue(component, sector));
|
||||
if (sectorField != null && sectorField.FieldType == typeof(Sector))
|
||||
{
|
||||
Main.Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => sectorField.SetValue(component, sector));
|
||||
}
|
||||
}
|
||||
|
||||
if (component is AnglerfishController angler)
|
||||
@ -169,8 +183,7 @@ namespace NewHorizons.Builder.Props
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove things that require sectors. Will just keep extending this as things pop up
|
||||
|
||||
// Remove things that require sectors if the sector is null. Will just keep extending this as things pop up.
|
||||
if (component is FogLight or SectoredMonoBehaviour)
|
||||
{
|
||||
GameObject.DestroyImmediate(component);
|
||||
@ -188,6 +201,12 @@ namespace NewHorizons.Builder.Props
|
||||
else if (component is Collider collider) collider.enabled = true;
|
||||
else if (component is Renderer renderer) renderer.enabled = true;
|
||||
else if (component is Shape shape) shape.enabled = true;
|
||||
else if (component is SectorCullGroup sectorCullGroup)
|
||||
{
|
||||
sectorCullGroup._inMapView = false;
|
||||
sectorCullGroup._isFastForwarding = false;
|
||||
sectorCullGroup.SetVisible(sectorCullGroup.ShouldBeVisible(), true, false);
|
||||
}
|
||||
// If it's not a moving anglerfish make sure the anim controller is regular
|
||||
else if (component is AnglerfishAnimController angler && angler.GetComponentInParent<AnglerfishController>() == null)
|
||||
{
|
||||
|
||||
21
NewHorizons/Components/RingFluidVolume.cs
Normal file
21
NewHorizons/Components/RingFluidVolume.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Components
|
||||
{
|
||||
public class RingFluidVolume : SimpleFluidVolume
|
||||
{
|
||||
public override void OnEffectVolumeEnter(GameObject hitObj)
|
||||
{
|
||||
FluidDetector fluidDetector = hitObj.GetComponent<FluidDetector>();
|
||||
if (fluidDetector == null) return;
|
||||
|
||||
ForceDetector forceDetector = hitObj.GetComponent<ForceDetector>();
|
||||
if (forceDetector != null && forceDetector._activeVolumes != null && forceDetector._activeVolumes.Count > 0 && forceDetector._activeVolumes.Where(activeVolume => activeVolume is ForceVolume).Select(activeVolume => activeVolume as ForceVolume).Any(activeVolume => activeVolume.GetAffectsAlignment(forceDetector._attachedBody))) return;
|
||||
|
||||
fluidDetector.AddVolume(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -241,7 +241,7 @@ namespace NewHorizons.Components
|
||||
}
|
||||
}
|
||||
|
||||
public string UniqueIDToName(string uniqueID)
|
||||
public static string UniqueIDToName(string uniqueID)
|
||||
{
|
||||
var name = TranslationHandler.GetTranslation(uniqueID, TranslationHandler.TextType.UI);
|
||||
|
||||
|
||||
52
NewHorizons/Components/VesselOrbLocker.cs
Normal file
52
NewHorizons/Components/VesselOrbLocker.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Components
|
||||
{
|
||||
public class VesselOrbLocker : MonoBehaviour
|
||||
{
|
||||
public GameObject _coordinateInterfaceOrbObject;
|
||||
private NomaiInterfaceOrb _coordinateInterfaceOrb;
|
||||
|
||||
public GameObject _coordinateInterfaceUpperOrbObject;
|
||||
private NomaiInterfaceOrb _coordinateInterfaceUpperOrb;
|
||||
|
||||
public GameObject _powerOrbObject;
|
||||
private NomaiInterfaceOrb _powerOrb;
|
||||
|
||||
public void InitializeOrbs()
|
||||
{
|
||||
_coordinateInterfaceOrb = _coordinateInterfaceOrbObject.GetComponent<NomaiInterfaceOrb>();
|
||||
_coordinateInterfaceUpperOrb = _coordinateInterfaceUpperOrbObject.GetComponent<NomaiInterfaceOrb>();
|
||||
_powerOrb = _powerOrbObject.GetComponent<NomaiInterfaceOrb>();
|
||||
}
|
||||
|
||||
public void AddLocks()
|
||||
{
|
||||
_coordinateInterfaceOrb.AddLock();
|
||||
_coordinateInterfaceUpperOrb.AddLock();
|
||||
_powerOrb.AddLock();
|
||||
}
|
||||
|
||||
public void AddLockToCoordinateOrb()
|
||||
{
|
||||
_coordinateInterfaceOrb.AddLock();
|
||||
}
|
||||
|
||||
public void AddLockToWarpOrb()
|
||||
{
|
||||
_coordinateInterfaceUpperOrb.AddLock();
|
||||
}
|
||||
|
||||
public void AddLockToPowerOrb()
|
||||
{
|
||||
_powerOrb.AddLock();
|
||||
}
|
||||
|
||||
public void RemoveLocks()
|
||||
{
|
||||
_coordinateInterfaceOrb.RemoveAllLocks();
|
||||
_coordinateInterfaceUpperOrb.RemoveAllLocks();
|
||||
_powerOrb.RemoveAllLocks();
|
||||
}
|
||||
}
|
||||
}
|
||||
8
NewHorizons/Components/VesselSingularityRoot.cs
Normal file
8
NewHorizons/Components/VesselSingularityRoot.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Components
|
||||
{
|
||||
public class VesselSingularityRoot : MonoBehaviour
|
||||
{
|
||||
}
|
||||
}
|
||||
10
NewHorizons/External/Configs/StarSystemConfig.cs
vendored
10
NewHorizons/External/Configs/StarSystemConfig.cs
vendored
@ -1,5 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using NewHorizons.Utility;
|
||||
using Newtonsoft.Json;
|
||||
@ -102,8 +102,16 @@ namespace NewHorizons.External.Configs
|
||||
|
||||
public class NomaiCoordinates
|
||||
{
|
||||
[MinLength(2)]
|
||||
[MaxLength(6)]
|
||||
public int[] x;
|
||||
|
||||
[MinLength(2)]
|
||||
[MaxLength(6)]
|
||||
public int[] y;
|
||||
|
||||
[MinLength(2)]
|
||||
[MaxLength(6)]
|
||||
public int[] z;
|
||||
}
|
||||
|
||||
|
||||
@ -387,7 +387,7 @@ namespace NewHorizons.Handlers
|
||||
|
||||
if (body.Config.HeightMap != null)
|
||||
{
|
||||
HeightMapBuilder.Make(go, sector, body.Config.HeightMap, body.Mod);
|
||||
HeightMapBuilder.Make(go, sector, body.Config.HeightMap, body.Mod, 51);
|
||||
}
|
||||
|
||||
if (body.Config.ProcGen != null)
|
||||
@ -447,7 +447,7 @@ namespace NewHorizons.Handlers
|
||||
if (!string.IsNullOrEmpty(body.Config.Atmosphere?.clouds?.texturePath))
|
||||
{
|
||||
CloudsBuilder.Make(go, sector, body.Config.Atmosphere, body.Mod);
|
||||
SunOverrideBuilder.Make(go, sector, body.Config.Atmosphere, surfaceSize);
|
||||
SunOverrideBuilder.Make(go, sector, body.Config.Atmosphere, body.Config.Water, surfaceSize);
|
||||
}
|
||||
|
||||
if (body.Config.Atmosphere.hasRain || body.Config.Atmosphere.hasSnow)
|
||||
@ -534,7 +534,10 @@ namespace NewHorizons.Handlers
|
||||
// Since we destroyed the AO we have to replace links to it in other places
|
||||
newAO.gameObject.GetComponentInChildren<ReferenceFrameVolume>()._referenceFrame._attachedAstroObject = newAO;
|
||||
|
||||
GameObject.Destroy(go.GetComponentInChildren<OrbitLine>().gameObject);
|
||||
// QM and stuff don't have orbit lines
|
||||
var orbitLine = go.GetComponentInChildren<OrbitLine>()?.gameObject;
|
||||
if (orbitLine != null) GameObject.Destroy(orbitLine);
|
||||
|
||||
var isMoon = newAO.GetAstroObjectType() == AstroObject.Type.Moon || newAO.GetAstroObjectType() == AstroObject.Type.Satellite;
|
||||
if (body.Config.Orbit.showOrbitLine) OrbitlineBuilder.Make(go, newAO, isMoon, body.Config);
|
||||
|
||||
@ -563,7 +566,7 @@ namespace NewHorizons.Handlers
|
||||
{
|
||||
if (childAO is NHAstroObject && ExistingAOConfigs.ContainsKey(childAO))
|
||||
{
|
||||
// If it's already and NH object we repeat the whole process else it doesn't work idk
|
||||
// If it's already an NH object we repeat the whole process else it doesn't work idk
|
||||
NextPassBodies.Add(ExistingAOConfigs[childAO]);
|
||||
}
|
||||
else
|
||||
@ -583,7 +586,7 @@ namespace NewHorizons.Handlers
|
||||
}
|
||||
|
||||
// Have to do this after setting position
|
||||
InitialMotionBuilder.SetInitialMotion(im, primary, newAO);
|
||||
InitialMotionBuilder.SetInitialMotionFromConfig(im, primary, newAO, body.Config.Orbit);
|
||||
|
||||
// Have to register this new AO to the locator
|
||||
Locator.RegisterAstroObject(newAO);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
using NewHorizons.External.Configs;
|
||||
using NewHorizons.External.Configs;
|
||||
using NewHorizons.Utility;
|
||||
using System;
|
||||
using System.Collections;
|
||||
@ -42,7 +42,7 @@ namespace NewHorizons.Handlers
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogError("There must be one and only one centerOfSolarSystem!");
|
||||
Logger.LogError($"There must be one and only one centerOfSolarSystem! Found [{centers.Length}]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,6 +87,7 @@ namespace NewHorizons.Handlers
|
||||
heightMap.heightMap = body.Config.HeightMap.heightMap;
|
||||
heightMap.maxHeight = size;
|
||||
heightMap.minHeight = body.Config.HeightMap.minHeight * size / body.Config.HeightMap.maxHeight;
|
||||
heightMap.stretch = body.Config.HeightMap.stretch;
|
||||
}
|
||||
if (body.Config.Atmosphere?.clouds?.texturePath != null)
|
||||
{
|
||||
@ -96,7 +97,7 @@ namespace NewHorizons.Handlers
|
||||
heightMap.textureMap = body.Config.Atmosphere.clouds.texturePath;
|
||||
}
|
||||
|
||||
HeightMapBuilder.Make(titleScreenGO, null, heightMap, body.Mod);
|
||||
HeightMapBuilder.Make(titleScreenGO, null, heightMap, body.Mod, 30);
|
||||
|
||||
GameObject pivot = GameObject.Instantiate(SearchUtilities.Find("Scene/Background/PlanetPivot"), SearchUtilities.Find("Scene/Background").transform);
|
||||
pivot.GetComponent<RotateTransform>()._degreesPerSecond = 10f;
|
||||
|
||||
201
NewHorizons/Handlers/VesselCoordinatePromptHandler.cs
Normal file
201
NewHorizons/Handlers/VesselCoordinatePromptHandler.cs
Normal file
@ -0,0 +1,201 @@
|
||||
using NewHorizons.Components;
|
||||
using NewHorizons.Utility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using UnityEngine;
|
||||
using static NewHorizons.External.Configs.StarSystemConfig;
|
||||
|
||||
namespace NewHorizons.Handlers
|
||||
{
|
||||
public class VesselCoordinatePromptHandler
|
||||
{
|
||||
private static List<Tuple<string, string, ScreenPrompt>> _factSystemIDPrompt;
|
||||
private static List<Texture2D> _textureCache;
|
||||
|
||||
public static void RegisterPrompts(List<NewHorizonsSystem> systems)
|
||||
{
|
||||
// Have to destroy the images we've created if this isn't the first time it has run
|
||||
if (_textureCache != null)
|
||||
{
|
||||
foreach (var texture in _textureCache)
|
||||
{
|
||||
UnityEngine.Object.Destroy(texture);
|
||||
}
|
||||
}
|
||||
|
||||
_textureCache = new List<Texture2D>();
|
||||
_factSystemIDPrompt = new List<Tuple<string, string, ScreenPrompt>>();
|
||||
|
||||
foreach (var system in systems)
|
||||
{
|
||||
var systemName = system.UniqueID;
|
||||
var fact = system.Config.factRequiredForWarp;
|
||||
var nomaiCoords = system.Config.coords;
|
||||
|
||||
if (system.UniqueID == "EyeOfTheUniverse" || nomaiCoords == null) continue;
|
||||
|
||||
RegisterPrompt(systemName, fact, nomaiCoords);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RegisterPrompt(string systemID, string fact, NomaiCoordinates coords)
|
||||
{
|
||||
var texture = MakeTexture(coords.x, coords.y, coords.z);
|
||||
|
||||
_textureCache.Add(texture);
|
||||
|
||||
var sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(texture.width / 2f, texture.height / 2f));
|
||||
|
||||
var name = ShipLogStarChartMode.UniqueIDToName(systemID);
|
||||
|
||||
var prompt = new ScreenPrompt($"{name}: <EYE>", sprite, 0);
|
||||
|
||||
_factSystemIDPrompt.Add(new (fact, systemID, prompt));
|
||||
|
||||
var manager = Locator.GetPromptManager();
|
||||
manager.AddScreenPrompt(prompt, manager.GetScreenPromptList(PromptPosition.LowerLeft), manager.GetTextAnchor(PromptPosition.LowerLeft), -1, false);
|
||||
}
|
||||
|
||||
// Gets called from the patches
|
||||
public static void SetPromptVisibility(bool visible)
|
||||
{
|
||||
foreach (var pair in _factSystemIDPrompt)
|
||||
{
|
||||
var fact = pair.Item1;
|
||||
var systemID = pair.Item2;
|
||||
var prompt = pair.Item3;
|
||||
|
||||
if (visible)
|
||||
{
|
||||
if (Main.Instance.CurrentStarSystem != systemID && (string.IsNullOrEmpty(fact) || Locator.GetShipLogManager().IsFactRevealed(fact)))
|
||||
{
|
||||
prompt.SetVisibility(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
prompt.SetVisibility(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
prompt.SetVisibility(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Texture2D MakeTexture(params int[][] coords)
|
||||
{
|
||||
if (coords == null || coords.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
int width = 96;
|
||||
int height = 96;
|
||||
Texture2D texture = new Texture2D(width * coords.Length, height, TextureFormat.RGBA32, false, false);
|
||||
texture.SetPixels(Enumerable.Repeat(Color.clear, texture.width * texture.height).ToArray());
|
||||
float offset = 0f;
|
||||
for (int i = 0; i < coords.Length; i++)
|
||||
{
|
||||
if (coords[i] == null || coords[i].Length < 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// Remove extra space if coordinate doesn't use left slot
|
||||
if (!coords[i].Contains(5))
|
||||
{
|
||||
offset -= width * 0.175f;
|
||||
}
|
||||
Rect rect = new Rect(offset, 0f, width, height);
|
||||
DrawCoordinateLines(texture, rect, coords[i]);
|
||||
// Remove extra space if coordinate doesn't use right slot
|
||||
if (!coords[i].Contains(2))
|
||||
{
|
||||
offset -= width * 0.175f;
|
||||
}
|
||||
offset += width;
|
||||
}
|
||||
texture.Apply();
|
||||
return texture;
|
||||
}
|
||||
|
||||
private static void DrawCoordinateLines(Texture2D texture, Rect rect, int[] coords)
|
||||
{
|
||||
if (coords == null || coords.Length < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
float lineWidth = 3f;
|
||||
for (int i = 0; i < coords.Length - 1; i++)
|
||||
{
|
||||
// Calculate start and end points
|
||||
Vector2 size = rect.size;
|
||||
Vector2 center = size * 0.5f;
|
||||
float radius = Mathf.Min(size.x, size.y) * 0.475f - lineWidth;
|
||||
|
||||
float angle0 = Mathf.Deg2Rad * (120f - (60f * coords[i + 0]));
|
||||
Vector2 pos0 = rect.position + center + new Vector2(Mathf.Cos(angle0), Mathf.Sin(angle0)) * radius;
|
||||
Vector2 start = new Vector2(Mathf.Round(pos0.x), Mathf.Round(pos0.y));
|
||||
|
||||
float angle1 = Mathf.Deg2Rad * (120f - (60f * coords[i + 1]));
|
||||
Vector2 pos1 = rect.position + center + new Vector2(Mathf.Cos(angle1), Mathf.Sin(angle1)) * radius;
|
||||
Vector2 end = new Vector2(Mathf.Round(pos1.x), Mathf.Round(pos1.y));
|
||||
|
||||
// Draw lines
|
||||
int x0 = Mathf.FloorToInt(Mathf.Min(start.x, end.x) - lineWidth * 2f);
|
||||
int y0 = Mathf.FloorToInt(Mathf.Min(start.y, end.y) - lineWidth * 2f);
|
||||
int x1 = Mathf.CeilToInt(Mathf.Max(start.x, end.x) + lineWidth * 2f);
|
||||
int y1 = Mathf.CeilToInt(Mathf.Max(start.y, end.y) + lineWidth * 2f);
|
||||
|
||||
Vector2 dir = end - start;
|
||||
float length = dir.magnitude;
|
||||
dir.Normalize();
|
||||
|
||||
for (int x = x0; x <= x1; x++)
|
||||
{
|
||||
for (int y = y0; y <= y1; y++)
|
||||
{
|
||||
Vector2 p = new Vector2(x, y);
|
||||
float dot = Vector2.Dot(p - start, dir);
|
||||
dot = Mathf.Clamp(dot, 0f, length);
|
||||
Vector2 pointOnLine = start + dir * dot;
|
||||
float distToLine = Mathf.Max(0f, Vector2.Distance(p, pointOnLine) - lineWidth);
|
||||
if (distToLine <= 1f)
|
||||
{
|
||||
// Line is within 1 pixel, fill with color (with anti-aliased blending)
|
||||
Color color = Color.white;
|
||||
float blend = 1f - Mathf.Clamp01(distToLine);
|
||||
|
||||
if (color.a * blend < 1f)
|
||||
{
|
||||
Color existing = texture.GetPixel(x, y);
|
||||
if (existing.a > 0f)
|
||||
{
|
||||
float colorA = color.a;
|
||||
color.a = 1f;
|
||||
texture.SetPixel(x, y, Color.Lerp(existing, color, Mathf.Clamp01(colorA * blend)));
|
||||
} else
|
||||
{
|
||||
color.a *= blend;
|
||||
texture.SetPixel(x, y, color);
|
||||
}
|
||||
} else
|
||||
{
|
||||
color.a *= blend;
|
||||
texture.SetPixel(x, y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool KnowsEyeCoordinates()
|
||||
{
|
||||
// Works normally in the main system, else check save data directly
|
||||
if (Main.Instance.CurrentStarSystem == "SolarSystem") return Locator.GetShipLogManager().IsFactRevealed("OPC_EYE_COORDINATES_X1");
|
||||
else return PlayerData._currentGameSave.shipLogFactSaves.ContainsKey("OPC_EYE_COORDINATES_X1");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using NewHorizons.Components;
|
||||
using NewHorizons.Utility;
|
||||
using Logger = NewHorizons.Utility.Logger;
|
||||
using static NewHorizons.Main;
|
||||
@ -83,44 +84,53 @@ namespace NewHorizons.Handlers
|
||||
vesselObject.name = VesselPrefab.name;
|
||||
vesselObject.transform.parent = null;
|
||||
|
||||
VesselOrbLocker vesselOrbLocker = vesselObject.GetComponent<VesselOrbLocker>();
|
||||
vesselOrbLocker.InitializeOrbs();
|
||||
vesselOrbLocker.AddLocks();
|
||||
|
||||
if (system.Config.vesselPosition != null)
|
||||
vesselObject.transform.position += system.Config.vesselPosition;
|
||||
|
||||
if (system.Config.vesselRotation != null)
|
||||
vesselObject.transform.eulerAngles = system.Config.vesselRotation;
|
||||
|
||||
vesselOrbLocker.RemoveLocks();
|
||||
vesselOrbLocker.AddLockToWarpOrb();
|
||||
|
||||
VesselSingularityRoot singularityRoot = vesselObject.GetComponentInChildren<VesselSingularityRoot>(true);
|
||||
|
||||
VesselWarpController vesselWarpController = vesselObject.GetComponentInChildren<VesselWarpController>(true);
|
||||
WarpController = vesselWarpController;
|
||||
|
||||
vesselWarpController._sourceWarpPlatform.transform.DestroyAllChildren();
|
||||
vesselWarpController._targetWarpPlatform.transform.DestroyAllChildren();
|
||||
GameObject.Destroy(vesselWarpController._blackHole.transform.parent.gameObject);
|
||||
GameObject.Destroy(vesselWarpController._whiteHole.transform.parent.gameObject);
|
||||
|
||||
GameObject WarpPlatform = SearchUtilities.Find("DB_VesselDimension_Body/Sector_VesselDimension/Sector_VesselBridge/Interactibles_VesselBridge/WarpController/Prefab_NOM_WarpPlatform");
|
||||
GameObject warpBH = WarpPlatform.transform.Find("BlackHole").gameObject;
|
||||
GameObject warpWH = WarpPlatform.transform.Find("WhiteHole").gameObject;
|
||||
|
||||
GameObject sourceBH = GameObject.Instantiate(warpBH, vesselWarpController._sourceWarpPlatform.transform, false);
|
||||
sourceBH.name = "BlackHole";
|
||||
vesselWarpController._sourceWarpPlatform._blackHole = sourceBH.GetComponentInChildren<SingularityController>();
|
||||
|
||||
|
||||
GameObject sourceWH = GameObject.Instantiate(warpWH, vesselWarpController._sourceWarpPlatform.transform, false);
|
||||
sourceWH.name = "WhiteHole";
|
||||
vesselWarpController._sourceWarpPlatform._whiteHole = sourceWH.GetComponentInChildren<SingularityController>();
|
||||
|
||||
GameObject targetBH = GameObject.Instantiate(warpBH, vesselWarpController._targetWarpPlatform.transform, false);
|
||||
targetBH.name = "BlackHole";
|
||||
vesselWarpController._targetWarpPlatform._blackHole = targetBH.GetComponentInChildren<SingularityController>();
|
||||
|
||||
GameObject targetWH = GameObject.Instantiate(warpWH, vesselWarpController._targetWarpPlatform.transform, false);
|
||||
targetWH.name = "WhiteHole";
|
||||
vesselWarpController._targetWarpPlatform._whiteHole = targetWH.GetComponentInChildren<SingularityController>();
|
||||
|
||||
GameObject blackHole = SearchUtilities.Find("DB_VesselDimension_Body/Sector_VesselDimension/Sector_VesselBridge/Interactibles_VesselBridge/BlackHole");
|
||||
GameObject newBlackHole = GameObject.Instantiate(blackHole, vesselWarpController.transform.parent, false);
|
||||
GameObject newBlackHole = GameObject.Instantiate(blackHole, Vector3.zero, Quaternion.identity, singularityRoot.transform);
|
||||
newBlackHole.name = "BlackHole";
|
||||
vesselWarpController._blackHole = newBlackHole.GetComponentInChildren<SingularityController>();
|
||||
vesselWarpController._blackHoleOneShot = vesselWarpController._blackHole.transform.parent.Find("BlackHoleAudio_OneShot").GetComponent<OWAudioSource>();
|
||||
|
||||
GameObject whiteHole = SearchUtilities.Find("DB_VesselDimension_Body/Sector_VesselDimension/Sector_VesselBridge/Interactibles_VesselBridge/WhiteHole");
|
||||
GameObject newWhiteHole = GameObject.Instantiate(whiteHole, vesselWarpController.transform.parent, false);
|
||||
GameObject newWhiteHole = GameObject.Instantiate(whiteHole, Vector3.zero, Quaternion.identity, singularityRoot.transform);
|
||||
newWhiteHole.name = "WhiteHole";
|
||||
vesselWarpController._whiteHole = newWhiteHole.GetComponentInChildren<SingularityController>();
|
||||
vesselWarpController._whiteHoleOneShot = vesselWarpController._whiteHole.transform.parent.Find("WhiteHoleAudio_OneShot").GetComponent<OWAudioSource>();
|
||||
@ -133,7 +143,7 @@ namespace NewHorizons.Handlers
|
||||
vesselWarpController._targetWarpPlatform.transform.localPosition = system.Config.warpExitPosition;
|
||||
|
||||
if (system.Config.warpExitRotation != null)
|
||||
vesselObject.transform.localEulerAngles = system.Config.warpExitRotation;
|
||||
vesselWarpController._targetWarpPlatform.transform.localEulerAngles = system.Config.warpExitRotation;
|
||||
|
||||
vesselObject.GetComponent<MapMarker>()._labelID = (UITextType)TranslationHandler.AddUI("VESSEL");
|
||||
|
||||
@ -227,8 +237,6 @@ namespace NewHorizons.Handlers
|
||||
vesselWarpController._cageAnimator.OnTranslationComplete -= new TransformAnimator.AnimationEvent(vesselWarpController.OnCageAnimationComplete);
|
||||
vesselWarpController._cageAnimator.OnTranslationComplete += new TransformAnimator.AnimationEvent(vesselWarpController.OnCageAnimationComplete);
|
||||
}
|
||||
if (vesselWarpController._cageLoopingAudio != null)
|
||||
vesselWarpController._cageLoopingAudio.FadeIn(1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,15 +198,6 @@ namespace NewHorizons
|
||||
private static void OnWakeUp()
|
||||
{
|
||||
IsSystemReady = true;
|
||||
try
|
||||
{
|
||||
Logger.Log($"Star system loaded [{Instance.CurrentStarSystem}]");
|
||||
Instance.OnStarSystemLoaded?.Invoke(Instance.CurrentStarSystem);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError($"Exception thrown when invoking star system loaded event with parameter [{Instance.CurrentStarSystem}] : {e.GetType().FullName} {e.Message} {e.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSceneUnloaded(Scene scene)
|
||||
@ -302,6 +293,16 @@ namespace NewHorizons
|
||||
|
||||
// Fix the map satellite
|
||||
SearchUtilities.Find("HearthianMapSatellite_Body", false).AddComponent<MapSatelliteOrbitFix>();
|
||||
|
||||
try
|
||||
{
|
||||
Logger.Log($"Star system loaded [{Instance.CurrentStarSystem}]");
|
||||
Instance.OnStarSystemLoaded?.Invoke(Instance.CurrentStarSystem);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError($"Exception thrown when invoking star system loaded event with parameter [{Instance.CurrentStarSystem}] : {e.GetType().FullName} {e.Message} {e.StackTrace}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -331,6 +332,8 @@ namespace NewHorizons
|
||||
if (shouldWarpInFromShip) _shipWarpController.WarpIn(WearingSuit);
|
||||
else if (shouldWarpInFromVessel) VesselWarpHandler.TeleportToVessel();
|
||||
else FindObjectOfType<PlayerSpawner>().DebugWarp(SystemDict[_currentStarSystem].SpawnPoint);
|
||||
|
||||
VesselCoordinatePromptHandler.RegisterPrompts(SystemDict.Where(system => system.Value.Config.coords != null).Select(x => x.Value).ToList());
|
||||
}
|
||||
|
||||
public void EnableWarpDrive()
|
||||
@ -368,7 +371,11 @@ namespace NewHorizons
|
||||
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);
|
||||
if (name != "SolarSystem")
|
||||
{
|
||||
SetDefaultSystem(name);
|
||||
_currentStarSystem = name;
|
||||
}
|
||||
}
|
||||
|
||||
if (SystemDict.ContainsKey(name))
|
||||
@ -446,15 +453,15 @@ namespace NewHorizons
|
||||
if (!foundFile) Logger.LogWarning($"{mod.ModHelper.Manifest.Name} has a folder for translations but none were loaded");
|
||||
}
|
||||
|
||||
public NewHorizonsBody LoadConfig(IModBehaviour mod, string relativeDirectory)
|
||||
public NewHorizonsBody LoadConfig(IModBehaviour mod, string relativePath)
|
||||
{
|
||||
NewHorizonsBody body = null;
|
||||
try
|
||||
{
|
||||
var config = mod.ModHelper.Storage.Load<PlanetConfig>(relativeDirectory);
|
||||
var config = mod.ModHelper.Storage.Load<PlanetConfig>(relativePath);
|
||||
if (config == null)
|
||||
{
|
||||
Logger.LogError($"Couldn't load {relativeDirectory}. Is your Json formatted correctly?");
|
||||
Logger.LogError($"Couldn't load {relativePath}. Is your Json formatted correctly?");
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -479,11 +486,11 @@ namespace NewHorizons
|
||||
// Has to happen after we make sure theres a system config
|
||||
config.MigrateAndValidate();
|
||||
|
||||
body = new NewHorizonsBody(config, mod, relativeDirectory);
|
||||
body = new NewHorizonsBody(config, mod, relativePath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError($"Error encounter when loading {relativeDirectory}: {e.Message} {e.StackTrace}");
|
||||
Logger.LogError($"Error encounter when loading {relativePath}: {e.Message} {e.StackTrace}");
|
||||
}
|
||||
|
||||
return body;
|
||||
@ -492,7 +499,6 @@ namespace NewHorizons
|
||||
public void SetDefaultSystem(string defaultSystem)
|
||||
{
|
||||
_defaultStarSystem = defaultSystem;
|
||||
_currentStarSystem = defaultSystem;
|
||||
}
|
||||
|
||||
#endregion Load
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
using NewHorizons.Builder.Props;
|
||||
using NewHorizons.Builder.Props;
|
||||
using NewHorizons.Utility;
|
||||
using OWML.Common;
|
||||
using OWML.Utils;
|
||||
@ -77,6 +77,14 @@ namespace NewHorizons
|
||||
return Main.Instance.OnStarSystemLoaded;
|
||||
}
|
||||
|
||||
public bool SetDefaultSystem(string name)
|
||||
{
|
||||
if (!Main.SystemDict.ContainsKey(name)) return false;
|
||||
|
||||
Main.Instance.SetDefaultSystem(name);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool ChangeCurrentStarSystem(string name)
|
||||
{
|
||||
if (!Main.SystemDict.ContainsKey(name)) return false;
|
||||
|
||||
34
NewHorizons/Patches/EyeCoordinatePromptTriggerPatches.cs
Normal file
34
NewHorizons/Patches/EyeCoordinatePromptTriggerPatches.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using HarmonyLib;
|
||||
using NewHorizons.Handlers;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Patches
|
||||
{
|
||||
[HarmonyPatch]
|
||||
public static class EyeCoordinatePromptTriggerPatches
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(EyeCoordinatePromptTrigger), nameof(EyeCoordinatePromptTrigger.Update))]
|
||||
public static bool EyeCoordinatePromptTrigger_Update(EyeCoordinatePromptTrigger __instance)
|
||||
{
|
||||
var showPrompts = __instance._warpController.HasPower();
|
||||
|
||||
// In other systems checking if the proper fact is revealed doesn't work, so we just overwrite this function
|
||||
__instance._promptController.SetEyeCoordinatesVisibility(showPrompts && VesselCoordinatePromptHandler.KnowsEyeCoordinates());
|
||||
|
||||
VesselCoordinatePromptHandler.SetPromptVisibility(showPrompts);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(EyeCoordinatePromptTrigger), nameof(EyeCoordinatePromptTrigger.OnExit))]
|
||||
public static void EyeCoordinatePromptTrigger_OnExit(GameObject __0)
|
||||
{
|
||||
if (__0.CompareTag("PlayerDetector"))
|
||||
{
|
||||
VesselCoordinatePromptHandler.SetPromptVisibility(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -115,6 +115,9 @@
|
||||
"properties": {
|
||||
"x": {
|
||||
"type": "array",
|
||||
"maxItems": 6,
|
||||
"minItems": 2,
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
@ -122,6 +125,9 @@
|
||||
},
|
||||
"y": {
|
||||
"type": "array",
|
||||
"maxItems": 6,
|
||||
"minItems": 2,
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
@ -129,6 +135,9 @@
|
||||
},
|
||||
"z": {
|
||||
"type": "array",
|
||||
"maxItems": 6,
|
||||
"minItems": 2,
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
|
||||
@ -1,148 +1,151 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
namespace NewHorizons.Utility
|
||||
{
|
||||
public static class AstroObjectLocator
|
||||
{
|
||||
private static Dictionary<string, AstroObject> _customAstroObjectDictionary = new Dictionary<string, AstroObject>();
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
_customAstroObjectDictionary = new Dictionary<string, AstroObject>();
|
||||
foreach (AstroObject ao in GameObject.FindObjectsOfType<AstroObject>())
|
||||
{
|
||||
// Ignore the sun station debris, we handle it as a child of the sun station
|
||||
if (ao.gameObject.name == "SS_Debris_Body") continue;
|
||||
|
||||
RegisterCustomAstroObject(ao);
|
||||
}
|
||||
}
|
||||
|
||||
public static AstroObject GetAstroObject(string name, bool flag = false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name)) return null;
|
||||
|
||||
if (_customAstroObjectDictionary.ContainsKey(name))
|
||||
{
|
||||
return _customAstroObjectDictionary[name];
|
||||
}
|
||||
|
||||
// Else check stock names
|
||||
var stringID = name.ToUpper().Replace(" ", "_").Replace("'", "");
|
||||
if (stringID.Equals("ATTLEROCK")) stringID = "TIMBER_MOON";
|
||||
if (stringID.Equals("HOLLOWS_LANTERN")) stringID = "VOLCANIC_MOON";
|
||||
if (stringID.Equals("ASH_TWIN")) stringID = "TOWER_TWIN";
|
||||
if (stringID.Equals("EMBER_TWIN")) stringID = "CAVE_TWIN";
|
||||
if (stringID.Equals("INTERLOPER")) stringID = "COMET";
|
||||
|
||||
string key;
|
||||
if (stringID.ToUpper().Replace("_", "").Equals("MAPSATELLITE"))
|
||||
{
|
||||
key = AstroObject.Name.MapSatellite.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
key = AstroObject.StringIDToAstroObjectName(stringID).ToString();
|
||||
}
|
||||
|
||||
if (_customAstroObjectDictionary.ContainsKey(key))
|
||||
{
|
||||
return _customAstroObjectDictionary[key];
|
||||
}
|
||||
|
||||
// Try again
|
||||
if (!flag) return GetAstroObject(name.Replace(" ", ""), true);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void RegisterCustomAstroObject(AstroObject ao)
|
||||
{
|
||||
var key = ao._name == AstroObject.Name.CustomString ? ao.GetCustomName() : ao._name.ToString();
|
||||
|
||||
if (_customAstroObjectDictionary.Keys.Contains(key))
|
||||
{
|
||||
Logger.LogWarning($"Registering duplicate [{ao.name}] as [{key}]");
|
||||
_customAstroObjectDictionary[key] = ao;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Log($"Registering [{ao.name}] as [{key}]");
|
||||
_customAstroObjectDictionary.Add(key, ao);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DeregisterCustomAstroObject(AstroObject ao)
|
||||
{
|
||||
var key = ao._name == AstroObject.Name.CustomString ? ao.GetCustomName() : ao._name.ToString();
|
||||
_customAstroObjectDictionary.Remove(key);
|
||||
}
|
||||
|
||||
public static AstroObject[] GetAllAstroObjects()
|
||||
{
|
||||
return _customAstroObjectDictionary.Values.ToArray();
|
||||
}
|
||||
|
||||
public static GameObject[] GetMoons(AstroObject primary)
|
||||
{
|
||||
return _customAstroObjectDictionary.Values.Where(x => x._primaryBody == primary).Select(x => x.gameObject).ToArray();
|
||||
}
|
||||
|
||||
public static GameObject[] GetChildren(AstroObject primary)
|
||||
{
|
||||
if (primary == null) return new GameObject[0];
|
||||
|
||||
var otherChildren = new List<GameObject>();
|
||||
switch (primary._name)
|
||||
{
|
||||
case AstroObject.Name.TowerTwin:
|
||||
otherChildren.Add(SearchUtilities.Find("TimeLoopRing_Body"));
|
||||
break;
|
||||
case AstroObject.Name.ProbeCannon:
|
||||
otherChildren.Add(SearchUtilities.Find("NomaiProbe_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("CannonMuzzle_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("FakeCannonMuzzle_Body (1)"));
|
||||
otherChildren.Add(SearchUtilities.Find("CannonBarrel_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("FakeCannonBarrel_Body (1)"));
|
||||
otherChildren.Add(SearchUtilities.Find("Debris_Body (1)"));
|
||||
break;
|
||||
case AstroObject.Name.GiantsDeep:
|
||||
otherChildren.Add(SearchUtilities.Find("BrambleIsland_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("GabbroIsland_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("QuantumIsland_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("StatueIsland_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("ConstructionYardIsland_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("GabbroShip_Body"));
|
||||
break;
|
||||
case AstroObject.Name.WhiteHole:
|
||||
otherChildren.Add(SearchUtilities.Find("WhiteholeStation_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("WhiteholeStationSuperstructure_Body"));
|
||||
break;
|
||||
case AstroObject.Name.TimberHearth:
|
||||
otherChildren.Add(SearchUtilities.Find("MiningRig_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("Ship_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("ModelRocket_Body"));
|
||||
break;
|
||||
case AstroObject.Name.DreamWorld:
|
||||
otherChildren.Add(SearchUtilities.Find("BackRaft_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("SealRaft_Body"));
|
||||
break;
|
||||
// For some dumb reason the sun station doesn't use AstroObject.Name.SunStation
|
||||
case AstroObject.Name.CustomString:
|
||||
if (primary._customName.Equals("Sun Station"))
|
||||
{
|
||||
// there are multiple debris with the same name
|
||||
otherChildren.AddRange(Object.FindObjectsOfType<AstroObject>()
|
||||
.Select(x => x.gameObject)
|
||||
.Where(x => x.name == "SS_Debris_Body"));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return otherChildren.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
namespace NewHorizons.Utility
|
||||
{
|
||||
public static class AstroObjectLocator
|
||||
{
|
||||
private static Dictionary<string, AstroObject> _customAstroObjectDictionary = new Dictionary<string, AstroObject>();
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
_customAstroObjectDictionary = new Dictionary<string, AstroObject>();
|
||||
foreach (AstroObject ao in GameObject.FindObjectsOfType<AstroObject>())
|
||||
{
|
||||
// Ignore the sun station debris, we handle it as a child of the sun station
|
||||
if (ao.gameObject.name == "SS_Debris_Body") continue;
|
||||
|
||||
RegisterCustomAstroObject(ao);
|
||||
}
|
||||
}
|
||||
|
||||
public static AstroObject GetAstroObject(string name, bool flag = false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name)) return null;
|
||||
|
||||
if (_customAstroObjectDictionary.ContainsKey(name))
|
||||
{
|
||||
return _customAstroObjectDictionary[name];
|
||||
}
|
||||
|
||||
// Else check stock names
|
||||
var stringID = name.ToUpper().Replace(" ", "_").Replace("'", "");
|
||||
if (stringID.Equals("ATTLEROCK")) stringID = "TIMBER_MOON";
|
||||
if (stringID.Equals("HOLLOWS_LANTERN")) stringID = "VOLCANIC_MOON";
|
||||
if (stringID.Equals("ASH_TWIN")) stringID = "TOWER_TWIN";
|
||||
if (stringID.Equals("EMBER_TWIN")) stringID = "CAVE_TWIN";
|
||||
if (stringID.Equals("INTERLOPER")) stringID = "COMET";
|
||||
|
||||
string key;
|
||||
if (stringID.ToUpper().Replace("_", "").Equals("MAPSATELLITE"))
|
||||
{
|
||||
key = AstroObject.Name.MapSatellite.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
key = AstroObject.StringIDToAstroObjectName(stringID).ToString();
|
||||
}
|
||||
|
||||
if (_customAstroObjectDictionary.ContainsKey(key))
|
||||
{
|
||||
return _customAstroObjectDictionary[key];
|
||||
}
|
||||
|
||||
// Try again
|
||||
if (!flag) return GetAstroObject(name.Replace(" ", ""), true);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void RegisterCustomAstroObject(AstroObject ao)
|
||||
{
|
||||
var key = ao._name == AstroObject.Name.CustomString ? ao.GetCustomName() : ao._name.ToString();
|
||||
|
||||
if (_customAstroObjectDictionary.Keys.Contains(key))
|
||||
{
|
||||
Logger.LogWarning($"Registering duplicate [{ao.name}] as [{key}]");
|
||||
_customAstroObjectDictionary[key] = ao;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Log($"Registering [{ao.name}] as [{key}]");
|
||||
_customAstroObjectDictionary.Add(key, ao);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DeregisterCustomAstroObject(AstroObject ao)
|
||||
{
|
||||
var key = ao._name == AstroObject.Name.CustomString ? ao.GetCustomName() : ao._name.ToString();
|
||||
_customAstroObjectDictionary.Remove(key);
|
||||
}
|
||||
|
||||
public static AstroObject[] GetAllAstroObjects()
|
||||
{
|
||||
return _customAstroObjectDictionary.Values.ToArray();
|
||||
}
|
||||
|
||||
public static GameObject[] GetMoons(AstroObject primary)
|
||||
{
|
||||
return _customAstroObjectDictionary.Values.Where(x => x._primaryBody == primary).Select(x => x.gameObject).ToArray();
|
||||
}
|
||||
|
||||
public static GameObject[] GetChildren(AstroObject primary)
|
||||
{
|
||||
if (primary == null) return new GameObject[0];
|
||||
|
||||
var otherChildren = new List<GameObject>();
|
||||
switch (primary._name)
|
||||
{
|
||||
case AstroObject.Name.TowerTwin:
|
||||
otherChildren.Add(SearchUtilities.Find("TimeLoopRing_Body"));
|
||||
break;
|
||||
case AstroObject.Name.ProbeCannon:
|
||||
otherChildren.Add(SearchUtilities.Find("NomaiProbe_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("CannonMuzzle_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("FakeCannonMuzzle_Body (1)"));
|
||||
otherChildren.Add(SearchUtilities.Find("CannonBarrel_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("FakeCannonBarrel_Body (1)"));
|
||||
otherChildren.Add(SearchUtilities.Find("Debris_Body (1)"));
|
||||
break;
|
||||
case AstroObject.Name.GiantsDeep:
|
||||
otherChildren.Add(SearchUtilities.Find("BrambleIsland_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("GabbroIsland_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("QuantumIsland_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("StatueIsland_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("ConstructionYardIsland_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("GabbroShip_Body"));
|
||||
break;
|
||||
case AstroObject.Name.WhiteHole:
|
||||
otherChildren.Add(SearchUtilities.Find("WhiteholeStation_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("WhiteholeStationSuperstructure_Body"));
|
||||
break;
|
||||
case AstroObject.Name.TimberHearth:
|
||||
otherChildren.Add(SearchUtilities.Find("MiningRig_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("Ship_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("ModelRocket_Body"));
|
||||
break;
|
||||
case AstroObject.Name.DreamWorld:
|
||||
otherChildren.Add(SearchUtilities.Find("BackRaft_Body"));
|
||||
otherChildren.Add(SearchUtilities.Find("SealRaft_Body"));
|
||||
break;
|
||||
case AstroObject.Name.MapSatellite:
|
||||
otherChildren.Add(SearchUtilities.Find("HearthianRecorder_Body"));
|
||||
break;
|
||||
// For some dumb reason the sun station doesn't use AstroObject.Name.SunStation
|
||||
case AstroObject.Name.CustomString:
|
||||
if (primary._customName.Equals("Sun Station"))
|
||||
{
|
||||
// there are multiple debris with the same name
|
||||
otherChildren.AddRange(Object.FindObjectsOfType<AstroObject>()
|
||||
.Select(x => x.gameObject)
|
||||
.Where(x => x.name == "SS_Debris_Body"));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return otherChildren.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,17 +1,65 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine;
|
||||
namespace NewHorizons.Utility
|
||||
{
|
||||
public static class CoordinateUtilities
|
||||
{
|
||||
public static Vector3 CartesianToSpherical(Vector3 v)
|
||||
// Longitude and latitude are in degrees
|
||||
// Using the phi and theta convention used on https://mathworld.wolfram.com/SphericalCoordinates.html (Mathematics not physics convention)
|
||||
public static Vector3 CartesianToSpherical(Vector3 v, bool useUnityCoords = true)
|
||||
{
|
||||
float dist = Mathf.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
|
||||
float latitude = (Mathf.Rad2Deg * Mathf.Acos(v.z / dist));
|
||||
float x, y, z;
|
||||
if (useUnityCoords)
|
||||
{
|
||||
// Y is up in unity
|
||||
x = v.x;
|
||||
y = v.z;
|
||||
z = v.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
z = v.z;
|
||||
}
|
||||
|
||||
float dist = Mathf.Sqrt(x * x + y * y + z * z);
|
||||
|
||||
// theta
|
||||
float longitude = 180f;
|
||||
if (v.x > 0) longitude = Mathf.Rad2Deg * Mathf.Atan(v.y / v.x);
|
||||
if (v.x < 0) longitude = Mathf.Rad2Deg * (Mathf.Atan(v.y / v.x) + Mathf.PI);
|
||||
if (x > 0) longitude = Mathf.Rad2Deg * Mathf.Atan(y / x);
|
||||
if (x < 0) longitude = Mathf.Rad2Deg * (Mathf.Atan(y / x) + Mathf.PI);
|
||||
|
||||
// phi
|
||||
float latitude = (Mathf.Rad2Deg * Mathf.Acos(z / dist));
|
||||
|
||||
return new Vector3(longitude, latitude, dist);
|
||||
}
|
||||
|
||||
public static Vector3 SphericalToCartesian(Vector3 v, bool useUnityCoords = true)
|
||||
{
|
||||
var longitude = v.x;
|
||||
var latitude = v.y;
|
||||
var r = v.z;
|
||||
|
||||
var theta = Mathf.Deg2Rad * longitude;
|
||||
var phi = Mathf.Deg2Rad * latitude;
|
||||
|
||||
float x, y, z;
|
||||
|
||||
if (useUnityCoords)
|
||||
{
|
||||
x = r * Mathf.Cos(theta) * Mathf.Sin(phi);
|
||||
z = r * Mathf.Sin(theta) * Mathf.Sin(phi);
|
||||
y = r * Mathf.Cos(phi);
|
||||
}
|
||||
else
|
||||
{
|
||||
x = r * Mathf.Cos(theta) * Mathf.Sin(phi);
|
||||
y = r * Mathf.Sin(theta) * Mathf.Sin(phi);
|
||||
z = r * Mathf.Cos(phi);
|
||||
}
|
||||
|
||||
return new Vector3(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,17 +28,16 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
static bool openMenuOnPause;
|
||||
static bool staticInitialized;
|
||||
|
||||
// menu params
|
||||
// Menu params
|
||||
internal static IModBehaviour loadedMod = null;
|
||||
internal Dictionary<string, PlanetConfig> loadedConfigFiles = new Dictionary<string, PlanetConfig>();
|
||||
private bool saveButtonUnlocked = false;
|
||||
private Vector2 recentModListScrollPosition = Vector2.zero;
|
||||
|
||||
// submenus
|
||||
// Submenus
|
||||
private List<DebugSubmenu> submenus;
|
||||
private int activeSubmenu = 0;
|
||||
|
||||
|
||||
private static JsonSerializerSettings jsonSettings = new JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
@ -55,7 +54,6 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
new DebugMenuNomaiText()
|
||||
};
|
||||
|
||||
|
||||
submenus.ForEach((submenu) => submenu.OnAwake(this));
|
||||
}
|
||||
|
||||
@ -89,6 +87,7 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
pauseMenuButton = Main.Instance.ModHelper.Menus.PauseMenu.OptionsButton.Duplicate(TranslationHandler.GetTranslation("Toggle Dev Tools Menu", TranslationHandler.TextType.UI).ToUpper());
|
||||
InitMenu();
|
||||
}
|
||||
|
||||
public static void UpdatePauseMenuButton()
|
||||
{
|
||||
if (pauseMenuButton != null)
|
||||
@ -99,11 +98,11 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
}
|
||||
|
||||
private void RestoreMenuOpennessState() { menuOpen = openMenuOnPause; }
|
||||
|
||||
private void ToggleMenu() { menuOpen = !menuOpen; openMenuOnPause = !openMenuOnPause; }
|
||||
|
||||
private void CloseMenu() { menuOpen = false; }
|
||||
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
if (!menuOpen) return;
|
||||
@ -113,8 +112,7 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
|
||||
GUILayout.BeginArea(new Rect(menuPosition.x, menuPosition.y, EditorMenuSize.x, EditorMenuSize.y), _editorMenuStyle);
|
||||
|
||||
// continue working on existing mod
|
||||
|
||||
// Continue working on existing mod
|
||||
GUILayout.Label("Name of your mod");
|
||||
if (loadedMod == null)
|
||||
{
|
||||
@ -138,9 +136,9 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
|
||||
GUILayout.Space(5);
|
||||
|
||||
// save your work
|
||||
|
||||
if (loadedMod != null) {
|
||||
// Save your work
|
||||
if (loadedMod != null)
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button(saveButtonUnlocked ? " O " : " | ", GUILayout.ExpandWidth(false)))
|
||||
{
|
||||
@ -157,23 +155,23 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
}
|
||||
|
||||
GUILayout.Space(20);
|
||||
|
||||
// draw submenu stuff
|
||||
|
||||
// Draw submenu stuff
|
||||
if (loadedMod != null)
|
||||
{
|
||||
GUILayout.BeginHorizontal(_tabBarStyle);
|
||||
GUILayout.Space(5);
|
||||
for (int i = 0; i < submenus.Count; i++)
|
||||
for (int i = 0; i < submenus.Count; i++)
|
||||
{
|
||||
GUI.enabled = i != activeSubmenu;
|
||||
var style = i == activeSubmenu ? _submenuStyle : _tabBarStyle;
|
||||
if (GUILayout.Button(" "+submenus[i].SubmenuName()+" ", style, GUILayout.ExpandWidth(false)))
|
||||
{
|
||||
if (GUILayout.Button(" " + submenus[i].SubmenuName() + " ", style, GUILayout.ExpandWidth(false)))
|
||||
{
|
||||
GUI.enabled = true;
|
||||
submenus[activeSubmenu].LoseActive();
|
||||
activeSubmenu = i;
|
||||
submenus[activeSubmenu].GainActive();
|
||||
|
||||
|
||||
}
|
||||
GUI.enabled = true;
|
||||
|
||||
@ -186,7 +184,6 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
submenus[activeSubmenu].OnGUI(this);
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
|
||||
GUILayout.EndArea();
|
||||
}
|
||||
@ -198,15 +195,16 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
|
||||
var folder = loadedMod.ModHelper.Manifest.ModFolderPath;
|
||||
|
||||
List<NewHorizonsBody> bodiesForThisMod = Main.BodyDict.Values.SelectMany(x => x).Where(x => x.Mod == loadedMod).ToList();
|
||||
foreach (NewHorizonsBody body in bodiesForThisMod)
|
||||
var bodiesForThisMod = Main.BodyDict.Values.SelectMany(x => x).Where(x => x.Mod == loadedMod).ToList();
|
||||
foreach (var body in bodiesForThisMod)
|
||||
{
|
||||
if (body.RelativePath == null)
|
||||
{
|
||||
Logger.Log("Error loading config for " + body.Config.name + " in " + body.Config.starSystem);
|
||||
Logger.Log($"Error loading config for {body.Config.name} in {body.Config.starSystem}");
|
||||
continue;
|
||||
}
|
||||
|
||||
loadedConfigFiles[folder + body.RelativePath] = (body.Config as PlanetConfig);
|
||||
loadedConfigFiles[folder + body.RelativePath] = body.Config;
|
||||
submenus.ForEach(submenu => submenu.LoadConfigFile(this, body.Config));
|
||||
}
|
||||
}
|
||||
@ -215,12 +213,14 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
{
|
||||
submenus.ForEach(submenu => submenu.PreSave(this));
|
||||
|
||||
string backupFolderName = "configBackups\\" + DateTime.Now.ToString("yyyyMMddTHHmmss") + "\\";
|
||||
var backupFolderName = $"configBackups\\{DateTime.Now.ToString("yyyyMMddTHHmmss")}\\";
|
||||
|
||||
Logger.Log($"Potentially saving {loadedConfigFiles.Keys.Count} files");
|
||||
|
||||
foreach (var filePath in loadedConfigFiles.Keys)
|
||||
{
|
||||
Logger.Log("Possibly Saving... " + loadedConfigFiles[filePath].name + " @ " + filePath);
|
||||
Logger.Log($"Possibly Saving... {loadedConfigFiles[filePath].name} @ {filePath}");
|
||||
|
||||
if (loadedConfigFiles[filePath].starSystem != Main.Instance.CurrentStarSystem) continue;
|
||||
|
||||
var relativePath = filePath.Replace(loadedMod.ModHelper.Manifest.ModFolderPath, "");
|
||||
@ -231,14 +231,17 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
|
||||
try
|
||||
{
|
||||
Logger.Log("Saving... " + relativePath + " to " + filePath);
|
||||
Logger.Log($"Saving... {relativePath} to {filePath}");
|
||||
var path = loadedMod.ModHelper.Manifest.ModFolderPath + relativePath;
|
||||
var directoryName = Path.GetDirectoryName(path);
|
||||
Directory.CreateDirectory(directoryName);
|
||||
|
||||
File.WriteAllText(path, json);
|
||||
}
|
||||
catch (Exception e) { Logger.LogError("Failed to save file " + backupFolderName + relativePath); Logger.LogError(e.Message + "\n" + e.StackTrace); }
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError($"Failed to save file {relativePath}:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
@ -248,7 +251,10 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
|
||||
File.WriteAllText(path, json);
|
||||
}
|
||||
catch (Exception e) { Logger.LogError("Failed to save backup file " + backupFolderName + relativePath); Logger.LogError(e.Message + "\n" + e.StackTrace); }
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError($"Failed to save backup file {backupFolderName}{relativePath}:\n{e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,7 +268,6 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
pauseMenuButton.OnClick += ToggleMenu;
|
||||
|
||||
submenus.ForEach(submenu => submenu.OnInit(this));
|
||||
|
||||
|
||||
_editorMenuStyle = new GUIStyle
|
||||
{
|
||||
|
||||
@ -122,11 +122,14 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
id = id
|
||||
};
|
||||
|
||||
string regex = @"Arc \d+ - Child of (\d*)"; // $"Arc {i} - Child of {parentID}";
|
||||
var parentID = (new Regex(regex)).Matches(metadata.spiralGo.name)[0].Groups[1].Value;
|
||||
metadata.parentID = parentID == "" ? -1 : int.Parse(parentID);
|
||||
|
||||
Logger.Log("Parent id for '" + metadata.spiralGo.name + "' : " + parentID);
|
||||
if (metadata.spiralGo != null)
|
||||
{
|
||||
string regex = @"Arc \d+ - Child of (\d*)"; // $"Arc {i} - Child of {parentID}";
|
||||
var parentID = (new Regex(regex)).Matches(metadata.spiralGo.name)[0].Groups[1].Value;
|
||||
metadata.parentID = parentID == "" ? -1 : int.Parse(parentID);
|
||||
|
||||
Logger.Log("Parent id for '" + metadata.spiralGo.name + "' : " + parentID);
|
||||
}
|
||||
|
||||
conversationMetadata.spirals.Add(metadata);
|
||||
}
|
||||
@ -216,7 +219,7 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
conversationMeta.conversation.rotation = null;
|
||||
UpdateConversationTransform(conversationMeta, sectorObject);
|
||||
}
|
||||
else
|
||||
else if (conversationMeta.conversationGo != null)
|
||||
{
|
||||
conversationMeta.conversationGo.transform.localPosition = data.pos;
|
||||
DebugPropPlacer.SetGameObjectRotation(conversationMeta.conversationGo, data, _dnp.gameObject.transform.position);
|
||||
@ -478,6 +481,7 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
void UpdateConversationTransform(ConversationMetadata conversationMetadata, GameObject sectorParent)
|
||||
{
|
||||
var nomaiWallTextObj = conversationMetadata.conversationGo;
|
||||
if (nomaiWallTextObj == null) return;
|
||||
var planetGO = sectorParent;
|
||||
var info = conversationMetadata.conversation;
|
||||
|
||||
@ -507,6 +511,7 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
{
|
||||
conversations.ForEach(metadata =>
|
||||
{
|
||||
if (metadata.conversationGo == null) return;
|
||||
metadata.conversation.position = metadata.conversationGo.transform.localPosition;
|
||||
metadata.conversation.rotation = metadata.conversationGo.transform.localEulerAngles;
|
||||
});
|
||||
|
||||
@ -12,14 +12,28 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
{
|
||||
class DebugMenuPropPlacer : DebugSubmenu
|
||||
{
|
||||
private Vector2 recentPropsScrollPosition = Vector2.zero;
|
||||
private HashSet<string> favoriteProps = new HashSet<string>();
|
||||
private List<string> propsLoadedFromConfig = new List<string>();
|
||||
public static readonly char separatorCharacter = '☧'; // since no chars are illegal in game object names, I picked one that's extremely unlikely to be used to be a separator
|
||||
private static readonly string favoritePropsPlayerPrefKey = "FavoriteProps";
|
||||
|
||||
internal DebugPropPlacer _dpp;
|
||||
internal DebugRaycaster _drc;
|
||||
|
||||
// misc
|
||||
private GameObject mostRecentlyPlacedProp;
|
||||
private Vector3 mostRecentlyPlacedPropSphericalPos;
|
||||
|
||||
// menu params
|
||||
private Vector2 recentPropsScrollPosition = Vector2.zero;
|
||||
private bool propsCollapsed = false;
|
||||
private bool propPositioningCollapsed = false;
|
||||
private Vector3 propPosDelta = new Vector3(0.1f, 0.1f, 0.1f);
|
||||
private Vector3 propRotDelta = new Vector3(0.1f, 0.1f, 0.1f);
|
||||
private Vector3 propSphericalPosDelta = new Vector3(0.1f, 0.1f, 0.1f);
|
||||
private float propRotationAboutLocalUpDelta = 0.1f;
|
||||
private float propScaleDelta = 0.1f;
|
||||
|
||||
internal override string SubmenuName()
|
||||
{
|
||||
return "Prop Placer";
|
||||
@ -40,7 +54,7 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
|
||||
internal override void OnBeginLoadMod(DebugMenu debugMenu)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
internal override void GainActive()
|
||||
@ -52,10 +66,10 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
{
|
||||
DebugPropPlacer.active = false;
|
||||
}
|
||||
|
||||
|
||||
internal override void LoadConfigFile(DebugMenu menu, PlanetConfig config)
|
||||
{
|
||||
_dpp.FindAndRegisterPropsFromConfig(config);
|
||||
_dpp.FindAndRegisterPropsFromConfig(config, propsLoadedFromConfig);
|
||||
}
|
||||
|
||||
private void LoadFavoriteProps()
|
||||
@ -81,16 +95,176 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
_dpp.SetCurrentObject(GUILayout.TextArea(_dpp.currentObject));
|
||||
|
||||
GUILayout.Space(5);
|
||||
GUILayout.Space(5);
|
||||
|
||||
|
||||
var arrow = propsCollapsed ? " > " : " v ";
|
||||
if (GUILayout.Button(arrow + "Recently placed objects", menu._tabBarStyle)) propsCollapsed = !propsCollapsed;
|
||||
if (!propsCollapsed) DrawPropsList(menu);
|
||||
GUILayout.Space(5);
|
||||
|
||||
if (_dpp.mostRecentlyPlacedPropGO != null)
|
||||
{
|
||||
arrow = propPositioningCollapsed ? " > " : " v ";
|
||||
if (GUILayout.Button(arrow + "Position last placed prop", menu._tabBarStyle)) propPositioningCollapsed = !propPositioningCollapsed;
|
||||
if (!propPositioningCollapsed) DrawPropsAdustmentControls(menu);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawPropsAdustmentControls(DebugMenu menu)
|
||||
{
|
||||
var propPath = _dpp.mostRecentlyPlacedPropPath;
|
||||
var propPathElements = propPath[propPath.Length - 1] == '/'
|
||||
? propPath.Substring(0, propPath.Length - 1).Split('/')
|
||||
: propPath.Split('/');
|
||||
string propName = propPathElements[propPathElements.Length - 1];
|
||||
GUILayout.Label($"Reposition {propName}: ");
|
||||
|
||||
|
||||
Vector3 latestPropPosDelta = VectorInput(_dpp.mostRecentlyPlacedPropGO.transform.localPosition, propPosDelta, out propPosDelta, "x", "y", "z");
|
||||
_dpp.mostRecentlyPlacedPropGO.transform.localPosition += latestPropPosDelta;
|
||||
if (latestPropPosDelta != Vector3.zero) mostRecentlyPlacedPropSphericalPos = DeltaSphericalPosition(mostRecentlyPlacedProp, Vector3.zero);
|
||||
|
||||
//GUILayout.Space(5);
|
||||
//Vector3 latestPropRotDelta = VectorInput(_dpp.mostRecentlyPlacedPropGO.transform.localEulerAngles, propRotDelta, out propRotDelta, "x", "y", "z");
|
||||
//_dpp.mostRecentlyPlacedPropGO.transform.localEulerAngles += latestPropRotDelta;
|
||||
|
||||
GUILayout.Space(5);
|
||||
GUILayout.Space(5);
|
||||
|
||||
|
||||
if (mostRecentlyPlacedProp != _dpp.mostRecentlyPlacedPropGO)
|
||||
{
|
||||
mostRecentlyPlacedProp = _dpp.mostRecentlyPlacedPropGO;
|
||||
mostRecentlyPlacedPropSphericalPos = DeltaSphericalPosition(mostRecentlyPlacedProp, Vector3.zero);
|
||||
}
|
||||
|
||||
Vector3 latestPropSphericalPosDelta = VectorInput(mostRecentlyPlacedPropSphericalPos, propSphericalPosDelta, out propSphericalPosDelta, "lat ", "lon ", "height");
|
||||
if (latestPropSphericalPosDelta != Vector3.zero)
|
||||
{
|
||||
DeltaSphericalPosition(mostRecentlyPlacedProp, latestPropSphericalPosDelta);
|
||||
mostRecentlyPlacedPropSphericalPos = mostRecentlyPlacedPropSphericalPos + latestPropSphericalPosDelta;
|
||||
}
|
||||
|
||||
GUILayout.Space(5);
|
||||
GUILayout.Space(5);
|
||||
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label("Rotate about up: ", GUILayout.Width(50));
|
||||
float deltaRot = 0;
|
||||
if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) deltaRot += propRotationAboutLocalUpDelta;
|
||||
if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) deltaRot -= propRotationAboutLocalUpDelta;
|
||||
propRotationAboutLocalUpDelta = float.Parse(GUILayout.TextField(propRotationAboutLocalUpDelta + "", GUILayout.Width(100)));
|
||||
|
||||
if (deltaRot != 0)
|
||||
{
|
||||
Transform astroObject = mostRecentlyPlacedProp.transform.parent.parent;
|
||||
mostRecentlyPlacedProp.transform.RotateAround(mostRecentlyPlacedProp.transform.position, mostRecentlyPlacedProp.transform.up, deltaRot);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label("scale: ", GUILayout.Width(50));
|
||||
var scaleString = mostRecentlyPlacedProp.transform.localScale.x + "";
|
||||
var newScaleString = GUILayout.TextField(scaleString, GUILayout.Width(50));
|
||||
var parsedScaleString = mostRecentlyPlacedProp.transform.localScale.x; try { parsedScaleString = float.Parse(newScaleString); } catch { }
|
||||
float deltaScale = scaleString == newScaleString ? 0 : parsedScaleString - mostRecentlyPlacedProp.transform.localScale.x;
|
||||
if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) deltaScale += propScaleDelta;
|
||||
if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) deltaScale -= propScaleDelta;
|
||||
propScaleDelta = float.Parse(GUILayout.TextField(propScaleDelta + "", GUILayout.Width(100)));
|
||||
|
||||
if (deltaScale != 0)
|
||||
{
|
||||
float newScale = mostRecentlyPlacedProp.transform.localScale.x + deltaScale;
|
||||
mostRecentlyPlacedProp.transform.localScale = new Vector3(newScale, newScale, newScale);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
private Vector3 DeltaSphericalPosition(GameObject prop, Vector3 deltaSpherical)
|
||||
{
|
||||
Transform astroObject = prop.transform.parent.parent;
|
||||
Transform sector = prop.transform.parent;
|
||||
Vector3 originalLocalPos = astroObject.InverseTransformPoint(prop.transform.position); // parent is the sector, this gives localPos relative to the astroobject (what the DetailBuilder asks for)
|
||||
Vector3 sphericalPos = CoordinateUtilities.CartesianToSpherical(originalLocalPos);
|
||||
|
||||
if (deltaSpherical == Vector3.zero) return sphericalPos;
|
||||
Vector3 newSpherical = sphericalPos + deltaSpherical;
|
||||
|
||||
Vector3 finalLocalPosition = CoordinateUtilities.SphericalToCartesian(newSpherical);
|
||||
Vector3 finalAbsolutePosition = astroObject.TransformPoint(finalLocalPosition);
|
||||
prop.transform.localPosition = prop.transform.parent.InverseTransformPoint(finalAbsolutePosition);
|
||||
// prop.transform.rotation = Quaternion.FromToRotation(originalLocalPos.normalized, finalLocalPosition.normalized) * prop.transform.rotation;
|
||||
|
||||
// first, rotate the object by the astroObject's rotation, that means anything afterwards is relative to this rotation (ie, we can pretend the astroObject has 0 rotation)
|
||||
// then, rotate by the difference in position, basically accounting for the curvature of a sphere
|
||||
// then re-apply the local rotations of the hierarchy down to the prop (apply the sector local rotation, then the prop local rotation)
|
||||
|
||||
// since we're doing all rotation relative to the astro object, we start with its absolute rotation
|
||||
// then we apply the rotation about the astroobject using FromTooRotation
|
||||
// then we reapply the local rotations down through the hierarchy
|
||||
prop.transform.rotation = astroObject.rotation * Quaternion.FromToRotation(originalLocalPos.normalized, finalLocalPosition.normalized) * sector.localRotation * prop.transform.localRotation;
|
||||
|
||||
return newSpherical;
|
||||
}
|
||||
|
||||
private Vector3 VectorInput(Vector3 input, Vector3 deltaControls, out Vector3 deltaControlsOut, string labelX, string labelY, string labelZ)
|
||||
{
|
||||
var dx = deltaControls.x;
|
||||
var dy = deltaControls.y;
|
||||
var dz = deltaControls.z;
|
||||
|
||||
// x
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label(labelX + ": ", GUILayout.Width(50));
|
||||
var xString = input.x + "";
|
||||
var newXString = GUILayout.TextField(xString, GUILayout.Width(50));
|
||||
var parsedXString = input.x; try { parsedXString = float.Parse(newXString); } catch { }
|
||||
float deltaX = xString == newXString ? 0 : parsedXString - input.x;
|
||||
if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) deltaX += dx;
|
||||
if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) deltaX -= dx;
|
||||
dx = float.Parse(GUILayout.TextField(dx + "", GUILayout.Width(100)));
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
// y
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label(labelY + ": ", GUILayout.Width(50));
|
||||
var yString = input.y + "";
|
||||
var newYString = GUILayout.TextField(yString, GUILayout.Width(50));
|
||||
var parsedYString = input.y; try { parsedYString = float.Parse(newYString); } catch { }
|
||||
float deltaY = yString == newYString ? 0 : parsedYString - input.y;
|
||||
if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) deltaY += dy;
|
||||
if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) deltaY -= dy;
|
||||
dy = float.Parse(GUILayout.TextField(dy + "", GUILayout.Width(100)));
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
// z
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label(labelZ + ": ", GUILayout.Width(50));
|
||||
var zString = input.z + "";
|
||||
var newZString = GUILayout.TextField(zString, GUILayout.Width(50));
|
||||
var parsedZString = input.z; try { parsedZString = float.Parse(newZString); } catch { }
|
||||
float deltaZ = zString == newZString ? 0 : parsedZString - input.z;
|
||||
if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) deltaZ += dz;
|
||||
if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) deltaZ -= dz;
|
||||
dz = float.Parse(GUILayout.TextField(dz + "", GUILayout.Width(100)));
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
deltaControlsOut = new Vector3(dx, dy, dz);
|
||||
return new Vector3(deltaX, deltaY, deltaZ);
|
||||
}
|
||||
|
||||
private void DrawPropsList(DebugMenu menu)
|
||||
{
|
||||
// List of recently placed objects
|
||||
GUILayout.Label("Recently placed objects");
|
||||
recentPropsScrollPosition = GUILayout.BeginScrollView(recentPropsScrollPosition, GUILayout.Width(menu.EditorMenuSize.x), GUILayout.Height(500));
|
||||
foreach (string propPath in DebugPropPlacer.RecentlyPlacedProps)
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
|
||||
var propPathElements = propPath[propPath.Length-1] == '/'
|
||||
? propPath.Substring(0, propPath.Length-1).Split('/')
|
||||
var propPathElements = propPath[propPath.Length - 1] == '/'
|
||||
? propPath.Substring(0, propPath.Length - 1).Split('/')
|
||||
: propPath.Split('/');
|
||||
string propName = propPathElements[propPathElements.Length - 1];
|
||||
|
||||
@ -118,8 +292,6 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
GUILayout.EndScrollView();
|
||||
|
||||
GUILayout.Space(5);
|
||||
}
|
||||
|
||||
internal override void PreSave(DebugMenu menu)
|
||||
@ -131,43 +303,51 @@ namespace NewHorizons.Utility.DebugMenu
|
||||
{
|
||||
var newDetails = _dpp.GetPropsConfigByBody();
|
||||
|
||||
Logger.Log("Updating config files. New Details Counts by planet: " + string.Join(", ", newDetails.Keys.Select(x => x + $" ({newDetails[x].Length})")));
|
||||
var newDetailsCountsByPlanet = string.Join(", ", newDetails.Keys.Select(x => $"{x.name} ({newDetails[x].Length})"));
|
||||
Logger.Log($"Updating config files. New Details Counts by planet: {newDetailsCountsByPlanet}");
|
||||
|
||||
Dictionary<string, string> planetToConfigPath = new Dictionary<string, string>();
|
||||
var planetToConfigPath = new Dictionary<AstroObject, string>();
|
||||
|
||||
// Get all configs
|
||||
foreach (var filePath in menu.loadedConfigFiles.Keys)
|
||||
{
|
||||
Logger.Log("potentially updating copy of config at " + filePath);
|
||||
Logger.Log($"Potentially updating copy of config at {filePath}");
|
||||
Logger.Log($"{menu.loadedConfigFiles[filePath].name} {AstroObjectLocator.GetAstroObject(menu.loadedConfigFiles[filePath].name)?.name}");
|
||||
Logger.Log($"{menu.loadedConfigFiles[filePath].name}");
|
||||
|
||||
if (menu.loadedConfigFiles[filePath].starSystem != Main.Instance.CurrentStarSystem) return;
|
||||
if (menu.loadedConfigFiles[filePath].name == null || AstroObjectLocator.GetAstroObject(menu.loadedConfigFiles[filePath].name) == null) { Logger.Log("Failed to update copy of config at " + filePath); continue; }
|
||||
if (menu.loadedConfigFiles[filePath].name == null || AstroObjectLocator.GetAstroObject(menu.loadedConfigFiles[filePath].name) == null)
|
||||
{
|
||||
Logger.Log("Failed to update copy of config at " + filePath);
|
||||
continue;
|
||||
}
|
||||
|
||||
var astroObjectName = DebugPropPlacer.GetAstroObjectName(menu.loadedConfigFiles[filePath].name);
|
||||
planetToConfigPath[astroObjectName] = filePath;
|
||||
var astroObject = AstroObjectLocator.GetAstroObject(menu.loadedConfigFiles[filePath].name);
|
||||
planetToConfigPath[astroObject] = filePath;
|
||||
|
||||
if (!newDetails.ContainsKey(astroObjectName)) continue;
|
||||
if (!newDetails.ContainsKey(astroObject)) continue;
|
||||
|
||||
if (menu.loadedConfigFiles[filePath].Props == null) menu.loadedConfigFiles[filePath].Props = new External.Modules.PropModule();
|
||||
menu.loadedConfigFiles[filePath].Props.details = newDetails[astroObjectName];
|
||||
if (menu.loadedConfigFiles[filePath].Props == null) menu.loadedConfigFiles[filePath].Props = new PropModule();
|
||||
menu.loadedConfigFiles[filePath].Props.details = newDetails[astroObject];
|
||||
|
||||
Logger.Log("successfully updated copy of config file for " + astroObjectName);
|
||||
Logger.Log($"Successfully updated copy of config file for {astroObject.name}");
|
||||
}
|
||||
|
||||
// find all new planets that do not yet have config paths
|
||||
var planetsThatDoNotHaveConfigFiles = newDetails.Keys.Where(x => !planetToConfigPath.ContainsKey(x)).ToList();
|
||||
foreach (var astroObjectName in planetsThatDoNotHaveConfigFiles)
|
||||
foreach (var astroObject in planetsThatDoNotHaveConfigFiles)
|
||||
{
|
||||
Logger.Log("Fabricating new config file for " + astroObjectName);
|
||||
Logger.Log("Fabricating new config file for " + astroObject.name);
|
||||
|
||||
var filepath = "planets/" + Main.Instance.CurrentStarSystem + "/" + astroObjectName + ".json";
|
||||
PlanetConfig c = new PlanetConfig();
|
||||
c.starSystem = Main.Instance.CurrentStarSystem;
|
||||
c.name = astroObjectName;
|
||||
c.Props = new PropModule();
|
||||
c.Props.details = newDetails[astroObjectName];
|
||||
var filepath = $"planets/{Main.Instance.CurrentStarSystem}/{astroObject.name}.json";
|
||||
|
||||
var config = new PlanetConfig();
|
||||
config.starSystem = Main.Instance.CurrentStarSystem;
|
||||
config.name = astroObject._name == AstroObject.Name.CustomString ? astroObject.GetCustomName() : astroObject._name.ToString();
|
||||
config.Props = new PropModule();
|
||||
config.Props.details = newDetails[astroObject];
|
||||
|
||||
menu.loadedConfigFiles[filepath] = c;
|
||||
menu.loadedConfigFiles[filepath] = config;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,6 +125,7 @@ namespace NewHorizons.Utility.DebugUtilities
|
||||
}.Select(vIdx => vIdx + topVerts.Length+bottomVerts.Length).ToArray();
|
||||
|
||||
Mesh m = new Mesh();
|
||||
m.name = "DebugArrow";
|
||||
m.vertices = topVerts.Concat(bottomVerts).Concat(sideVerts).ToArray();
|
||||
m.triangles = topTris.Concat(bottomTris).Concat(sideTris).ToArray();
|
||||
m.RecalculateNormals();
|
||||
|
||||
@ -1,284 +1,283 @@
|
||||
using NewHorizons.Builder.Props;
|
||||
using NewHorizons.External.Configs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using static NewHorizons.External.Modules.PropModule;
|
||||
|
||||
namespace NewHorizons.Utility.DebugUtilities
|
||||
{
|
||||
|
||||
//
|
||||
// The prop placer. Doesn't interact with any files, just places and tracks props.
|
||||
//
|
||||
|
||||
[RequireComponent(typeof(DebugRaycaster))]
|
||||
class DebugPropPlacer : MonoBehaviour
|
||||
{
|
||||
private struct PropPlacementData
|
||||
{
|
||||
public string body;
|
||||
public string system;
|
||||
public GameObject gameObject;
|
||||
public DetailInfo detailInfo;
|
||||
}
|
||||
|
||||
// VASE
|
||||
public static readonly string DEFAULT_OBJECT = "BrittleHollow_Body/Sector_BH/Sector_NorthHemisphere/Sector_NorthPole/Sector_HangingCity/Sector_HangingCity_District1/Props_HangingCity_District1/OtherComponentsGroup/Props_HangingCity_Building_10/Prefab_NOM_VaseThin";
|
||||
|
||||
public string currentObject { get; private set; } // path of the prop to be placed
|
||||
private bool hasAddedCurrentObjectToRecentsList = false;
|
||||
private List<PropPlacementData> props = new List<PropPlacementData>();
|
||||
private List<PropPlacementData> deletedProps = new List<PropPlacementData>();
|
||||
private DebugRaycaster _rc;
|
||||
|
||||
public static HashSet<string> RecentlyPlacedProps = new HashSet<string>();
|
||||
|
||||
public static bool active = false;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_rc = this.GetRequiredComponent<DebugRaycaster>();
|
||||
currentObject = DEFAULT_OBJECT;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!Main.Debug) return;
|
||||
if (!active) return;
|
||||
|
||||
if (Keyboard.current[Key.G].wasReleasedThisFrame)
|
||||
{
|
||||
PlaceObject();
|
||||
}
|
||||
|
||||
if (Keyboard.current[Key.Minus].wasReleasedThisFrame)
|
||||
{
|
||||
DeleteLast();
|
||||
}
|
||||
|
||||
if (Keyboard.current[Key.Equals].wasReleasedThisFrame)
|
||||
{
|
||||
UndoDelete();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetCurrentObject(string s)
|
||||
{
|
||||
currentObject = s;
|
||||
hasAddedCurrentObjectToRecentsList = false;
|
||||
}
|
||||
|
||||
internal void PlaceObject()
|
||||
{
|
||||
DebugRaycastData data = _rc.Raycast();
|
||||
PlaceObject(data, this.gameObject.transform.position);
|
||||
|
||||
if (!hasAddedCurrentObjectToRecentsList)
|
||||
{
|
||||
hasAddedCurrentObjectToRecentsList = true;
|
||||
|
||||
if (!RecentlyPlacedProps.Contains(currentObject))
|
||||
{
|
||||
RecentlyPlacedProps.Add(currentObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void PlaceObject(DebugRaycastData data, Vector3 playerAbsolutePosition)
|
||||
{
|
||||
// TODO: implement sectors
|
||||
// if this hits a sector, store that sector and add a config file option for it
|
||||
|
||||
if (!data.hitBodyGameObject.name.EndsWith("_Body"))
|
||||
{
|
||||
Logger.Log("Cannot place object on non-body object: " + data.hitBodyGameObject.name);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (currentObject == "" || currentObject == null)
|
||||
{
|
||||
SetCurrentObject(DEFAULT_OBJECT);
|
||||
}
|
||||
|
||||
GameObject prop = DetailBuilder.MakeDetail(data.hitBodyGameObject, data.hitBodyGameObject.GetComponentInChildren<Sector>(), currentObject, data.pos, data.norm, 1, false);
|
||||
PropPlacementData propData = RegisterProp_WithReturn(data.bodyName, prop);
|
||||
|
||||
SetGameObjectRotation(prop, data, playerAbsolutePosition);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Logger.Log($"Failed to place object {currentObject} on body ${data.hitBodyGameObject} at location ${data.pos}.");
|
||||
}
|
||||
}
|
||||
using NewHorizons.Builder.Props;
|
||||
using NewHorizons.External.Configs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using static NewHorizons.External.Modules.PropModule;
|
||||
|
||||
namespace NewHorizons.Utility.DebugUtilities
|
||||
{
|
||||
|
||||
//
|
||||
// The prop placer. Doesn't interact with any files, just places and tracks props.
|
||||
//
|
||||
|
||||
[RequireComponent(typeof(DebugRaycaster))]
|
||||
class DebugPropPlacer : MonoBehaviour
|
||||
{
|
||||
private struct PropPlacementData
|
||||
{
|
||||
public AstroObject body;
|
||||
public string system;
|
||||
public GameObject gameObject;
|
||||
public DetailInfo detailInfo;
|
||||
}
|
||||
|
||||
// VASE
|
||||
public static readonly string DEFAULT_OBJECT = "BrittleHollow_Body/Sector_BH/Sector_NorthHemisphere/Sector_NorthPole/Sector_HangingCity/Sector_HangingCity_District1/Props_HangingCity_District1/OtherComponentsGroup/Props_HangingCity_Building_10/Prefab_NOM_VaseThin";
|
||||
|
||||
public string currentObject { get; private set; } // path of the prop to be placed
|
||||
private bool hasAddedCurrentObjectToRecentsList = false;
|
||||
private List<PropPlacementData> props = new List<PropPlacementData>();
|
||||
private List<PropPlacementData> deletedProps = new List<PropPlacementData>();
|
||||
private DebugRaycaster _rc;
|
||||
|
||||
public static HashSet<string> RecentlyPlacedProps = new HashSet<string>();
|
||||
|
||||
public static bool active = false;
|
||||
public GameObject mostRecentlyPlacedPropGO { get { return props.Count() <= 0 ? null : props[props.Count() - 1].gameObject; } }
|
||||
public string mostRecentlyPlacedPropPath { get { return props.Count() <= 0 ? "" : props[props.Count() - 1].detailInfo.path; } }
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_rc = this.GetRequiredComponent<DebugRaycaster>();
|
||||
currentObject = DEFAULT_OBJECT;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!Main.Debug) return;
|
||||
if (!active) return;
|
||||
|
||||
if (Keyboard.current[Key.G].wasReleasedThisFrame)
|
||||
{
|
||||
PlaceObject();
|
||||
}
|
||||
|
||||
if (Keyboard.current[Key.Minus].wasReleasedThisFrame)
|
||||
{
|
||||
DeleteLast();
|
||||
}
|
||||
|
||||
if (Keyboard.current[Key.Equals].wasReleasedThisFrame)
|
||||
{
|
||||
UndoDelete();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetCurrentObject(string s)
|
||||
{
|
||||
currentObject = s;
|
||||
hasAddedCurrentObjectToRecentsList = false;
|
||||
}
|
||||
|
||||
internal void PlaceObject()
|
||||
{
|
||||
DebugRaycastData data = _rc.Raycast();
|
||||
PlaceObject(data, this.gameObject.transform.position);
|
||||
|
||||
if (!hasAddedCurrentObjectToRecentsList)
|
||||
{
|
||||
hasAddedCurrentObjectToRecentsList = true;
|
||||
|
||||
if (!RecentlyPlacedProps.Contains(currentObject))
|
||||
{
|
||||
RecentlyPlacedProps.Add(currentObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void PlaceObject(DebugRaycastData data, Vector3 playerAbsolutePosition)
|
||||
{
|
||||
// TODO: implement sectors
|
||||
// if this hits a sector, store that sector and add a config file option for it
|
||||
|
||||
if (!data.hitBodyGameObject.name.EndsWith("_Body"))
|
||||
{
|
||||
Logger.Log("Cannot place object on non-body object: " + data.hitBodyGameObject.name);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (currentObject == "" || currentObject == null)
|
||||
{
|
||||
SetCurrentObject(DEFAULT_OBJECT);
|
||||
}
|
||||
|
||||
GameObject prop = DetailBuilder.MakeDetail(data.hitBodyGameObject, data.hitBodyGameObject.GetComponentInChildren<Sector>(), currentObject, data.pos, data.norm, 1, false);
|
||||
PropPlacementData propData = RegisterProp_WithReturn(data.hitBodyGameObject.GetComponent<AstroObject>(), prop);
|
||||
|
||||
SetGameObjectRotation(prop, data, playerAbsolutePosition);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Logger.Log($"Failed to place object {currentObject} on body ${data.hitBodyGameObject} at location ${data.pos}.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetGameObjectRotation(GameObject prop, DebugRaycastData data, Vector3 playerAbsolutePosition)
|
||||
{
|
||||
// align with surface normal
|
||||
Vector3 alignToSurface = (Quaternion.LookRotation(data.norm) * Quaternion.FromToRotation(Vector3.up, Vector3.forward)).eulerAngles;
|
||||
prop.transform.localEulerAngles = alignToSurface;
|
||||
|
||||
// rotate facing dir towards player
|
||||
GameObject g = new GameObject("DebugProp");
|
||||
g.transform.parent = prop.transform.parent;
|
||||
g.transform.localPosition = prop.transform.localPosition;
|
||||
g.transform.localRotation = prop.transform.localRotation;
|
||||
|
||||
prop.transform.parent = g.transform;
|
||||
|
||||
var dirTowardsPlayer = prop.transform.parent.transform.InverseTransformPoint(playerAbsolutePosition) - prop.transform.localPosition;
|
||||
dirTowardsPlayer.y = 0;
|
||||
float rotation = Quaternion.LookRotation(dirTowardsPlayer).eulerAngles.y;
|
||||
prop.transform.localEulerAngles = new Vector3(0, rotation, 0);
|
||||
|
||||
prop.transform.parent = g.transform.parent;
|
||||
{
|
||||
// align with surface normal
|
||||
Vector3 alignToSurface = (Quaternion.LookRotation(data.norm) * Quaternion.FromToRotation(Vector3.up, Vector3.forward)).eulerAngles;
|
||||
prop.transform.localEulerAngles = alignToSurface;
|
||||
|
||||
// rotate facing dir towards player
|
||||
GameObject g = new GameObject("DebugProp");
|
||||
g.transform.parent = prop.transform.parent;
|
||||
g.transform.localPosition = prop.transform.localPosition;
|
||||
g.transform.localRotation = prop.transform.localRotation;
|
||||
|
||||
prop.transform.parent = g.transform;
|
||||
|
||||
var dirTowardsPlayer = prop.transform.parent.transform.InverseTransformPoint(playerAbsolutePosition) - prop.transform.localPosition;
|
||||
dirTowardsPlayer.y = 0;
|
||||
float rotation = Quaternion.LookRotation(dirTowardsPlayer).eulerAngles.y;
|
||||
prop.transform.localEulerAngles = new Vector3(0, rotation, 0);
|
||||
|
||||
prop.transform.parent = g.transform.parent;
|
||||
GameObject.Destroy(g);
|
||||
}
|
||||
|
||||
public static string GetAstroObjectName(string bodyName)
|
||||
{
|
||||
if (bodyName.EndsWith("_Body")) bodyName = bodyName.Substring(0, bodyName.Length-"_Body".Length);
|
||||
|
||||
var astroObject = AstroObjectLocator.GetAstroObject(bodyName);
|
||||
if (astroObject == null) return null;
|
||||
|
||||
var astroObjectName = astroObject.name;
|
||||
if (astroObjectName.EndsWith("_Body")) astroObjectName = astroObjectName.Substring(0, astroObjectName.Length-"_Body".Length);
|
||||
|
||||
return astroObjectName;
|
||||
}
|
||||
|
||||
public void FindAndRegisterPropsFromConfig(PlanetConfig config)
|
||||
{
|
||||
if (config.starSystem != Main.Instance.CurrentStarSystem) return;
|
||||
|
||||
AstroObject planet = AstroObjectLocator.GetAstroObject(config.name);
|
||||
|
||||
if (planet == null) return;
|
||||
if (config.Props == null || config.Props.details == null) return;
|
||||
|
||||
var astroObjectName = GetAstroObjectName(config.name);
|
||||
|
||||
foreach (var detail in config.Props.details)
|
||||
{
|
||||
GameObject spawnedProp = DetailBuilder.GetSpawnedGameObjectByDetailInfo(detail);
|
||||
|
||||
if (spawnedProp == null)
|
||||
{
|
||||
Logger.LogError("No spawned prop found for " + detail.path);
|
||||
continue;
|
||||
}
|
||||
|
||||
PropPlacementData data = RegisterProp_WithReturn(astroObjectName, spawnedProp, detail.path, detail);
|
||||
|
||||
// note: we do not support placing props from assetbundles, so they will not be added to the
|
||||
// selectable list of placed props
|
||||
if (detail.assetBundle == null && !RecentlyPlacedProps.Contains(data.detailInfo.path))
|
||||
{
|
||||
RecentlyPlacedProps.Add(data.detailInfo.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RegisterProp(string bodyGameObjectName, GameObject prop)
|
||||
{
|
||||
RegisterProp_WithReturn(bodyGameObjectName, prop);
|
||||
}
|
||||
|
||||
private PropPlacementData RegisterProp_WithReturn(string bodyGameObjectName, GameObject prop, string propPath = null, DetailInfo detailInfo = null)
|
||||
{
|
||||
if (Main.Debug)
|
||||
{
|
||||
// TOOD: make this prop an item
|
||||
}
|
||||
|
||||
|
||||
string bodyName = GetAstroObjectName(bodyGameObjectName);
|
||||
|
||||
Logger.Log("Adding prop to " + Main.Instance.CurrentStarSystem + "::" + bodyName);
|
||||
|
||||
|
||||
detailInfo = detailInfo == null ? new DetailInfo() : detailInfo;
|
||||
detailInfo.path = propPath == null ? currentObject : propPath;
|
||||
|
||||
PropPlacementData data = new PropPlacementData
|
||||
{
|
||||
body = bodyName,
|
||||
gameObject = prop,
|
||||
system = Main.Instance.CurrentStarSystem,
|
||||
detailInfo = detailInfo
|
||||
};
|
||||
|
||||
props.Add(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
public Dictionary<string, DetailInfo[]> GetPropsConfigByBody()
|
||||
{
|
||||
var groupedProps = props
|
||||
.GroupBy(p => p.system + "." + p.body)
|
||||
.Select(grp => grp.ToList())
|
||||
.ToList();
|
||||
|
||||
Dictionary<string, DetailInfo[]> propConfigs = new Dictionary<string, DetailInfo[]>();
|
||||
|
||||
foreach (List<PropPlacementData> bodyProps in groupedProps)
|
||||
{
|
||||
if (bodyProps == null || bodyProps.Count == 0) continue;
|
||||
Logger.Log("getting prop group for body " + bodyProps[0].body);
|
||||
if (AstroObjectLocator.GetAstroObject(bodyProps[0].body) == null) continue;
|
||||
string bodyName = GetAstroObjectName(bodyProps[0].body);
|
||||
|
||||
DetailInfo[] infoArray = new DetailInfo[bodyProps.Count];
|
||||
propConfigs[bodyName] = infoArray;
|
||||
|
||||
for(int i = 0; i < bodyProps.Count; i++)
|
||||
{
|
||||
var prop = bodyProps[i];
|
||||
var rootTransform = prop.gameObject.transform.root;
|
||||
|
||||
// Objects are parented to the sector and not to the planet
|
||||
// However, raycasted positions are reported relative to the root game object
|
||||
// Normally these two are the same, but there are some notable exceptions (ex, floating islands)
|
||||
// So we can't use local position/rotation here, we have to inverse transform the global position/rotation relative to root object
|
||||
prop.detailInfo.position = rootTransform.InverseTransformPoint(prop.gameObject.transform.position);
|
||||
prop.detailInfo.scale = prop.gameObject.transform.localScale.x;
|
||||
if (!prop.detailInfo.alignToNormal) prop.detailInfo.rotation = rootTransform.InverseTransformRotation(prop.gameObject.transform.rotation).eulerAngles;
|
||||
|
||||
infoArray[i] = prop.detailInfo;
|
||||
}
|
||||
}
|
||||
|
||||
return propConfigs;
|
||||
}
|
||||
|
||||
public void DeleteLast()
|
||||
{
|
||||
if (props.Count <= 0) return;
|
||||
|
||||
PropPlacementData last = props[props.Count-1];
|
||||
props.RemoveAt(props.Count-1);
|
||||
|
||||
last.gameObject.SetActive(false);
|
||||
|
||||
deletedProps.Add(last);
|
||||
}
|
||||
|
||||
public void UndoDelete()
|
||||
{
|
||||
if (deletedProps.Count <= 0) return;
|
||||
|
||||
PropPlacementData last = deletedProps[deletedProps.Count-1];
|
||||
deletedProps.RemoveAt(deletedProps.Count-1);
|
||||
|
||||
last.gameObject.SetActive(true);
|
||||
|
||||
props.Add(last);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetAstroObjectName(string bodyName)
|
||||
{
|
||||
var astroObject = AstroObjectLocator.GetAstroObject(bodyName);
|
||||
if (astroObject == null) return null;
|
||||
|
||||
var astroObjectName = astroObject.name;
|
||||
|
||||
return astroObjectName;
|
||||
}
|
||||
|
||||
public void FindAndRegisterPropsFromConfig(PlanetConfig config, List<string> pathsList = null)
|
||||
{
|
||||
if (config.starSystem != Main.Instance.CurrentStarSystem) return;
|
||||
|
||||
AstroObject planet = AstroObjectLocator.GetAstroObject(config.name);
|
||||
|
||||
if (planet == null) return;
|
||||
if (config.Props == null || config.Props.details == null) return;
|
||||
|
||||
var astroObject = AstroObjectLocator.GetAstroObject(config.name);
|
||||
|
||||
foreach (var detail in config.Props.details)
|
||||
{
|
||||
GameObject spawnedProp = DetailBuilder.GetSpawnedGameObjectByDetailInfo(detail);
|
||||
|
||||
if (spawnedProp == null)
|
||||
{
|
||||
Logger.LogError("No spawned prop found for " + detail.path);
|
||||
continue;
|
||||
}
|
||||
|
||||
PropPlacementData data = RegisterProp_WithReturn(astroObject, spawnedProp, detail.path, detail);
|
||||
|
||||
// note: we do not support placing props from assetbundles, so they will not be added to the
|
||||
// selectable list of placed props
|
||||
if (detail.assetBundle == null && !RecentlyPlacedProps.Contains(data.detailInfo.path))
|
||||
{
|
||||
if (pathsList != null) pathsList.Add(data.detailInfo.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RegisterProp(AstroObject body, GameObject prop)
|
||||
{
|
||||
RegisterProp_WithReturn(body, prop);
|
||||
}
|
||||
|
||||
private PropPlacementData RegisterProp_WithReturn(AstroObject body, GameObject prop, string propPath = null, DetailInfo detailInfo = null)
|
||||
{
|
||||
if (Main.Debug)
|
||||
{
|
||||
// TOOD: make this prop an item
|
||||
}
|
||||
|
||||
//var body = AstroObjectLocator.GetAstroObject(bodyGameObjectName);
|
||||
|
||||
Logger.Log($"Adding prop to {Main.Instance.CurrentStarSystem}::{body.name}");
|
||||
|
||||
|
||||
detailInfo = detailInfo == null ? new DetailInfo() : detailInfo;
|
||||
detailInfo.path = propPath == null ? currentObject : propPath;
|
||||
|
||||
PropPlacementData data = new PropPlacementData
|
||||
{
|
||||
body = body,
|
||||
gameObject = prop,
|
||||
system = Main.Instance.CurrentStarSystem,
|
||||
detailInfo = detailInfo
|
||||
};
|
||||
|
||||
props.Add(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
public Dictionary<AstroObject, DetailInfo[]> GetPropsConfigByBody()
|
||||
{
|
||||
var groupedProps = props
|
||||
.GroupBy(p => p.system + "." + p.body)
|
||||
.Select(grp => grp.ToList())
|
||||
.ToList();
|
||||
|
||||
Dictionary<AstroObject, DetailInfo[]> propConfigs = new Dictionary<AstroObject, DetailInfo[]>();
|
||||
|
||||
foreach (List<PropPlacementData> bodyProps in groupedProps)
|
||||
{
|
||||
if (bodyProps == null || bodyProps.Count == 0) continue;
|
||||
if (bodyProps[0].body == null) continue;
|
||||
var body = bodyProps[0].body;
|
||||
Logger.Log("getting prop group for body " + body.name);
|
||||
//string bodyName = GetAstroObjectName(bodyProps[0].body);
|
||||
|
||||
DetailInfo[] infoArray = new DetailInfo[bodyProps.Count];
|
||||
propConfigs[body] = infoArray;
|
||||
|
||||
for (int i = 0; i < bodyProps.Count; i++)
|
||||
{
|
||||
var prop = bodyProps[i];
|
||||
var rootTransform = prop.gameObject.transform.root;
|
||||
|
||||
// Objects are parented to the sector and not to the planet
|
||||
// However, raycasted positions are reported relative to the root game object
|
||||
// Normally these two are the same, but there are some notable exceptions (ex, floating islands)
|
||||
// So we can't use local position/rotation here, we have to inverse transform the global position/rotation relative to root object
|
||||
prop.detailInfo.position = rootTransform.InverseTransformPoint(prop.gameObject.transform.position);
|
||||
prop.detailInfo.scale = prop.gameObject.transform.localScale.x;
|
||||
if (!prop.detailInfo.alignToNormal) prop.detailInfo.rotation = rootTransform.InverseTransformRotation(prop.gameObject.transform.rotation).eulerAngles;
|
||||
|
||||
infoArray[i] = prop.detailInfo;
|
||||
}
|
||||
}
|
||||
|
||||
return propConfigs;
|
||||
}
|
||||
|
||||
public void DeleteLast()
|
||||
{
|
||||
if (props.Count <= 0) return;
|
||||
|
||||
PropPlacementData last = props[props.Count - 1];
|
||||
props.RemoveAt(props.Count - 1);
|
||||
|
||||
last.gameObject.SetActive(false);
|
||||
|
||||
deletedProps.Add(last);
|
||||
}
|
||||
|
||||
public void UndoDelete()
|
||||
{
|
||||
if (deletedProps.Count <= 0) return;
|
||||
|
||||
PropPlacementData last = deletedProps[deletedProps.Count - 1];
|
||||
deletedProps.RemoveAt(deletedProps.Count - 1);
|
||||
|
||||
last.gameObject.SetActive(true);
|
||||
|
||||
props.Add(last);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,12 @@ namespace NewHorizons.Utility
|
||||
private static Dictionary<string, Texture2D> _loadedTextures = new Dictionary<string, Texture2D>();
|
||||
private static List<Texture2D> _generatedTextures = new List<Texture2D>();
|
||||
|
||||
public static bool IsTextureLoaded(IModBehaviour mod, string filename)
|
||||
{
|
||||
var path = mod.ModHelper.Manifest.ModFolderPath + filename;
|
||||
return _loadedTextures.ContainsKey(path);
|
||||
}
|
||||
|
||||
public static Texture2D GetTexture(IModBehaviour mod, string filename)
|
||||
{
|
||||
return GetTexture(mod, filename, true);
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
{
|
||||
"filename": "NewHorizons.dll",
|
||||
"author": "xen and Bwc9876",
|
||||
"author": "xen, Bwc9876, clay, MegaPiggy, John, Book",
|
||||
"name": "New Horizons",
|
||||
"uniqueName": "xen.NewHorizons",
|
||||
"version": "1.3.1",
|
||||
"version": "1.3.2",
|
||||
"owmlVersion": "2.5.2",
|
||||
"conflicts": [ "Raicuparta.QuantumSpaceBuddies", "Vesper.AutoResume", "PacificEngine.OW_Randomizer" ],
|
||||
"pathsToPreserve": [ "planets", "systems", "translations" ]
|
||||
|
||||
@ -77,6 +77,14 @@ public static class SchemaExporter
|
||||
{"title", _title},
|
||||
{"description", _description}
|
||||
});
|
||||
|
||||
if (_title == "Star System Schema")
|
||||
{
|
||||
schema.Definitions["NomaiCoordinates"].Properties["x"].UniqueItems = true;
|
||||
schema.Definitions["NomaiCoordinates"].Properties["y"].UniqueItems = true;
|
||||
schema.Definitions["NomaiCoordinates"].Properties["z"].UniqueItems = true;
|
||||
}
|
||||
|
||||
return schema;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user