using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Mirror; using Unity.AI.Navigation; using UnityEngine; using UnityEngine.Serialization; using Random = UnityEngine.Random; namespace Level.BuildModules { public class ProceduralPrefabs : NetworkBehaviour { public Room[] roomPrefabs; public Room startingRoom; public GameObject cubePrefab; private Room[,] _spawnedRooms; public List flattenSpawnedRooms = new(); 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 IEnumerator Start() { if(!isServer) yield break; _size = PlayerPrefs.GetInt("LevelSize"); _spawnedRooms = new Room[_size, _size]; _spawnedRooms[_startCellX, _startCellY] = startingRoom; networkManager = NetworkManager.singleton.GetComponent(); for (int i = 0; i < _size; i++) { if (_size > 200) { yield return new WaitForSecondsRealtime(0.1f); } yield return new WaitForSecondsRealtime(1f); PlaceOneRoom(); } yield return new WaitForSecondsRealtime(1f); print("<---Rooms Spawned--->"); flattenSpawnedRooms[0].GetComponent().BuildNavMesh(); print("<---Surface builded--->"); networkManager.OnPlayerSpawned += OnPlayerSpawned; } private void OnPlayerSpawned() { print("OnPlayerSpawned"); if (enemyList.Count == networkManager.maxMonsters) return; if (networkManager.players.Count == networkManager.maxConnections) { MonsterSpawn(); CubeSpawn(); } } private void CubeSpawn() { Vector3 pos = _enemySpawnPoses[Random.Range(0, _enemySpawnPoses.Count)]; GameObject go = Instantiate(cubePrefab, pos, Quaternion.identity); go.GetComponent().Original = true; NetworkServer.Spawn(go); enemyList.Add(go); print("<---Cube spawned--->"); } private void MonsterSpawn() { 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); } print("<---Monster spawned--->"); } 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; 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); 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; flattenSpawnedRooms.Add(newRoom); _enemySpawnPoses.Add(newRoom.transform.position); 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); room.Finish(); 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.DisableDoor(RoomDoor.U); selectedRoom.DisableDoor(RoomDoor.D); break; case 2 : room.DisableDoor(RoomDoor.U2); selectedRoom.DisableDoor(RoomDoor.D2); break; case 3 : room.DisableDoor(RoomDoor.U3); selectedRoom.DisableDoor(RoomDoor.D3); break; } } else if (direction == Vector2Int.down) { switch (rand) { case 1 : room.DisableDoor(RoomDoor.D); selectedRoom.DisableDoor(RoomDoor.U); break; case 2 : room.DisableDoor(RoomDoor.D2); selectedRoom.DisableDoor(RoomDoor.U2); break; case 3 : room.DisableDoor(RoomDoor.D3); selectedRoom.DisableDoor(RoomDoor.U3); break; } } else if (direction == Vector2Int.right) { switch (rand) { case 1 : room.DisableDoor(RoomDoor.R); selectedRoom.DisableDoor(RoomDoor.L); break; case 2 : room.DisableDoor(RoomDoor.R2); selectedRoom.DisableDoor(RoomDoor.L2); break; case 3 : room.DisableDoor(RoomDoor.R3); selectedRoom.DisableDoor(RoomDoor.L3); break; } } else if (direction == Vector2Int.left) { switch (rand) { case 1 : room.DisableDoor(RoomDoor.L); selectedRoom.DisableDoor(RoomDoor.R); break; case 2 : room.DisableDoor(RoomDoor.L2); selectedRoom.DisableDoor(RoomDoor.R2); break; case 3 : room.DisableDoor(RoomDoor.L3); selectedRoom.DisableDoor(RoomDoor.R3); break; } } } } }