using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class World : MonoBehaviour { //basic [SerializeField] private Material material; [SerializeField] private GameObject playerPrefab; public int worldSize; private string name; private Dictionary otherPlayers = new Dictionary(); private Queue playersToCreate = new Queue(); private Queue playersPositionsToUpdate = new Queue(); private Queue playersRotationsToUpdate = new Queue(); private bool backToMenuRequest = false; //chunks private Chunk[,] chunks; private Queue chunksToUpdate = new Queue(); //blocks [SerializeField] private BlockData[] blockData; //network private Client client; private string ip; private int port; private void Start() { //get default information name = PlayerPrefs.GetString("userName"); ip = PlayerPrefs.GetString("serverIP"); port = int.Parse(PlayerPrefs.GetString("port")); client = new Client(ip, port, this, name); } //removes a player from the game world public void RemovePlayer(byte id) { playersPositionsToUpdate.Enqueue(new Player.PlayerPositionUpdateData(id, Vector3.zero, true)); } private void Update() { //update 1 chunk in list if (chunksToUpdate.Count > 0) { ChunkCoord chunk = chunksToUpdate.Dequeue(); chunks[chunk.x, chunk.z].Update(); } //create 1 player in list if (playersToCreate.Count > 0) { byte id = playersToCreate.Dequeue(); GameObject player = Instantiate(playerPrefab); player.transform.position = new Vector3((byte)player.transform.position.x, GetHeight((byte)player.transform.position.x, (byte)player.transform.position.z) + 2, (byte)player.transform.position.z); player.transform.SetParent(gameObject.transform); otherPlayers.Add(id, player); } //update 1 player position in list if (playersPositionsToUpdate.Count > 0) { Player.PlayerPositionUpdateData data = playersPositionsToUpdate.Dequeue(); otherPlayers.TryGetValue(data.id, out GameObject g); if (g != null) { g.transform.position = data.position; if (data.destroy) { Destroy(g); otherPlayers.Remove(data.id); } } } //update 1 player rotation in list if (playersRotationsToUpdate.Count > 0) { Player.PlayerRotationsUpdateData data = playersRotationsToUpdate.Dequeue(); otherPlayers.TryGetValue(data.id, out GameObject g); if (g != null) { g.transform.rotation = data.rotation; } } //go bock to menu if (backToMenuRequest) { SceneManager.LoadScene("Scenes/Login", LoadSceneMode.Single); } } //enqueue player position update to list public void UpdatePlayerPosition(Vector3 position, byte id) { playersPositionsToUpdate.Enqueue(new Player.PlayerPositionUpdateData(id, position, false)); } //enqueue player rotation update to list public void UpdatePlayerRotation(Quaternion rotation, byte id) { playersRotationsToUpdate.Enqueue(new Player.PlayerRotationsUpdateData(id, rotation)); } //enqueue player create data to list public void AddPlayer(byte id) { playersToCreate.Enqueue(id); } //creates the array for chunk objects public void CreateChunkArray() { chunks = new Chunk[worldSize, worldSize]; } //initialized a chunk public void InitChunk(int x, int z, byte[,,] blocks) { chunks[x, z] = new Chunk(material, new ChunkCoord(x, z), this, blocks); } //initialized the chunk objects public void CreateChunks() { for (int x = 0; x < worldSize; x++) { for (int z = 0; z < worldSize; z++) { chunks[x, z].Initialize(); chunks[x, z].gameObject.transform.SetParent(gameObject.transform); chunks[x, z].AddBlocks(); chunks[x, z].CreateMesh(); } } } //return the ID of a block public byte GetBlockID(Vector3 positionInWorld) { byte height = GetHeight((int)positionInWorld.x, (int)positionInWorld.z); //world pass if (positionInWorld.x < 0 || positionInWorld.y < 0 || positionInWorld.z < 0 || positionInWorld.x >= worldSize * Data.chunkWidth || positionInWorld.y > height || positionInWorld.z >= worldSize * Data.chunkWidth) { return 0; } //chunk pass if ((int)positionInWorld.y == height) { return 3; } if ((int)positionInWorld.y == 0) { return 1; } if ((int)positionInWorld.y > height - 3) { return 2; } if ((int)positionInWorld.y < height) { return 4; } return 0; } //returns if a block is on the position public bool CheckBlock(Vector3 positionInWorld) { if (positionInWorld.x < -1 || positionInWorld.z < -1 || positionInWorld.x > worldSize * Data.chunkWidth || positionInWorld.z > worldSize * Data.chunkWidth) { return false; } if (positionInWorld.x < 0 || positionInWorld.y < 0 || positionInWorld.z < 0 || positionInWorld.x >= worldSize * Data.chunkWidth || positionInWorld.y >= Data.chunkHeight || positionInWorld.z >= worldSize * Data.chunkWidth) { return true; } ChunkCoord chunk = new ChunkCoord((int)(positionInWorld.x / Data.chunkWidth), (int)(positionInWorld.z / Data.chunkWidth)); int xInChunk = (int)(positionInWorld.x - chunk.x * Data.chunkWidth); int yInChunk = (int)positionInWorld.y; int zInChunk = (int)(positionInWorld.z - chunk.z * Data.chunkWidth); if (chunks[chunk.x, chunk.z] != null) { if (chunks[chunk.x, chunk.z].blocks[xInChunk, yInChunk, zInChunk] == 0) { return false; } } return true; } //return textures array of a block public byte[] GetTextures(byte blockID) { return blockData[blockID].textures; } //get the height public byte GetHeight(int x, int z) { int xChunk = x / Data.chunkWidth; int zChunk = z / Data.chunkWidth; int xInChunk = x - (xChunk * Data.chunkWidth); int zInChunk = z - (zChunk * Data.chunkWidth); Chunk c = chunks[xChunk, zChunk]; for (int y = 0; y < Data.chunkHeight; y++) { if (c.blocks[xInChunk, y, zInChunk] == 0) { return (byte)(y - 1); } } return 250; } //edit a block in local chunk storage public void EditBlock(ChunkCoord chunk, Vector3 positionInChunk, byte blockID) { byte xInChunk = (byte)(positionInChunk.x); byte yInChunk = (byte)positionInChunk.y; byte zInChunk = (byte)(positionInChunk.z); //edit block in chunk if (chunks[chunk.x, chunk.z].blocks[xInChunk, yInChunk, zInChunk] != 1) { chunks[chunk.x, chunk.z].Edit(xInChunk, yInChunk, zInChunk, blockID); chunksToUpdate.Enqueue(new ChunkCoord(chunk.x, chunk.z)); //update surrounding chunks if (chunk.x - 1 >= 0) { chunksToUpdate.Enqueue(new ChunkCoord(chunk.x - 1, chunk.z)); } if (chunk.x + 1 < worldSize) { chunksToUpdate.Enqueue(new ChunkCoord(chunk.x + 1, chunk.z)); } if (chunk.z - 1 >= 0) { chunksToUpdate.Enqueue(new ChunkCoord(chunk.x, chunk.z - 1)); } if (chunk.z + 1 < worldSize) { chunksToUpdate.Enqueue(new ChunkCoord(chunk.x, chunk.z + 1)); } } } private void OnApplicationQuit() { client.Disconnect(); } public void BackToMenu() { SceneManager.LoadScene("Scenes/Login", LoadSceneMode.Single); } public Client GetClient() { return client; } [Serializable] public class BlockData { public string name; public byte[] textures = new byte[6]; } }