206 lines
6.1 KiB
C#
206 lines
6.1 KiB
C#
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<BlocksMap>();
|
|
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<Vector3, BlockNode> map = currentMap.blocks[node.blockData.blockName];
|
|
if (map == null)
|
|
{
|
|
map = new Dictionary<Vector3, BlockNode>();
|
|
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<Vector3, BlockNode> 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
|
|
|
|
}
|