using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Mirror; using UnityEngine; using UnityEngine.Serialization; using Random = UnityEngine.Random; namespace Level.BuildModules { public class ProceduralPrefabs : NetworkBehaviour { [FormerlySerializedAs("roomPrefabs")] public Room[] roomPrefabs; [FormerlySerializedAs("StartingRoom")] public Room startingRoom; private Room[,] _spawnedRooms; private int _size; private int _startCellX = 0; private int _startCellY = 0; private CustomNetworkManager networkManager; public GameObject enemyPrefab; private List _enemySpawnPoses = new(); public List enemyList = new(); private void Start() { if(!isServer) return; _size = PlayerPrefs.GetInt("LevelSize"); _spawnedRooms = new Room[_size, _size]; _spawnedRooms[_startCellX, _startCellY] = startingRoom; networkManager = NetworkManager.singleton.GetComponent(); for (int i = 0; i < _size; i++) { // yield return new WaitForSecondsRealtime(0.1f); PlaceOneRoom(); } if (enemyList.Count == networkManager.maxMonsters) return; if (networkManager.players.Count == networkManager.maxConnections) { for (int i = 0; i < networkManager.maxMonsters; i++) { Vector3 pos = _enemySpawnPoses[Random.Range(0, _enemySpawnPoses.Count)]; GameObject go = Instantiate(enemyPrefab, pos, Quaternion.identity); NetworkServer.Spawn(go); enemyList.Add(go); } } } private void PlaceOneRoom() { HashSet vacantPlaces = new HashSet(); for (int x = 0; x < _spawnedRooms.GetLength(0); x++) { for (int y = 0; y < _spawnedRooms.GetLength(1); y++) { if (_spawnedRooms[x, y] == null) continue; int maxX = _spawnedRooms.GetLength(0) - 1; int maxY = _spawnedRooms.GetLength(1) - 1; AddVacantPlaceIfValid(x - 1, y, vacantPlaces); AddVacantPlaceIfValid(x, y - 1, vacantPlaces); AddVacantPlaceIfValid(x + 1, y, vacantPlaces); AddVacantPlaceIfValid(x, y + 1, vacantPlaces); } } Room newRoom = Instantiate(roomPrefabs[Random.Range(0, roomPrefabs.Length)]); NetworkServer.Spawn(newRoom.gameObject); _enemySpawnPoses.Add(newRoom.transform.position); int limit = 500; while (limit-- > 0) { Vector2Int position = vacantPlaces.ElementAt(Random.Range(0, vacantPlaces.Count)); // newRoom.RotateRandomly(); if (ConnectToSomething(newRoom, position)) { newRoom.transform.position = new Vector3(position.x - _startCellX, 0, position.y - _startCellY) * newRoom.roomSize; _spawnedRooms[position.x, position.y] = newRoom; return; } } NetworkServer.Destroy(newRoom.gameObject); Destroy(newRoom.gameObject); } private void AddVacantPlaceIfValid(int x, int y, HashSet vacantPlaces) { if (x >= 0 && x < _spawnedRooms.GetLength(0) && y >= 0 && y < _spawnedRooms.GetLength(1) && _spawnedRooms[x, y] == null) { vacantPlaces.Add(new Vector2Int(x, y)); } } private bool ConnectToSomething(Room room, Vector2Int p) { List neighbours = new List(); AddNeighbourIfValid(room.DoorU, p.x, p.y + 1, Vector2Int.up, neighbours); AddNeighbourIfValid(room.DoorD, p.x, p.y - 1, Vector2Int.down, neighbours); AddNeighbourIfValid(room.DoorR, p.x + 1, p.y, Vector2Int.right, neighbours); AddNeighbourIfValid(room.DoorL, p.x - 1, p.y, Vector2Int.left, neighbours); AddNeighbourIfValid(room.DoorU2, p.x, p.y + 1, Vector2Int.up, neighbours); AddNeighbourIfValid(room.DoorD2, p.x, p.y - 1, Vector2Int.down, neighbours); AddNeighbourIfValid(room.DoorR2, p.x + 1, p.y, Vector2Int.right, neighbours); AddNeighbourIfValid(room.DoorL2, p.x - 1, p.y, Vector2Int.left, neighbours); AddNeighbourIfValid(room.DoorU3, p.x, p.y + 1, Vector2Int.up, neighbours); AddNeighbourIfValid(room.DoorD3, p.x, p.y - 1, Vector2Int.down, neighbours); AddNeighbourIfValid(room.DoorR3, p.x + 1, p.y, Vector2Int.right, neighbours); AddNeighbourIfValid(room.DoorL3, p.x - 1, p.y, Vector2Int.left, neighbours); if (neighbours.Count == 0) return false; Vector2Int selectedDirection = neighbours[Random.Range(0, neighbours.Count)]; Room selectedRoom = _spawnedRooms[p.x + selectedDirection.x, p.y + selectedDirection.y]; DisableDoors(room, selectedRoom, selectedDirection); return true; } private void AddNeighbourIfValid(GameObject door, int x, int y, Vector2Int direction, List neighbours) { if (door != null && x >= 0 && x <= _spawnedRooms.GetLength(0) - 1 && y >= 0 && y <= _spawnedRooms.GetLength(1) - 1 && _spawnedRooms[x, y] != null) { neighbours.Add(direction); } } private void DisableDoors(Room room, Room selectedRoom, Vector2Int direction) { int rand = Random.Range(1, 4); if (direction == Vector2Int.up) { switch (rand) { case 1 : room.DoorU.SetActive(false); selectedRoom.DoorD.SetActive(false); break; case 2 : room.DoorU2.SetActive(false); selectedRoom.DoorD2.SetActive(false); break; case 3 : room.DoorU3.SetActive(false); selectedRoom.DoorD3.SetActive(false); break; } } else if (direction == Vector2Int.down) { switch (rand) { case 1 : room.DoorD.SetActive(false); selectedRoom.DoorU.SetActive(false); break; case 2 : room.DoorD2.SetActive(false); selectedRoom.DoorU2.SetActive(false); break; case 3 : room.DoorD3.SetActive(false); selectedRoom.DoorU3.SetActive(false); break; } } else if (direction == Vector2Int.right) { switch (rand) { case 1 : room.DoorR.SetActive(false); selectedRoom.DoorL.SetActive(false); break; case 2 : room.DoorR2.SetActive(false); selectedRoom.DoorL2.SetActive(false); break; case 3 : room.DoorR3.SetActive(false); selectedRoom.DoorL3.SetActive(false); break; } } else if (direction == Vector2Int.left) { switch (rand) { case 1 : room.DoorL.SetActive(false); selectedRoom.DoorR.SetActive(false); break; case 2 : room.DoorL2.SetActive(false); selectedRoom.DoorR2.SetActive(false); break; case 3 : room.DoorL3.SetActive(false); selectedRoom.DoorR3.SetActive(false); break; } } } } }