using System; using System.Collections.Generic; using HG; using RoR2.Navigation; using UnityEngine; using UnityEngine.Serialization; namespace RoR2; public class SceneInfo : MonoBehaviour { private static class NodeGraphOverlay { private static Dictionary<(MapNodeGroup.GraphType graphType, HullMask hullMask), (DebugOverlay.MeshDrawer drawer, Action updater)> drawers; private static void StaticUpdate() { foreach (KeyValuePair<(MapNodeGroup.GraphType, HullMask), (DebugOverlay.MeshDrawer, Action)> drawer in drawers) { drawer.Value.Item2(); } } private static void SetGraphDrawEnabled(bool shouldDraw, MapNodeGroup.GraphType graphType, HullMask hullMask) { (MapNodeGroup.GraphType, HullMask) key = (graphType, hullMask); DebugOverlay.MeshDrawer drawer; GenericMemoizer<(DebugOverlay.MeshDrawer, SceneInfo, MapNodeGroup.GraphType, HullMask), Mesh> getNodeGraphMeshMemoizer; if (shouldDraw) { if (drawers == null) { drawers = new Dictionary<(MapNodeGroup.GraphType, HullMask), (DebugOverlay.MeshDrawer, Action)>(); RoR2Application.onUpdate += StaticUpdate; } if (!drawers.ContainsKey(key)) { drawer = DebugOverlay.GetMeshDrawer(); drawer.hasMeshOwnership = true; drawer.material = DebugOverlay.defaultWireMaterial; getNodeGraphMeshMemoizer = new GenericMemoizer<(DebugOverlay.MeshDrawer, SceneInfo, MapNodeGroup.GraphType, HullMask), Mesh>(GetNodeGraphMesh); drawers.Add(key, (drawer, Updater)); } } else if (drawers != null) { if (drawers.TryGetValue(key, out (DebugOverlay.MeshDrawer, Action) value)) { value.Item1.Dispose(); drawers.Remove(key); } if (drawers.Count == 0) { drawers = null; RoR2Application.onUpdate -= StaticUpdate; } } static Mesh GetNodeGraphMesh(in (DebugOverlay.MeshDrawer, SceneInfo sceneInfo, MapNodeGroup.GraphType graphType, HullMask hullMask) input) { return input.sceneInfo?.GetNodeGraph(input.graphType).GenerateLinkDebugMesh(input.hullMask); } void Updater() { DebugOverlay.MeshDrawer meshDrawer = drawer; ref GenericMemoizer<(DebugOverlay.MeshDrawer, SceneInfo, MapNodeGroup.GraphType, HullMask), Mesh> reference = ref getNodeGraphMeshMemoizer; (DebugOverlay.MeshDrawer, SceneInfo, MapNodeGroup.GraphType, HullMask) input2 = (drawer, instance, graphType, hullMask); meshDrawer.mesh = reference.Evaluate(in input2); } } [ConCommand(commandName = "debug_scene_draw_nodegraph", flags = ConVarFlags.Cheat, helpText = "Enables/disables overlay drawing of the specified nodegraph. Format: {shouldDraw} {graphType} {hullClassification, ...}")] private static void CCDebugSceneDrawNodegraph(ConCommandArgs args) { bool argBool = args.GetArgBool(0); MapNodeGroup.GraphType argEnum = args.GetArgEnum(1); HullMask hullMask = (HullMask)(1 << (int)args.GetArgEnum(2)); if (hullMask == HullMask.None) { throw new ConCommandException("Cannot use HullMask.None."); } for (int i = 3; i < args.Count; i++) { HullClassification? hullClassification = args.TryGetArgEnum(i); if (hullClassification.HasValue) { hullMask = (HullMask)((int)hullMask | (1 << (int)hullClassification.Value)); } } SetGraphDrawEnabled(argBool, argEnum, hullMask); } } private static SceneInfo _instance; [FormerlySerializedAs("groundNodes")] public MapNodeGroup groundNodeGroup; [FormerlySerializedAs("airNodes")] public MapNodeGroup airNodeGroup; [FormerlySerializedAs("railNodes")] public MapNodeGroup railNodeGroup; public MeshRenderer approximateMapBoundMesh; [SerializeField] private NodeGraph groundNodesAsset; [SerializeField] private NodeGraph airNodesAsset; public static SceneInfo instance => _instance; public NodeGraph groundNodes { get; private set; } public NodeGraph airNodes { get; private set; } public NodeGraph railNodes { get; private set; } public SceneDef sceneDef { get; private set; } public bool countsAsStage { get { if (!sceneDef) { return false; } if (sceneDef.sceneType != SceneType.Stage) { return sceneDef.sceneType == SceneType.UntimedStage; } return true; } } private void Awake() { if ((bool)groundNodesAsset) { groundNodes = UnityEngine.Object.Instantiate(groundNodesAsset); } else { Debug.LogWarning(base.gameObject.scene.name + " has no groundNodesAsset"); } if ((bool)airNodesAsset) { airNodes = UnityEngine.Object.Instantiate(airNodesAsset); } else { Debug.LogWarning(base.gameObject.scene.name + " has no airNodesAsset"); } sceneDef = SceneCatalog.GetSceneDefFromSceneName(base.gameObject.scene.name); } private void Start() { } private void RemoveCollisionFromParticleSystems() { ParticleSystem[] array = UnityEngine.Object.FindObjectsOfType(); int num = 0; ParticleSystem[] array2 = array; for (int i = 0; i < array2.Length; i++) { ParticleSystem.CollisionModule collision = array2[i].collision; if (collision.enabled) { num++; } collision.enabled = false; } } private void OnDestroy() { UnityEngine.Object.Destroy(groundNodes); UnityEngine.Object.Destroy(airNodes); UnityEngine.Object.Destroy(railNodes); } public MapNodeGroup GetNodeGroup(MapNodeGroup.GraphType nodeGraphType) { return nodeGraphType switch { MapNodeGroup.GraphType.Ground => groundNodeGroup, MapNodeGroup.GraphType.Air => airNodeGroup, MapNodeGroup.GraphType.Rail => railNodeGroup, _ => null, }; } public NodeGraph GetNodeGraph(MapNodeGroup.GraphType nodeGraphType) { return nodeGraphType switch { MapNodeGroup.GraphType.Ground => groundNodes, MapNodeGroup.GraphType.Air => airNodes, MapNodeGroup.GraphType.Rail => railNodes, _ => null, }; } public void SetGateState(string gateName, bool gateEnabled) { bool flag = false; if ((bool)groundNodes) { flag = groundNodes.TrySetGateState(gateName, gateEnabled) || flag; } if ((bool)airNodes) { flag = airNodes.TrySetGateState(gateName, gateEnabled) || flag; } if ((bool)railNodes) { flag = railNodes.TrySetGateState(gateName, gateEnabled) || flag; } if (!flag) { Debug.LogError($"Unable to set gate state for {base.gameObject.scene.name}: {gateName}={gateEnabled}"); } } private void OnEnable() { if (!_instance) { _instance = this; } } private void OnDisable() { if (_instance == this) { _instance = null; } } private void OnValidate() { if ((bool)groundNodeGroup) { groundNodesAsset = groundNodeGroup.nodeGraph; } if ((bool)airNodeGroup) { airNodesAsset = airNodeGroup.nodeGraph; } } }