Clean up node builder

This commit is contained in:
Nick 2022-07-21 21:58:19 -04:00
parent 57c0418025
commit 239b34798f

View File

@ -12,7 +12,6 @@ using Logger = NewHorizons.Utility.Logger;
namespace NewHorizons.Builder.Props namespace NewHorizons.Builder.Props
{ {
// TODO // TODO
//3) support for existing dimensions? //3) support for existing dimensions?
//5) test whether nodes can lead to vanilla dimensions //5) test whether nodes can lead to vanilla dimensions
@ -37,25 +36,19 @@ namespace NewHorizons.Builder.Props
_propagatedSignals = null; _propagatedSignals = null;
NamedNodes = new(); NamedNodes = new();
BuiltBrambleNodes = new(); BuiltBrambleNodes = new();
PropagateSignals();
} }
// how warping works
// every frame, each FogWarpDetector loops over all FogWarpVolume instances it has in _warpVolumes. Each instance gets CheckWarpProximity called
// (pretty much every FogWarpVolume in the game is a SphericalFogWarpVolume. that's where CheckWarpProximity is called)
// if CheckWarpProximity would return 0, it calls its own WarpDetector() function
//
public static void FinishPairingNodesForDimension(string dimensionName, AstroObject dimensionAO = null) public static void FinishPairingNodesForDimension(string dimensionName, AstroObject dimensionAO = null)
{ {
Logger.LogWarning($"Pairing missed for {dimensionName}"); Logger.LogVerbose($"Pairing missed for {dimensionName}");
if (!_unpairedNodes.ContainsKey(dimensionName)) return; if (!_unpairedNodes.ContainsKey(dimensionName)) return;
Logger.LogWarning("proceeding"); Logger.LogVerbose("proceeding");
foreach (var nodeWarpController in _unpairedNodes[dimensionName]) foreach (var nodeWarpController in _unpairedNodes[dimensionName])
{ {
Logger.LogWarning($"Pairing node {nodeWarpController.gameObject.name} links to {dimensionName}"); Logger.LogVerbose($"Pairing node {nodeWarpController.gameObject.name} links to {dimensionName}");
PairEntrance(nodeWarpController, dimensionName, dimensionAO); PairEntrance(nodeWarpController, dimensionName, dimensionAO);
} }
@ -66,7 +59,7 @@ namespace NewHorizons.Builder.Props
{ {
if (!_unpairedNodes.ContainsKey(linksTo)) _unpairedNodes[linksTo] = new(); if (!_unpairedNodes.ContainsKey(linksTo)) _unpairedNodes[linksTo] = new();
Logger.LogWarning($"Recording node {warpVolume.gameObject.name} links to {linksTo}"); Logger.LogVerbose($"Recording node {warpVolume.gameObject.name} links to {linksTo}");
_unpairedNodes[linksTo].Add(warpVolume); _unpairedNodes[linksTo].Add(warpVolume);
} }
@ -80,29 +73,22 @@ namespace NewHorizons.Builder.Props
return outerFogWarpVolume; return outerFogWarpVolume;
} }
// Makes signals inside dimensions appear on the nodes as well
// Runs Floyd-Warshall algorithm on dimensions and nodes.
private static void PropagateSignals() private static void PropagateSignals()
{ {
// The purpose of this function is to determine which signals any given node should play, based on which dimension it links to
// you know how the main dark bramble node, the one that forms the core of the planet, plays Feldspar's harmonica signal, even though Feldspar isn't in the dimension that the node links directly to?
// that's what this function is for. it would determine that the main node should play Feldspar's signal
// New Strategy (thanks Damian):
// 1) Run Floyd-Warshall on the dimensions (where each dimension is a vertex and each node is an edge)
// 2) For each dimension A, if it's possible to reach dimension B, add dimension B's signals to the list propagatedSignals[A]
var allDimensions = PlanetCreationHandler.Bodies.Where(body => body?.Config?.Bramble?.dimension != null).Select(body => body.Config).ToList(); var allDimensions = PlanetCreationHandler.Bodies.Where(body => body?.Config?.Bramble?.dimension != null).Select(body => body.Config).ToList();
// // Access will be our final answer - if access[i, j], then nodes linking to dimension i should display all of dimension j's signals
// Floyd Warshall
//
// access will be our final answer - if access[i, j], then nodes linking to dimension i should display all of dimension j's signals
var access = new bool[allDimensions.Count(), allDimensions.Count()]; var access = new bool[allDimensions.Count(), allDimensions.Count()];
var dimensionNameToIndex = new Dictionary<string, int>(); var dimensionNameToIndex = new Dictionary<string, int>();
for (int dimensionIndex = 0; dimensionIndex < allDimensions.Count(); dimensionIndex++) dimensionNameToIndex[allDimensions[dimensionIndex].name] = dimensionIndex; for (int dimensionIndex = 0; dimensionIndex < allDimensions.Count(); dimensionIndex++)
{
dimensionNameToIndex[allDimensions[dimensionIndex].name] = dimensionIndex;
}
// set up the direct links (ie, if dimension 0 contains a node that links to dimension 3, set access[0, 3] = true) // Set up the direct links (ie, if dimension 0 contains a node that links to dimension 3, set access[0, 3] = true)
for (int dimensionIndex = 0; dimensionIndex < allDimensions.Count(); dimensionIndex++) for (int dimensionIndex = 0; dimensionIndex < allDimensions.Count(); dimensionIndex++)
{ {
var dimension = allDimensions[dimensionIndex]; var dimension = allDimensions[dimensionIndex];
@ -114,21 +100,22 @@ namespace NewHorizons.Builder.Props
} }
} }
// a node that links to dimension A should display all of dimension A's signals, so for the purposes of our function, we need to say that dimension A links to dimension A // A node that links to dimension A should display all of dimension A's signals, so for the purposes of our function,
for (int dimensionIndex = 0; dimensionIndex < allDimensions.Count(); dimensionIndex++) access[dimensionIndex, dimensionIndex] = true; // we need to say that dimension A links to dimension A
for (int dimensionIndex = 0; dimensionIndex < allDimensions.Count(); dimensionIndex++)
{
access[dimensionIndex, dimensionIndex] = true;
}
// The actual Floyd-Warshall - determine whether each pair of dimensions link indirectly (eg if A->B->C, then after this step, access[A, C] = true) // The actual Floyd-Warshall - determine whether each pair of dimensions link indirectly (eg if A->B->C,
// then after this step, access[A, C] = true)
for (int k = 0; k < allDimensions.Count(); k++) for (int k = 0; k < allDimensions.Count(); k++)
for (int i = 0; i < allDimensions.Count(); i++) for (int i = 0; i < allDimensions.Count(); i++)
for (int j = 0; j < allDimensions.Count(); j++) for (int j = 0; j < allDimensions.Count(); j++)
if (access[i, k] && access[k, j]) if (access[i, k] && access[k, j])
access[i, j] = true; access[i, j] = true;
// // This dictionary lists all the signals a given node should have, depending on the dimension it links to
// Build the list of dimensionName -> List<SignalInfo>
//
// this dictionary lists all the signals a given node should have, depending on the dimension it links to
// ie, if a node links to "dimension1", then that node should spawn all of the signals in the list propagatedSignals["dimension1"] // ie, if a node links to "dimension1", then that node should spawn all of the signals in the list propagatedSignals["dimension1"]
_propagatedSignals = new Dictionary<string, List<SignalInfo>>(); _propagatedSignals = new Dictionary<string, List<SignalInfo>>();
foreach (var dimension in allDimensions) foreach (var dimension in allDimensions)
@ -149,20 +136,21 @@ namespace NewHorizons.Builder.Props
} }
} }
// Returns ture or false depending on if it succeeds
private static bool PairEntrance(InnerFogWarpVolume nodeWarp, string destinationName, AstroObject dimensionAO = null) private static bool PairEntrance(InnerFogWarpVolume nodeWarp, string destinationName, AstroObject dimensionAO = null)
{ {
Logger.LogWarning($"Pairing node {nodeWarp.gameObject.name} to {destinationName}"); Logger.LogVerbose($"Pairing node {nodeWarp.gameObject.name} to {destinationName}");
var destinationAO = dimensionAO ?? AstroObjectLocator.GetAstroObject(destinationName); // find child "Sector/OuterWarp" var destinationAO = dimensionAO ?? AstroObjectLocator.GetAstroObject(destinationName);
if (destinationAO == null) return false; if (destinationAO == null) return false;
Logger.LogWarning($"Found {destinationName} as gameobject {destinationAO.gameObject.name} (was passed in: {dimensionAO != null})"); Logger.LogVerbose($"Found {destinationName} as gameobject {destinationAO.gameObject.name} (was passed in: {dimensionAO != null})");
// link the node's warp volume to the destination's // link the node's warp volume to the destination's
var destination = GetOuterFogWarpVolumeFromAstroObject(destinationAO.gameObject); var destination = GetOuterFogWarpVolumeFromAstroObject(destinationAO.gameObject);
if (destination == null) return false; if (destination == null) return false;
Logger.LogWarning($"Proceeding with pairing node {nodeWarp.gameObject.name} to {destinationName}. Path to outer fog warp volume: {destination.transform.GetPath()}"); Logger.LogVerbose($"Proceeding with pairing node {nodeWarp.gameObject.name} to {destinationName}. Path to outer fog warp volume: {destination.transform.GetPath()}");
nodeWarp._linkedOuterWarpVolume = destination; nodeWarp._linkedOuterWarpVolume = destination;
destination.RegisterSenderWarp(nodeWarp); destination.RegisterSenderWarp(nodeWarp);
@ -170,10 +158,6 @@ namespace NewHorizons.Builder.Props
return true; return true;
} }
// DB_EscapePodDimension_Body/Sector_EscapePodDimension/Interactables_EscapePodDimension/InnerWarp_ToAnglerNest // need to change the light shaft color
// 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"
public static void Make(GameObject go, Sector sector, BrambleNodeInfo[] configs, IModBehaviour mod) public static void Make(GameObject go, Sector sector, BrambleNodeInfo[] configs, IModBehaviour mod)
{ {
foreach (var config in configs) foreach (var config in configs)
@ -194,7 +178,6 @@ namespace NewHorizons.Builder.Props
} }
var innerFogWarpVolume = brambleNode.GetComponent<InnerFogWarpVolume>(); var innerFogWarpVolume = brambleNode.GetComponent<InnerFogWarpVolume>();
//brambleNode.AddComponent<FogWarpHUDMarker>();
var fogLight = brambleNode.GetComponent<FogLight>(); var fogLight = brambleNode.GetComponent<FogLight>();
brambleNode.transform.parent = sector.transform; brambleNode.transform.parent = sector.transform;
@ -228,12 +211,13 @@ namespace NewHorizons.Builder.Props
innerFogWarpVolume._exits = newExits.ToArray(); innerFogWarpVolume._exits = newExits.ToArray();
} }
// set up screen fog effect // Set up screen fog effect
// (in the base game, any sector that contains a bramble node needs an EffectRuleset with type FogWarp) // (in the base game, any sector that contains a bramble node needs an EffectRuleset with type FogWarp)
// (this isn't jank I swear, this is how it's supposed to work) // (this isn't jank I swear, this is how it's supposed to work)
var sectorHasFogEffectRuleset = sector var sectorHasFogEffectRuleset = sector
.GetComponents<EffectRuleset>() .GetComponents<EffectRuleset>()
.Any(effectRuleset => effectRuleset._type == EffectRuleset.BubbleType.FogWarp); .Any(effectRuleset => effectRuleset._type == EffectRuleset.BubbleType.FogWarp);
if (!sectorHasFogEffectRuleset) if (!sectorHasFogEffectRuleset)
{ {
var fogEffectRuleset = sector.gameObject.AddComponent<EffectRuleset>(); var fogEffectRuleset = sector.gameObject.AddComponent<EffectRuleset>();
@ -246,14 +230,16 @@ namespace NewHorizons.Builder.Props
fogEffectRuleset._material = GameObject.Find("DB_PioneerDimension_Body/Sector_PioneerDimension").GetComponent<EffectRuleset>()._material; fogEffectRuleset._material = GameObject.Find("DB_PioneerDimension_Body/Sector_PioneerDimension").GetComponent<EffectRuleset>()._material;
} }
//TODO: replace InnerFogWarpVolume with NHInnerFogWarpVolume, which overrides GetFogDensity to account for scale (this will fix the issue with screen fog caused by scaled down nodes) // TODO: replace InnerFogWarpVolume with NHInnerFogWarpVolume, which overrides GetFogDensity to
// account for scale (this will fix the issue with screen fog caused by scaled down nodes)
// Set the scale // Set the scale
brambleNode.transform.localScale = Vector3.one * config.scale; brambleNode.transform.localScale = Vector3.one * config.scale;
innerFogWarpVolume._warpRadius *= config.scale; innerFogWarpVolume._warpRadius *= config.scale;
innerFogWarpVolume._exitRadius *= config.scale; innerFogWarpVolume._exitRadius *= config.scale;
// Seed fog works differently, so it doesn't need to be fixed (it's also located on a different child path, so the below FindChild calls wouldn't work) // Seed fog works differently, so it doesn't need to be fixed
// (it's also located on a different child path, so the below FindChild calls wouldn't work)
if (!config.isSeed) if (!config.isSeed)
{ {
var fog = brambleNode.FindChild("Effects/InnerWarpFogSphere"); var fog = brambleNode.FindChild("Effects/InnerWarpFogSphere");
@ -276,8 +262,12 @@ namespace NewHorizons.Builder.Props
// Set up warps // Set up warps
innerFogWarpVolume._sector = sector; innerFogWarpVolume._sector = sector;
innerFogWarpVolume._attachedBody = go.GetComponent<OWRigidbody>(); // I don't think this is necessary, it seems to be set correctly on its own innerFogWarpVolume._attachedBody = go.GetComponent<OWRigidbody>();
innerFogWarpVolume._containerWarpVolume = GetOuterFogWarpVolumeFromAstroObject(go); // the OuterFogWarpVolume of the dimension this node is inside of (null if this node is not inside of a bramble dimension (eg it's sitting on a planet or something))
// the OuterFogWarpVolume of the dimension this node is inside of
// (null if this node is not inside of a bramble dimension, eg it's sitting on a planet or something)
innerFogWarpVolume._containerWarpVolume = GetOuterFogWarpVolumeFromAstroObject(go);
var success = PairEntrance(innerFogWarpVolume, config.linksTo); var success = PairEntrance(innerFogWarpVolume, config.linksTo);
if (!success) RecordUnpairedNode(innerFogWarpVolume, config.linksTo); if (!success) RecordUnpairedNode(innerFogWarpVolume, config.linksTo);
@ -289,7 +279,6 @@ namespace NewHorizons.Builder.Props
} }
// Make signals // Make signals
if (_propagatedSignals == null) PropagateSignals();
foreach (var signalConfig in _propagatedSignals[config.linksTo]) foreach (var signalConfig in _propagatedSignals[config.linksTo])
{ {
var signalGO = SignalBuilder.Make(go, sector, signalConfig, mod); var signalGO = SignalBuilder.Make(go, sector, signalConfig, mod);