using System.Collections; using System.Collections.Generic; using UnityEngine; using KairoEngine.Chunks; using KairoEngine.Core; using KairoEngine.UI; using Utils = KairoEngine.Utility.Utilities; using Sirenix.OdinInspector; namespace KairoEngine.VoxelBuildingSystem { [HideMonoScript] public class VoxelBuildingSystem : MonoBehaviour { public static VoxelBuildingSystem instance; public Vector3Int chunkSize = new Vector3Int(16, 16, 16); public Vector3Int chunkCount = new Vector3Int(3, 3, 3); public Vector3 voxelSize = new Vector3(1f, 1f, 1f); public LayerMask layerMask; public List buildingTemplates = new List(); [ReadOnly] public int currentBuildingTemplate; [ReadOnly] public VoxelBuildingTool tool = VoxelBuildingTool.Build; public ChunkSystem chunkSystem; [HideInInspector] public Dictionary buildings = new Dictionary(); [HideInInspector] public List buildingList = new List(); private Vector3 pointerPosition; public void CreateVoxelSystem() { chunkSystem = new ChunkSystem(chunkSize, false); for (int x = 0; x < chunkCount.x; x++) { for (int z = 0; z < chunkCount.z; z++) { for (int y = 0; y < chunkCount.y; y++) { Vector3Int chunkPos = new Vector3Int(x * chunkSize.x, y * chunkSize.y, z * chunkSize.z); chunkSystem.CreateChunk(chunkPos, (Chunk c, Vector3Int pos) => new VoxelBuildData(pos, -1)); } } } } void Start() => CreateVoxelSystem(); void Update() { pointerPosition = Utils.GetMouseWorldPosition(layerMask.value); if(!MouseInputUIBlocker.BlockedByUI) { switch (tool) { case VoxelBuildingTool.Build: if(Input.GetKeyDown(KeyCode.R)) RotateBuilding(); if(Input.GetMouseButtonDown(0)) PlaceBuilding(pointerPosition); break; case VoxelBuildingTool.Remove: if(Input.GetMouseButtonDown(0)) RemoveBuilding(pointerPosition); break; default: break; } } if(Input.GetKeyDown(KeyCode.Alpha1)) CycleBuildingTemplate(); } public void RotateBuilding() {} public void PlaceBuilding(Vector3 pos) { Vector3 worldPos = GetMouseWorldSnappedPosition(); Vector3Int voxelPos = FindVoxelPosition(pointerPosition); if(!CanPlaceBuilding(voxelPos, currentBuildingTemplate, true)) return; Transform newBuilding = Instantiate(buildingTemplates[currentBuildingTemplate].prefab, worldPos, this.transform.rotation, this.transform); BuildingBehaviour buildingBehaviour = newBuilding.GetComponent(); if(buildingBehaviour == null) { Debug.LogError($"Building prefab has no BuildingBehaviour component! Cannot place building", newBuilding); Destroy(newBuilding); return; } buildingBehaviour.origin = voxelPos; buildings.Add(voxelPos, buildingBehaviour); buildingList.Add(buildingBehaviour); List voxelPositions = GetBuildingVoxelList(voxelPos, currentBuildingTemplate); for (int i = 0; i < voxelPositions.Count; i++) { VoxelBuildData block = chunkSystem.GetBlock(voxelPositions[i]); block.buildingIndex = buildingList.Count - 1; block.buildingTemplateIndex = currentBuildingTemplate; chunkSystem.SetBlock(voxelPositions[i], block); } } public bool CanPlaceBuilding(Vector3Int voxelPos, int buildingTemplateIndex, bool debug = false) { List voxelPositions = GetBuildingVoxelList(voxelPos, buildingTemplateIndex); for (int i = 0; i < voxelPositions.Count; i++) { VoxelBuildData block = chunkSystem.GetBlock(voxelPositions[i]); if(block.buildingIndex != -1) { if(debug) Debug.Log("Cannot place building, place is occupied."); return false; } } return true; } public void RemoveBuilding(Vector3 pos) {} public Vector3Int FindVoxelPosition(Vector3 pos) { return new Vector3Int(Mathf.FloorToInt(pos.x/voxelSize.x), Mathf.FloorToInt(pos.y/voxelSize.y), Mathf.FloorToInt(pos.z/voxelSize.z)); } public Vector3 GetMouseWorldSnappedPosition() => (Vector3)FindVoxelPosition(pointerPosition); public Vector3Int GetMouseVoxelPosition() => FindVoxelPosition(pointerPosition); public void CycleBuildingTemplate() { if(currentBuildingTemplate < buildingTemplates.Count - 1) currentBuildingTemplate += 1; else currentBuildingTemplate = 0; GenericEvents.Trigger("OnBuildingTemplateChanged"); //Debug.Log($"Changing current building template to {currentBuildingTemplate}"); } public List GetBuildingVoxelList(Vector3Int offset, int buildingTemplateId) { BuildingTemplate template = buildingTemplates[buildingTemplateId]; List positionList = new List(); for(int x = 0; x < template.size.x; x++) { for (int y = 0; y < template.size.y; y++) { for (int z = 0; z < template.size.z; z++) { Vector3Int pos = new Vector3Int(offset.x + x, offset.y + y, offset.z + z); positionList.Add(pos); //Debug.Log(pos); } } } //Debug.Log($"{positionList.Count} voxel positions found for building \"{buildingTemplates[buildingTemplateId].title}\""); return positionList; } } public enum VoxelBuildingTool { None, Build, Remove } }