mirror of
https://github.com/Outer-Wilds-New-Horizons/new-horizons.git
synced 2025-12-11 20:15:44 +01:00
Rearrange prop building + start tornado support
This commit is contained in:
parent
59647c7f4c
commit
572e5d2bca
135
NewHorizons/Builder/Props/DetailBuilder.cs
Normal file
135
NewHorizons/Builder/Props/DetailBuilder.cs
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
using NewHorizons.Utility;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
using Random = UnityEngine.Random;
|
||||||
|
using Logger = NewHorizons.Utility.Logger;
|
||||||
|
using NewHorizons.External;
|
||||||
|
using OWML.Common;
|
||||||
|
|
||||||
|
namespace NewHorizons.Builder.Props
|
||||||
|
{
|
||||||
|
public static class DetailBuilder
|
||||||
|
{
|
||||||
|
public static void Make(GameObject go, Sector sector, IPlanetConfig config, IModAssets assets, string uniqueModName)
|
||||||
|
{
|
||||||
|
foreach (var detail in config.Props.Details)
|
||||||
|
{
|
||||||
|
if (detail.assetBundle != null)
|
||||||
|
{
|
||||||
|
var prefab = PropBuildManager.LoadPrefab(detail.assetBundle, detail.path, uniqueModName, assets);
|
||||||
|
MakeDetail(go, sector, prefab, detail.position, detail.rotation, detail.scale, detail.alignToNormal, detail.generateColliders);
|
||||||
|
}
|
||||||
|
else if (detail.objFilePath != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var prefab = assets.Get3DObject(detail.objFilePath, detail.mtlFilePath);
|
||||||
|
prefab.SetActive(false);
|
||||||
|
MakeDetail(go, sector, prefab, detail.position, detail.rotation, detail.scale, detail.alignToNormal, detail.generateColliders);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError($"Could not load 3d object {detail.objFilePath} with texture {detail.mtlFilePath} : {e.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else MakeDetail(go, sector, detail.path, detail.position, detail.rotation, detail.scale, detail.alignToNormal, detail.generateColliders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GameObject MakeDetail(GameObject go, Sector sector, string propToClone, MVector3 position, MVector3 rotation, float scale, bool alignWithNormal, bool generateColliders)
|
||||||
|
{
|
||||||
|
var prefab = GameObject.Find(propToClone);
|
||||||
|
|
||||||
|
//TODO: this is super costly
|
||||||
|
if (prefab == null) prefab = SearchUtilities.FindObjectOfTypeAndName<GameObject>(propToClone.Split(new char[] { '\\', '/' }).Last());
|
||||||
|
if (prefab == null) Logger.LogError($"Couldn't find detail {propToClone}");
|
||||||
|
return MakeDetail(go, sector, prefab, position, rotation, scale, alignWithNormal, generateColliders);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GameObject MakeDetail(GameObject go, Sector sector, GameObject prefab, MVector3 position, MVector3 rotation, float scale, bool alignWithNormal, bool generateColliders)
|
||||||
|
{
|
||||||
|
if (prefab == null) return null;
|
||||||
|
|
||||||
|
GameObject prop = GameObject.Instantiate(prefab, sector.transform);
|
||||||
|
prop.SetActive(false);
|
||||||
|
|
||||||
|
List<string> assetBundles = new List<string>();
|
||||||
|
foreach (var streamingHandle in prop.GetComponentsInChildren<StreamingMeshHandle>())
|
||||||
|
{
|
||||||
|
var assetBundle = streamingHandle.assetBundle;
|
||||||
|
if (!assetBundles.Contains(assetBundle))
|
||||||
|
{
|
||||||
|
assetBundles.Add(assetBundle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var assetBundle in assetBundles)
|
||||||
|
{
|
||||||
|
sector.OnOccupantEnterSector += ((SectorDetector sd) => StreamingManager.LoadStreamingAssets(assetBundle));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var component in prop.GetComponents<Component>().Concat(prop.GetComponentsInChildren<Component>()))
|
||||||
|
{
|
||||||
|
// Enable all children or something
|
||||||
|
var enabledField = component.GetType().GetField("enabled");
|
||||||
|
if (enabledField != null && enabledField.FieldType == typeof(bool)) enabledField.SetValue(component, true);
|
||||||
|
|
||||||
|
// TODO: Make this work or smthng
|
||||||
|
if (component is GhostIK) (component as GhostIK).enabled = false;
|
||||||
|
if (component is GhostEffects) (component as GhostEffects).enabled = false;
|
||||||
|
|
||||||
|
if (component is SectoredMonoBehaviour)
|
||||||
|
{
|
||||||
|
(component as SectoredMonoBehaviour).SetSector(sector);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component is AnglerfishController)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
(component as AnglerfishController)._chaseSpeed += OWPhysics.CalculateOrbitVelocity(go.GetAttachedOWRigidbody(), go.GetComponent<AstroObject>().GetPrimaryBody().GetAttachedOWRigidbody()).magnitude;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError($"Couldn't update AnglerFish chase speed: {e.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mesh colliders
|
||||||
|
if (generateColliders)
|
||||||
|
{
|
||||||
|
if (component is MeshFilter && component.gameObject.GetComponent<MeshCollider>() == null)
|
||||||
|
{
|
||||||
|
var mesh = (component as MeshFilter).mesh;
|
||||||
|
if (mesh.isReadable) component.gameObject.AddComponent<MeshCollider>();
|
||||||
|
else Logger.LogError($"Couldn't change mesh for {component.gameObject.name} because it is not readable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prop.transform.position = position == null ? go.transform.position : go.transform.TransformPoint((Vector3)position);
|
||||||
|
|
||||||
|
Quaternion rot = rotation == null ? Quaternion.identity : Quaternion.Euler((Vector3)rotation);
|
||||||
|
prop.transform.localRotation = rot;
|
||||||
|
if (alignWithNormal)
|
||||||
|
{
|
||||||
|
var up = prop.transform.localPosition.normalized;
|
||||||
|
var front = Vector3.Cross(up, Vector3.left);
|
||||||
|
if (front.sqrMagnitude == 0f) front = Vector3.Cross(up, Vector3.forward);
|
||||||
|
if (front.sqrMagnitude == 0f) front = Vector3.Cross(up, Vector3.up);
|
||||||
|
|
||||||
|
prop.transform.LookAt(prop.transform.position + front, up);
|
||||||
|
}
|
||||||
|
|
||||||
|
prop.transform.localScale = scale != 0 ? Vector3.one * scale : prefab.transform.localScale;
|
||||||
|
|
||||||
|
prop.SetActive(true);
|
||||||
|
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
79
NewHorizons/Builder/Props/PropBuildManager.cs
Normal file
79
NewHorizons/Builder/Props/PropBuildManager.cs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
using NewHorizons.External;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
using Random = UnityEngine.Random;
|
||||||
|
using Logger = NewHorizons.Utility.Logger;
|
||||||
|
using System.Reflection;
|
||||||
|
using NewHorizons.Utility;
|
||||||
|
using OWML.Common;
|
||||||
|
|
||||||
|
namespace NewHorizons.Builder.Props
|
||||||
|
{
|
||||||
|
public static class PropBuildManager
|
||||||
|
{
|
||||||
|
public static void Make(GameObject go, Sector sector, IPlanetConfig config, IModAssets assets, string uniqueModName)
|
||||||
|
{
|
||||||
|
if (config.Props.Scatter != null)
|
||||||
|
{
|
||||||
|
ScatterBuilder.Make(go, sector, config, assets, uniqueModName);
|
||||||
|
}
|
||||||
|
if(config.Props.Details != null)
|
||||||
|
{
|
||||||
|
DetailBuilder.Make(go, sector, config, assets, uniqueModName);
|
||||||
|
}
|
||||||
|
if(config.Props.Geysers != null)
|
||||||
|
{
|
||||||
|
foreach(var geyserInfo in config.Props.Geysers)
|
||||||
|
{
|
||||||
|
GeyserBuilder.Make(go, sector, geyserInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(config.Props.Tornados != null)
|
||||||
|
{
|
||||||
|
foreach(var tornadoInfo in config.Props.Tornados)
|
||||||
|
{
|
||||||
|
TornadoBuilder.Make(go, sector, tornadoInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GameObject LoadPrefab(string assetBundle, string path, string uniqueModName, IModAssets assets)
|
||||||
|
{
|
||||||
|
string key = uniqueModName + "." + assetBundle;
|
||||||
|
AssetBundle bundle;
|
||||||
|
GameObject prefab;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Main.AssetBundles.ContainsKey(key)) bundle = Main.AssetBundles[key];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bundle = assets.LoadBundle(assetBundle);
|
||||||
|
Main.AssetBundles[key] = bundle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError($"Couldn't load AssetBundle {assetBundle} : {e.Message}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
prefab = bundle.LoadAsset<GameObject>(path);
|
||||||
|
prefab.SetActive(false);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Log($"Couldn't load asset {path} from AssetBundle {assetBundle} : {e.Message}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefab;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,241 +0,0 @@
|
|||||||
using NewHorizons.External;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using UnityEngine;
|
|
||||||
using Random = UnityEngine.Random;
|
|
||||||
using Logger = NewHorizons.Utility.Logger;
|
|
||||||
using System.Reflection;
|
|
||||||
using NewHorizons.Utility;
|
|
||||||
using OWML.Common;
|
|
||||||
|
|
||||||
namespace NewHorizons.Builder.Props
|
|
||||||
{
|
|
||||||
public static class PropBuilder
|
|
||||||
{
|
|
||||||
public static void Make(GameObject go, Sector sector, IPlanetConfig config, IModAssets assets, string uniqueModName)
|
|
||||||
{
|
|
||||||
if (config.Props.Scatter != null)
|
|
||||||
{
|
|
||||||
PropBuilder.MakeScatter(go, config.Props.Scatter, config.Base.SurfaceSize, sector, assets, uniqueModName, config);
|
|
||||||
}
|
|
||||||
if(config.Props.Details != null)
|
|
||||||
{
|
|
||||||
foreach(var detail in config.Props.Details)
|
|
||||||
{
|
|
||||||
if(detail.assetBundle != null)
|
|
||||||
{
|
|
||||||
var prefab = LoadPrefab(detail.assetBundle, detail.path, uniqueModName, assets);
|
|
||||||
MakeDetail(go, sector, prefab, detail.position, detail.rotation, detail.scale, detail.alignToNormal, detail.generateColliders);
|
|
||||||
}
|
|
||||||
else if(detail.objFilePath != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var prefab = assets.Get3DObject(detail.objFilePath, detail.mtlFilePath);
|
|
||||||
prefab.SetActive(false);
|
|
||||||
MakeDetail(go, sector, prefab, detail.position, detail.rotation, detail.scale, detail.alignToNormal, detail.generateColliders);
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
Logger.LogError($"Could not load 3d object {detail.objFilePath} with texture {detail.mtlFilePath} : {e.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else MakeDetail(go, sector, detail.path, detail.position, detail.rotation, detail.scale, detail.alignToNormal, detail.generateColliders);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(config.Props.Geysers != null)
|
|
||||||
{
|
|
||||||
foreach(var geyserInfo in config.Props.Geysers)
|
|
||||||
{
|
|
||||||
GeyserBuilder.Make(go, sector, geyserInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GameObject MakeDetail(GameObject go, Sector sector, string propToClone, MVector3 position, MVector3 rotation, float scale, bool alignWithNormal, bool generateColliders)
|
|
||||||
{
|
|
||||||
var prefab = GameObject.Find(propToClone);
|
|
||||||
|
|
||||||
//TODO: this is super costly
|
|
||||||
if (prefab == null) prefab = SearchUtilities.FindObjectOfTypeAndName<GameObject>(propToClone.Split(new char[] { '\\', '/' }).Last());
|
|
||||||
if (prefab == null) Logger.LogError($"Couldn't find detail {propToClone}");
|
|
||||||
return MakeDetail(go, sector, prefab, position, rotation, scale, alignWithNormal, generateColliders);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GameObject MakeDetail(GameObject go, Sector sector, GameObject prefab, MVector3 position, MVector3 rotation, float scale, bool alignWithNormal, bool generateColliders)
|
|
||||||
{
|
|
||||||
if (prefab == null) return null;
|
|
||||||
|
|
||||||
GameObject prop = GameObject.Instantiate(prefab, sector.transform);
|
|
||||||
prop.SetActive(false);
|
|
||||||
|
|
||||||
List<string> assetBundles = new List<string>();
|
|
||||||
foreach (var streamingHandle in prop.GetComponentsInChildren<StreamingMeshHandle>())
|
|
||||||
{
|
|
||||||
var assetBundle = streamingHandle.assetBundle;
|
|
||||||
if (!assetBundles.Contains(assetBundle))
|
|
||||||
{
|
|
||||||
assetBundles.Add(assetBundle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var assetBundle in assetBundles)
|
|
||||||
{
|
|
||||||
sector.OnOccupantEnterSector += ((SectorDetector sd) => StreamingManager.LoadStreamingAssets(assetBundle));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach(var component in prop.GetComponents<Component>().Concat(prop.GetComponentsInChildren<Component>()))
|
|
||||||
{
|
|
||||||
// Enable all children or something
|
|
||||||
var enabledField = component.GetType().GetField("enabled");
|
|
||||||
if (enabledField != null && enabledField.FieldType == typeof(bool)) enabledField.SetValue(component, true);
|
|
||||||
|
|
||||||
// TODO: Make this work or smthng
|
|
||||||
if (component is GhostIK) (component as GhostIK).enabled = false;
|
|
||||||
if (component is GhostEffects) (component as GhostEffects).enabled = false;
|
|
||||||
|
|
||||||
if(component is SectoredMonoBehaviour)
|
|
||||||
{
|
|
||||||
(component as SectoredMonoBehaviour).SetSector(sector);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (component is AnglerfishController)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
(component as AnglerfishController)._chaseSpeed += OWPhysics.CalculateOrbitVelocity(go.GetAttachedOWRigidbody(), go.GetComponent<AstroObject>().GetPrimaryBody().GetAttachedOWRigidbody()).magnitude;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.LogError($"Couldn't update AnglerFish chase speed: {e.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mesh colliders
|
|
||||||
if (generateColliders)
|
|
||||||
{
|
|
||||||
if(component is MeshFilter && component.gameObject.GetComponent<MeshCollider>() == null)
|
|
||||||
{
|
|
||||||
var mesh = (component as MeshFilter).mesh;
|
|
||||||
if (mesh.isReadable) component.gameObject.AddComponent<MeshCollider>();
|
|
||||||
else Logger.LogError($"Couldn't change mesh for {component.gameObject.name} because it is not readable");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prop.transform.position = position == null ? go.transform.position : go.transform.TransformPoint((Vector3)position);
|
|
||||||
|
|
||||||
Quaternion rot = rotation == null ? Quaternion.identity : Quaternion.Euler((Vector3)rotation);
|
|
||||||
prop.transform.localRotation = rot;
|
|
||||||
if (alignWithNormal)
|
|
||||||
{
|
|
||||||
var up = prop.transform.localPosition.normalized;
|
|
||||||
var front = Vector3.Cross(up, Vector3.left);
|
|
||||||
if (front.sqrMagnitude == 0f) front = Vector3.Cross(up, Vector3.forward);
|
|
||||||
if (front.sqrMagnitude == 0f) front = Vector3.Cross(up, Vector3.up);
|
|
||||||
|
|
||||||
prop.transform.LookAt(prop.transform.position + front, up);
|
|
||||||
}
|
|
||||||
|
|
||||||
prop.transform.localScale = scale != 0 ? Vector3.one * scale : prefab.transform.localScale;
|
|
||||||
|
|
||||||
prop.SetActive(true);
|
|
||||||
|
|
||||||
return prop;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void MakeScatter(GameObject go, PropModule.ScatterInfo[] scatterInfo, float radius, Sector sector, IModAssets assets, string uniqueModName, IPlanetConfig config)
|
|
||||||
{
|
|
||||||
var heightMap = config.HeightMap;
|
|
||||||
|
|
||||||
var area = 4f * Mathf.PI * radius * radius;
|
|
||||||
var points = RandomUtility.FibonacciSphere((int)(area * 10));
|
|
||||||
|
|
||||||
Texture2D heightMapTexture = null;
|
|
||||||
if (heightMap != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
heightMapTexture = assets.GetTexture(heightMap.HeightMap);
|
|
||||||
}
|
|
||||||
catch (Exception) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var propInfo in scatterInfo)
|
|
||||||
{
|
|
||||||
GameObject prefab;
|
|
||||||
if (propInfo.assetBundle != null) prefab = LoadPrefab(propInfo.assetBundle, propInfo.path, uniqueModName, assets);
|
|
||||||
else prefab = GameObject.Find(propInfo.path);
|
|
||||||
for(int i = 0; i < propInfo.count; i++)
|
|
||||||
{
|
|
||||||
var randomInd = (int)Random.Range(0, points.Count);
|
|
||||||
var point = points[randomInd];
|
|
||||||
|
|
||||||
var height = radius;
|
|
||||||
if(heightMapTexture != null)
|
|
||||||
{
|
|
||||||
var sphericals = CoordinateUtilities.CartesianToSpherical(point);
|
|
||||||
float longitude = sphericals.x;
|
|
||||||
float latitude = sphericals.y;
|
|
||||||
|
|
||||||
float sampleX = heightMapTexture.width * longitude / 360f;
|
|
||||||
float sampleY = heightMapTexture.height * latitude / 180f;
|
|
||||||
|
|
||||||
float relativeHeight = heightMapTexture.GetPixel((int)sampleX, (int)sampleY).r;
|
|
||||||
height = (relativeHeight * (heightMap.MaxHeight - heightMap.MinHeight) + heightMap.MinHeight);
|
|
||||||
|
|
||||||
// Because heightmaps are dumb gotta rotate it 90 degrees around the x axis bc UHHHHHHHHHHHHH
|
|
||||||
point = Quaternion.Euler(90, 0, 0) * point;
|
|
||||||
|
|
||||||
// Keep things mostly above water
|
|
||||||
if (config.Water != null && height - 1f < config.Water.Size) continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var prop = MakeDetail(go, sector, prefab, (MVector3)(point.normalized * height), null, propInfo.scale, true, propInfo.generateColliders);
|
|
||||||
if(propInfo.offset != null) prop.transform.localPosition += prop.transform.TransformVector(propInfo.offset);
|
|
||||||
if(propInfo.rotation != null) prop.transform.rotation *= Quaternion.Euler(propInfo.rotation);
|
|
||||||
points.RemoveAt(randomInd);
|
|
||||||
if (points.Count == 0) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static GameObject LoadPrefab(string assetBundle, string path, string uniqueModName, IModAssets assets)
|
|
||||||
{
|
|
||||||
string key = uniqueModName + "." + assetBundle;
|
|
||||||
AssetBundle bundle;
|
|
||||||
GameObject prefab;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Main.AssetBundles.ContainsKey(key)) bundle = Main.AssetBundles[key];
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bundle = assets.LoadBundle(assetBundle);
|
|
||||||
Main.AssetBundles[key] = bundle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.LogError($"Couldn't load AssetBundle {assetBundle} : {e.Message}");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
prefab = bundle.LoadAsset<GameObject>(path);
|
|
||||||
prefab.SetActive(false);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.Log($"Couldn't load asset {path} from AssetBundle {assetBundle} : {e.Message}");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return prefab;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
78
NewHorizons/Builder/Props/ScatterBuilder.cs
Normal file
78
NewHorizons/Builder/Props/ScatterBuilder.cs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
using NewHorizons.Utility;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
using Random = UnityEngine.Random;
|
||||||
|
using Logger = NewHorizons.Utility.Logger;
|
||||||
|
using NewHorizons.External;
|
||||||
|
using OWML.Common;
|
||||||
|
|
||||||
|
namespace NewHorizons.Builder.Props
|
||||||
|
{
|
||||||
|
public static class ScatterBuilder
|
||||||
|
{
|
||||||
|
public static void Make(GameObject go, Sector sector, IPlanetConfig config, IModAssets assets, string uniqueModName)
|
||||||
|
{
|
||||||
|
MakeScatter(go, config.Props.Scatter, config.Base.SurfaceSize, sector, assets, uniqueModName, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void MakeScatter(GameObject go, PropModule.ScatterInfo[] scatterInfo, float radius, Sector sector, IModAssets assets, string uniqueModName, IPlanetConfig config)
|
||||||
|
{
|
||||||
|
var heightMap = config.HeightMap;
|
||||||
|
|
||||||
|
var area = 4f * Mathf.PI * radius * radius;
|
||||||
|
var points = RandomUtility.FibonacciSphere((int)(area * 10));
|
||||||
|
|
||||||
|
Texture2D heightMapTexture = null;
|
||||||
|
if (heightMap != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
heightMapTexture = assets.GetTexture(heightMap.HeightMap);
|
||||||
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var propInfo in scatterInfo)
|
||||||
|
{
|
||||||
|
GameObject prefab;
|
||||||
|
if (propInfo.assetBundle != null) prefab = PropBuildManager.LoadPrefab(propInfo.assetBundle, propInfo.path, uniqueModName, assets);
|
||||||
|
else prefab = GameObject.Find(propInfo.path);
|
||||||
|
for (int i = 0; i < propInfo.count; i++)
|
||||||
|
{
|
||||||
|
var randomInd = (int)Random.Range(0, points.Count);
|
||||||
|
var point = points[randomInd];
|
||||||
|
|
||||||
|
var height = radius;
|
||||||
|
if (heightMapTexture != null)
|
||||||
|
{
|
||||||
|
var sphericals = CoordinateUtilities.CartesianToSpherical(point);
|
||||||
|
float longitude = sphericals.x;
|
||||||
|
float latitude = sphericals.y;
|
||||||
|
|
||||||
|
float sampleX = heightMapTexture.width * longitude / 360f;
|
||||||
|
float sampleY = heightMapTexture.height * latitude / 180f;
|
||||||
|
|
||||||
|
float relativeHeight = heightMapTexture.GetPixel((int)sampleX, (int)sampleY).r;
|
||||||
|
height = (relativeHeight * (heightMap.MaxHeight - heightMap.MinHeight) + heightMap.MinHeight);
|
||||||
|
|
||||||
|
// Because heightmaps are dumb gotta rotate it 90 degrees around the x axis bc UHHHHHHHHHHHHH
|
||||||
|
point = Quaternion.Euler(90, 0, 0) * point;
|
||||||
|
|
||||||
|
// Keep things mostly above water
|
||||||
|
if (config.Water != null && height - 1f < config.Water.Size) continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var prop = DetailBuilder.MakeDetail(go, sector, prefab, (MVector3)(point.normalized * height), null, propInfo.scale, true, propInfo.generateColliders);
|
||||||
|
if (propInfo.offset != null) prop.transform.localPosition += prop.transform.TransformVector(propInfo.offset);
|
||||||
|
if (propInfo.rotation != null) prop.transform.rotation *= Quaternion.Euler(propInfo.rotation);
|
||||||
|
points.RemoveAt(randomInd);
|
||||||
|
if (points.Count == 0) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
89
NewHorizons/Builder/Props/TornadoBuilder.cs
Normal file
89
NewHorizons/Builder/Props/TornadoBuilder.cs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
using NewHorizons.External;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
using Logger = NewHorizons.Utility.Logger;
|
||||||
|
|
||||||
|
namespace NewHorizons.Builder.Props
|
||||||
|
{
|
||||||
|
public static class TornadoBuilder
|
||||||
|
{
|
||||||
|
public static string tornadoParentName = "Tornados";
|
||||||
|
|
||||||
|
public static void Make(GameObject go, Sector sector, PropModule.TornadoInfo info)
|
||||||
|
{
|
||||||
|
// If we are given elevation choose a random position
|
||||||
|
Vector3 position;
|
||||||
|
float elevation = 0f;
|
||||||
|
|
||||||
|
if (info.position != null)
|
||||||
|
{
|
||||||
|
position = info.position;
|
||||||
|
elevation = position.magnitude;
|
||||||
|
}
|
||||||
|
else if (info.elevation != 0f)
|
||||||
|
{
|
||||||
|
position = UnityEngine.Random.insideUnitSphere * info.elevation;
|
||||||
|
elevation = info.elevation;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.LogError($"Couldn't make tornado for {go.name}: No elevation or position was given");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var prefab = GameObject.Find("GiantsDeep_Body/Sector_GD/Sector_GDInterior/Tornadoes_GDInterior/MovingTornadoes/Root/UpTornado_Pivot (2)");
|
||||||
|
|
||||||
|
// Default radius is 40, height is 837.0669
|
||||||
|
|
||||||
|
var tornado = GameObject.Instantiate(prefab, sector.transform);
|
||||||
|
tornado.SetActive(false);
|
||||||
|
|
||||||
|
tornado.transform.localPosition = Vector3.zero;
|
||||||
|
|
||||||
|
var scale = Vector3.one;
|
||||||
|
var height = 837.0669f;
|
||||||
|
if (info.scale != null)
|
||||||
|
{
|
||||||
|
scale = new Vector3(info.scale.X / 40f, info.scale.Y / 837.0669f, info.scale.Z / 40f);
|
||||||
|
height = info.scale.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
tornado.transform.localScale = scale;
|
||||||
|
|
||||||
|
var tornadoController = tornado.GetComponent<TornadoController>();
|
||||||
|
tornadoController.SetSector(sector);
|
||||||
|
var n = position.normalized;
|
||||||
|
tornadoController._bottomBone.localPosition = n * elevation;
|
||||||
|
tornadoController._midBone.localPosition = n * (elevation + height/2f);
|
||||||
|
tornadoController._topBone.localPosition = n * (elevation + height);
|
||||||
|
|
||||||
|
tornadoController._snapBonesToSphere = true;
|
||||||
|
tornadoController._wander = true;
|
||||||
|
tornadoController._wanderRate = 0.02f;
|
||||||
|
tornadoController._wanderDegreesX = 360f;
|
||||||
|
tornadoController._wanderDegreesZ = 360f;
|
||||||
|
|
||||||
|
/*
|
||||||
|
tornadoController._formationDuration = 1f;
|
||||||
|
tornadoController._collapseDuration = 1f;
|
||||||
|
sector.OnOccupantEnterSector += ((sectorDetector) =>
|
||||||
|
{
|
||||||
|
tornadoController.StartFormation();
|
||||||
|
});
|
||||||
|
sector.OnOccupantExitSector += ((sectorDetector) =>
|
||||||
|
{
|
||||||
|
if (!sector.ContainsOccupant(DynamicOccupant.Player | DynamicOccupant.Probe | DynamicOccupant.Ship))
|
||||||
|
{
|
||||||
|
tornadoController.StartCollapse();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
|
tornado.SetActive(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
NewHorizons/External/PropModule.cs
vendored
9
NewHorizons/External/PropModule.cs
vendored
@ -13,6 +13,7 @@ namespace NewHorizons.External
|
|||||||
public DetailInfo[] Details;
|
public DetailInfo[] Details;
|
||||||
public RaftInfo[] Rafts;
|
public RaftInfo[] Rafts;
|
||||||
public GeyserInfo[] Geysers;
|
public GeyserInfo[] Geysers;
|
||||||
|
public TornadoInfo[] Tornados;
|
||||||
|
|
||||||
public class ScatterInfo
|
public class ScatterInfo
|
||||||
{
|
{
|
||||||
@ -47,5 +48,13 @@ namespace NewHorizons.External
|
|||||||
{
|
{
|
||||||
public MVector3 position;
|
public MVector3 position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class TornadoInfo
|
||||||
|
{
|
||||||
|
public float elevation;
|
||||||
|
public MVector3 position;
|
||||||
|
public MVector3 scale;
|
||||||
|
public MColor tint;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user