using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using NaughtyAttributes; using UnityEngine.UIElements; public class ModelCheckManager : MonoBehaviour { private static ModelCheckManager instance; public static ModelCheckManager getInstance() => instance; private Environment environment; [SerializeField] private BlocksMap blocksMap; private BlocksMap currentMap; private long validNodes; private long invalidNodes; private long totalNodes; public UnityEvent OnAllValidEvent; // help notifing the correctness of all blocks public UnityEvent OnValidNodeEvent; // add a feedback (materail change, flush light, correct sound, etc) public UnityEvent OnInvalidNodeEvent; // add a feedback (materail change, flush light, incorrect sound, etc) [Header("Map Recording")] public string newMapName = "NewBlocksMap"; [SerializeField] private bool debug = false; public void setBlockMap(BlocksMap map) { blocksMap = map; totalNodes = blocksMap.calcTotalNodes(); } void Start() { if (debug) Initialize(); } // TODO: call this function after selecting the current map and switch to editor scene public void Initialize() { environment = Environment.getInstance(); // get total nodes in the blocksMap if (blocksMap != null) totalNodes = blocksMap.calcTotalNodes(); // add listener to env events environment.onBlockAddedEvent.AddListener(x => { addNode(createBlockNode(x.getBlockData(), x.transform.position, x.transform.rotation)); }); environment.onBlockRemovedEvent.AddListener(x => { removeNode(x.getBlockData().blockName, x.transform.position); }); environment.onBlockMovedEvt.AddListener((block, pos, rot) => { removeNode(block.getBlockData().blockName, pos); addNode(createBlockNode(block.getBlockData(), block.transform.position, block.transform.rotation)); }); // initialize the current map validNodes = 0; invalidNodes = 0; currentMap = ScriptableObject.CreateInstance(); currentMap.init(blocksMap); } private BlockNode createBlockNode(BlockData blockData, Vector3 position, Quaternion rotation) { return new BlockNode(blockData, BlocksMap.RoundPosition(position), BlocksMap.RoundRotation(rotation)); } private void Awake() { if (instance == null) instance = this; else Destroy(gameObject); } // handle node addition public void addNode(BlockNode node) { Dictionary map = currentMap.blocks[node.blockData.blockName]; if (map == null) { map = new Dictionary(); currentMap.blocks[node.blockData.blockName] = map; } map[node.position] = node; currentMap.allNodes.Add(node); if (blocksMap == null) return; if (tryMarkNode(node)) { validNodes++; OnValidNodeEvent.Invoke(); if (validNodes == totalNodes && invalidNodes == 0) OnAllValidEvent.Invoke(); } else { invalidNodes++; OnInvalidNodeEvent.Invoke(); } debugisValid(node); } // handle updating the node when moving it using the transform //public void updateNode(BlockNode node) //{ // // TODO: Update node positions when moved / CTRL + Z if it changed to account for deleting it //} // handle node removal public void removeNode(string blockName, Vector3 position) { position = BlocksMap.RoundPosition(position); BlockNode node = currentMap.blocks[blockName][position]; if (blocksMap == null) return; currentMap.blocks[blockName].Remove(node.position); currentMap.allNodes.Remove(node); if (node.matchedNode != null) // valid node { node.matchedNode.matchedNode = null; node.matchedNode = null; validNodes--; } else // invalid node { invalidNodes--; } } private bool tryMarkNode(BlockNode node) { Dictionary map = blocksMap.blocks[node.blockData.blockName]; if (map == null) return false; if (!map.TryGetValue(node.position, out BlockNode target)) return false; if (!matchRotation(node, target)) return false; target.matchedNode = node; node.matchedNode = target; return true; } private bool matchRotation(BlockNode node1, BlockNode node2) { float angle = Quaternion.Angle(node1.rotation.normalized, node2.rotation.normalized); return node1.rotation.normalized.Equals(node2.rotation.normalized) || angle == 180; } private void debugisValid(BlockNode node) { Debug.Log($"Node at {node.position} is " + (node.matchedNode != null ? "valid" : "invalid")); } // TODO: seperate this Editor tool #if UNITY_EDITOR [Button("Save Current Map as Asset")] public void saveCurrentMap() { if (currentMap == null) { Debug.LogWarning("No current map to save."); return; } if (currentMap.allNodes.Count == 0) { Debug.LogWarning("Current map is empty. Nothing to save."); return; } currentMap.setRootNode(currentMap.allNodes[0]); string folder = "Assets/BlocksMaps"; if (!UnityEditor.AssetDatabase.IsValidFolder(folder)) UnityEditor.AssetDatabase.CreateFolder("Assets", "BlocksMaps"); string path = $"{folder}/{newMapName}.asset"; UnityEditor.AssetDatabase.CreateAsset(currentMap, path); UnityEditor.EditorUtility.SetDirty(currentMap); UnityEditor.AssetDatabase.SaveAssets(); UnityEditor.AssetDatabase.Refresh(); UnityEditor.EditorGUIUtility.PingObject(currentMap); Debug.Log($"Saved to {path}"); } #endif }