mirror of
https://github.com/Outer-Wilds-New-Horizons/new-horizons.git
synced 2025-12-11 20:15:44 +01:00
remove prop placer
This commit is contained in:
parent
b9e0eb3b43
commit
eb56815aac
@ -51,6 +51,7 @@ namespace NewHorizons.Builder.Props
|
||||
_detailInfoToCorrespondingSpawnedGameObject.Clear();
|
||||
}
|
||||
|
||||
// i dont like how this is just a random collection in this class but quantum guy uses it :(
|
||||
public static GameObject GetSpawnedGameObjectByDetailInfo(DetailInfo detail)
|
||||
{
|
||||
if (!_detailInfoToCorrespondingSpawnedGameObject.ContainsKey(detail))
|
||||
|
||||
@ -622,7 +622,6 @@ namespace NewHorizons
|
||||
}
|
||||
|
||||
Locator.GetPlayerBody().gameObject.AddComponent<DebugRaycaster>();
|
||||
Locator.GetPlayerBody().gameObject.AddComponent<DebugPropPlacer>();
|
||||
Locator.GetPlayerBody().gameObject.AddComponent<DebugMenu>();
|
||||
Locator.GetPlayerBody().gameObject.AddComponent<PlayerShipAtmosphereDetectorFix>();
|
||||
if (HasDLC) Locator.GetPlayerBody().gameObject.AddComponent<LanternExtinguisher>();
|
||||
|
||||
@ -1,312 +0,0 @@
|
||||
using NewHorizons.Builder.Props;
|
||||
using NewHorizons.External.Configs;
|
||||
using NewHorizons.External.Modules.Props;
|
||||
using NewHorizons.Handlers;
|
||||
using NewHorizons.Utility.Files;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using NewHorizons.Utility.OuterWilds;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace NewHorizons.Utility.DebugTools
|
||||
{
|
||||
|
||||
//
|
||||
// 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 ScreenPrompt _placePrompt;
|
||||
private ScreenPrompt _undoPrompt;
|
||||
private ScreenPrompt _redoPrompt;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_rc = this.GetRequiredComponent<DebugRaycaster>();
|
||||
currentObject = DEFAULT_OBJECT;
|
||||
|
||||
_placePrompt = new ScreenPrompt(TranslationHandler.GetTranslation("DEBUG_PLACE", TranslationHandler.TextType.UI) + " <CMD>", ImageUtilities.GetButtonSprite(KeyCode.G));
|
||||
_undoPrompt = new ScreenPrompt(TranslationHandler.GetTranslation("DEBUG_UNDO", TranslationHandler.TextType.UI) + " <CMD>", ImageUtilities.GetButtonSprite(KeyCode.Minus));
|
||||
_redoPrompt = new ScreenPrompt(TranslationHandler.GetTranslation("DEBUG_REDO", TranslationHandler.TextType.UI) + " <CMD>", ImageUtilities.GetButtonSprite(KeyCode.Equals));
|
||||
|
||||
Locator.GetPromptManager().AddScreenPrompt(_placePrompt, PromptPosition.UpperRight, false);
|
||||
Locator.GetPromptManager().AddScreenPrompt(_undoPrompt, PromptPosition.UpperRight, false);
|
||||
Locator.GetPromptManager().AddScreenPrompt(_redoPrompt, PromptPosition.UpperRight, false);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
var promptManager = Locator.GetPromptManager();
|
||||
if (promptManager == null) return;
|
||||
promptManager.RemoveScreenPrompt(_placePrompt, PromptPosition.UpperRight);
|
||||
promptManager.RemoveScreenPrompt(_undoPrompt, PromptPosition.UpperRight);
|
||||
promptManager.RemoveScreenPrompt(_redoPrompt, PromptPosition.UpperRight);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
UpdatePromptVisibility();
|
||||
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 UpdatePromptVisibility()
|
||||
{
|
||||
var visible = !OWTime.IsPaused() && Main.Debug && active;
|
||||
_placePrompt.SetVisibility(visible);
|
||||
_undoPrompt.SetVisibility(visible && props.Count > 0);
|
||||
_redoPrompt.SetVisibility(visible && deletedProps.Count > 0);
|
||||
}
|
||||
|
||||
public void SetCurrentObject(string s)
|
||||
{
|
||||
currentObject = s;
|
||||
hasAddedCurrentObjectToRecentsList = false;
|
||||
}
|
||||
|
||||
internal void PlaceObject()
|
||||
{
|
||||
DebugRaycastData data = _rc.Raycast();
|
||||
PlaceObject(data);
|
||||
|
||||
//TODO: use DropItem logic to make props not clip through the ground when placed
|
||||
//public virtual void DropItem(Vector3 position, Vector3 normal, Transform parent, Sector sector, IItemDropTarget customDropTarget)
|
||||
|
||||
if (!hasAddedCurrentObjectToRecentsList)
|
||||
{
|
||||
hasAddedCurrentObjectToRecentsList = true;
|
||||
|
||||
if (!RecentlyPlacedProps.Contains(currentObject))
|
||||
{
|
||||
RecentlyPlacedProps.Add(currentObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void PlaceObject(DebugRaycastData data)
|
||||
{
|
||||
// TODO: implement sectors
|
||||
// if this hits a sector, store that sector and add a config file option for it
|
||||
|
||||
if (data.hitBodyGameObject == null)
|
||||
{
|
||||
NHLogger.LogError($"Failed to place object {currentObject} on nothing.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (currentObject == "" || currentObject == null)
|
||||
{
|
||||
SetCurrentObject(DEFAULT_OBJECT);
|
||||
}
|
||||
|
||||
var planetGO = data.hitBodyGameObject;
|
||||
|
||||
if (!planetGO.name.EndsWith("_Body"))
|
||||
{
|
||||
NHLogger.LogWarning("Cannot place object on non-body object: " + data.hitBodyGameObject.name);
|
||||
}
|
||||
|
||||
var sector = planetGO.GetComponentInChildren<Sector>();
|
||||
var prefab = SearchUtilities.Find(currentObject);
|
||||
var detailInfo = new DetailInfo()
|
||||
{
|
||||
position = data.pos,
|
||||
rotation = data.rot.eulerAngles,
|
||||
keepLoaded = true
|
||||
};
|
||||
var prop = DetailBuilder.Make(planetGO, sector, null, prefab, detailInfo);
|
||||
|
||||
var body = data.hitBodyGameObject.GetComponent<AstroObject>();
|
||||
if (body != null) RegisterProp(body, prop);
|
||||
}
|
||||
catch
|
||||
{
|
||||
NHLogger.LogError($"Failed to place object {currentObject} on body ${data.hitBodyGameObject} at location ${data.pos}.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
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;
|
||||
|
||||
var 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)
|
||||
{
|
||||
var spawnedProp = DetailBuilder.GetSpawnedGameObjectByDetailInfo(detail);
|
||||
|
||||
if (spawnedProp == null)
|
||||
{
|
||||
NHLogger.LogError("No spawned prop found for " + detail.path);
|
||||
continue;
|
||||
}
|
||||
|
||||
var 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);
|
||||
|
||||
NHLogger.LogVerbose($"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();
|
||||
|
||||
foreach (List<PropPlacementData> bodyProps in groupedProps)
|
||||
{
|
||||
if (bodyProps == null || bodyProps.Count == 0) continue;
|
||||
if (bodyProps[0].body == null) continue;
|
||||
var body = bodyProps[0].body;
|
||||
NHLogger.LogVerbose("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.alignRadial.GetValueOrDefault()) 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -48,7 +48,6 @@ namespace NewHorizons.Utility.DebugTools.Menu
|
||||
{
|
||||
submenus = new List<DebugSubmenu>()
|
||||
{
|
||||
new DebugMenuPropPlacer(),
|
||||
new DebugMenuShipLogs(),
|
||||
};
|
||||
|
||||
|
||||
@ -1,401 +0,0 @@
|
||||
using HarmonyLib;
|
||||
using NewHorizons.External.Configs;
|
||||
using NewHorizons.External.Modules;
|
||||
using NewHorizons.Utility.Geometry;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using NewHorizons.Utility.OuterWilds;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Utility.DebugTools.Menu
|
||||
{
|
||||
class DebugMenuPropPlacer : DebugSubmenu
|
||||
{
|
||||
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";
|
||||
}
|
||||
|
||||
internal override void OnInit(DebugMenu menu)
|
||||
{
|
||||
_dpp = menu.GetComponent<DebugPropPlacer>();
|
||||
_drc = menu.GetComponent<DebugRaycaster>();
|
||||
}
|
||||
|
||||
internal override void OnAwake(DebugMenu menu)
|
||||
{
|
||||
_dpp = menu.GetComponent<DebugPropPlacer>();
|
||||
_drc = menu.GetComponent<DebugRaycaster>();
|
||||
LoadFavoriteProps();
|
||||
}
|
||||
|
||||
internal override void OnBeginLoadMod(DebugMenu debugMenu)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
internal override void GainActive()
|
||||
{
|
||||
DebugPropPlacer.active = true;
|
||||
}
|
||||
|
||||
internal override void LoseActive()
|
||||
{
|
||||
DebugPropPlacer.active = false;
|
||||
}
|
||||
|
||||
internal override void LoadConfigFile(DebugMenu menu, PlanetConfig config)
|
||||
{
|
||||
_dpp.FindAndRegisterPropsFromConfig(config, propsLoadedFromConfig);
|
||||
}
|
||||
|
||||
private void LoadFavoriteProps()
|
||||
{
|
||||
string favoritePropsPlayerPref = PlayerPrefs.GetString(favoritePropsPlayerPrefKey);
|
||||
|
||||
if (favoritePropsPlayerPref == null || favoritePropsPlayerPref == "") return;
|
||||
|
||||
var favoritePropPaths = favoritePropsPlayerPref.Split(separatorCharacter);
|
||||
foreach (string favoriteProp in favoritePropPaths)
|
||||
{
|
||||
DebugPropPlacer.RecentlyPlacedProps.Add(favoriteProp);
|
||||
this.favoriteProps.Add(favoriteProp);
|
||||
}
|
||||
}
|
||||
|
||||
internal override void OnGUI(DebugMenu menu)
|
||||
{
|
||||
//
|
||||
// DebugPropPlacer
|
||||
//
|
||||
GUILayout.Label("Currently placing: ");
|
||||
_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)
|
||||
{
|
||||
SetSphericalPosition(mostRecentlyPlacedProp, mostRecentlyPlacedPropSphericalPos + 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;
|
||||
}
|
||||
|
||||
// DB_EscapePodDimension_Body/Sector_EscapePodDimension/Interactables_EscapePodDimension/InnerWarp_ToAnglerNest
|
||||
// DB_ExitOnlyDimension_Body/Sector_ExitOnlyDimension/Interactables_ExitOnlyDimension/InnerWarp_ToExitOnly // need to change the colors
|
||||
// DB_HubDimension_Body/Sector_HubDimension/Interactables_HubDimension/InnerWarp_ToCluster // need to delete the child "Signal_Harmonica"
|
||||
|
||||
private Vector3 SetSphericalPosition(GameObject prop, Vector3 newSpherical)
|
||||
{
|
||||
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 (newSpherical == sphericalPos) return sphericalPos;
|
||||
|
||||
Vector3 finalLocalPosition = CoordinateUtilities.SphericalToCartesian(newSpherical);
|
||||
Vector3 finalAbsolutePosition = astroObject.TransformPoint(finalLocalPosition);
|
||||
prop.transform.localPosition = prop.transform.parent.InverseTransformPoint(finalAbsolutePosition);
|
||||
NHLogger.Log("new position: " + prop.transform.localPosition);
|
||||
|
||||
var onlyChangingRAndRIsNegative = false;
|
||||
|
||||
// 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
|
||||
Vector3 originalLocalPos_ForcedPositiveR = CoordinateUtilities.SphericalToCartesian(new Vector3(sphericalPos.x, sphericalPos.y, Mathf.Abs(sphericalPos.z)));
|
||||
Vector3 finalLocalPos_ForcedPositiveR = CoordinateUtilities.SphericalToCartesian(new Vector3(newSpherical.x, newSpherical.y, Mathf.Abs(newSpherical.z)));
|
||||
if (!onlyChangingRAndRIsNegative) prop.transform.rotation = astroObject.rotation * Quaternion.FromToRotation(originalLocalPos_ForcedPositiveR.normalized, finalLocalPos_ForcedPositiveR.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
|
||||
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('/')
|
||||
: propPath.Split('/');
|
||||
string propName = propPathElements[propPathElements.Length - 1];
|
||||
|
||||
string favoriteButtonIcon = favoriteProps.Contains(propPath) ? "★" : "☆";
|
||||
if (GUILayout.Button(favoriteButtonIcon, GUILayout.ExpandWidth(false)))
|
||||
{
|
||||
if (favoriteProps.Contains(propPath))
|
||||
{
|
||||
favoriteProps.Remove(propPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
favoriteProps.Add(propPath);
|
||||
}
|
||||
|
||||
string[] favoritePropsArray = favoriteProps.ToArray<string>();
|
||||
PlayerPrefs.SetString(favoritePropsPlayerPrefKey, string.Join(separatorCharacter + "", favoritePropsArray));
|
||||
}
|
||||
|
||||
if (GUILayout.Button(propName))
|
||||
{
|
||||
_dpp.SetCurrentObject(propPath);
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
GUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
internal override void PreSave(DebugMenu menu)
|
||||
{
|
||||
UpdateLoadedConfigsForRecentSystem(menu);
|
||||
}
|
||||
|
||||
private void UpdateLoadedConfigsForRecentSystem(DebugMenu menu)
|
||||
{
|
||||
var newDetails = _dpp.GetPropsConfigByBody();
|
||||
|
||||
var newDetailsCountsByPlanet = string.Join(", ", newDetails.Keys.Select(x => $"{x.name} ({newDetails[x].Length})"));
|
||||
NHLogger.Log($"Updating config files. New Details Counts by planet: {newDetailsCountsByPlanet}");
|
||||
|
||||
var planetToConfigPath = new Dictionary<AstroObject, string>();
|
||||
|
||||
// Get all configs
|
||||
foreach (var filePath in menu.loadedConfigFiles.Keys)
|
||||
{
|
||||
NHLogger.LogVerbose($"Potentially updating copy of config at {filePath}");
|
||||
NHLogger.LogVerbose($"{menu.loadedConfigFiles[filePath].name} {AstroObjectLocator.GetAstroObject(menu.loadedConfigFiles[filePath].name)?.name}");
|
||||
NHLogger.LogVerbose($"{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)
|
||||
{
|
||||
NHLogger.LogWarning("Failed to update copy of config at " + filePath);
|
||||
continue;
|
||||
}
|
||||
|
||||
var astroObject = AstroObjectLocator.GetAstroObject(menu.loadedConfigFiles[filePath].name);
|
||||
planetToConfigPath[astroObject] = filePath;
|
||||
|
||||
if (!newDetails.ContainsKey(astroObject)) continue;
|
||||
|
||||
if (menu.loadedConfigFiles[filePath].Props == null) menu.loadedConfigFiles[filePath].Props = new PropModule();
|
||||
menu.loadedConfigFiles[filePath].Props.details = newDetails[astroObject];
|
||||
|
||||
NHLogger.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 astroObject in planetsThatDoNotHaveConfigFiles)
|
||||
{
|
||||
NHLogger.Log("Fabricating new config file for " + astroObject.name);
|
||||
|
||||
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] = config;
|
||||
}
|
||||
}
|
||||
|
||||
internal override void PrintNewConfigSection(DebugMenu menu)
|
||||
{
|
||||
foreach (var body in _dpp.GetPropsConfigByBody())
|
||||
{
|
||||
var json = body.Value.Join(
|
||||
detail => "\t" + JsonConvert.SerializeObject(detail, DebugMenu.jsonSettings),
|
||||
",\n"
|
||||
);
|
||||
NHLogger.Log($"{body.Key.name} ({body.Value.Length})\n[\n{json}\n]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user