private void NetChunkLoadedForClient(object[] args) { // Called on server when finished loading a chunk from file, to send to a player. string data = (string)args[0]; int chunkX = (int)args[1]; int chunkY = (int)args[2]; GameObject player = (GameObject)args[3]; int index = GetChunkIndex(chunkX, chunkY); if (AnyPendingOperationsFor(index)) { // Merge the loaded data with any pending operations. string merged = ChunkIO.Merge(data, PendingOperations[index], ChunkSize, true); // Compress again using RLE. float eff; string compressed = ChunkIO.RLE(merged, out eff); // Apply back to the data. data = compressed; } // Send to client. Msg_SendChunk msg = new Msg_SendChunk() { Data = data, ChunkX = chunkX, ChunkY = chunkY, Layer = Name }; // Send the data to the client using the server. NetworkServer.SendToClientOfPlayer(player, (short)MessageTypes.SEND_CHUNK_DATA, msg); }
public void RecievedNetChunk(string data, int chunkX, int chunkY) { // Called on only clients, when the network message for an incomming chunk has been recieved. // Make sure that the chunk is created first! int index = GetChunkIndex(chunkX, chunkY); if (!IsChunkLoading(index)) { return; } // First get a list of tiles, based on the data. BaseTile[][] tiles = ChunkIO.MakeChunk(data, ChunkSize, null, Use_RLE_In_Net); SetChunkTiles(tiles, chunkX * ChunkSize, chunkY * ChunkSize); // Mark as done loading. Chunk c = Chunks[index]; c.DoneLoading(); loading.Remove(index); }
public void ResolveAllPendingOperations() { // Saves all pending operations to file and clears the pending array. ChunkIO.MergeAllToFile(this.Map.World.RealityName, Name, ChunkSize, WidthInChunks, PendingOperations, OperationsResolved); // The operations will be cleared once they have been saved. }
[Server] // Intentional, called from Player.NetUtils. public void CmdRequestChunk(int x, int y, GameObject player) { // Called when a player requests a chunk from this server. // We need to make a compressed representation of the tiles and send it. // First, validation. if (player == null) { return; } if (!IsChunkInBounds(x, y)) { return; } // FOR NOW: // 1. See if chunk is loaded. if (IsChunkLoaded(x, y)) { // Great, send a copy of this. ChunkIO.GetChunkForNet_Loaded(player, Tiles, x, y, ChunkSize, NetChunkMade, Use_RLE_In_Net); } else { // Chunk is not loaded, what do I do? // Load a copy and send it? // But then how does the client make persistent changes to it? // Load it permamently in the server while the client is in it? // Allow the client to send a copy back once it is unloaded? // ---> Allow the client to make changes, record them on the server, and once the chunk is loaded, apply those changes. Also save those changes when X? // Decided solution: // Load from file. // Apply any 'changes' (explained later). // Send to client. // Client can then make any changes to that chunk, which are sent to the server, and stored as 'changes'. // Once the server really loads the chunk, the 'changes' are applied for real. // When a chunk is saved to file, all pending changes to that chunk are removed. // 1. Ensure it is saved to file... if (ChunkIO.IsChunkSaved(this.Map.World.RealityName, Name, x, y)) { // 2. Load from file. ChunkIO.GetChunkForNet_Unloaded(player, this.Map.World.RealityName, Name, x, y, ChunkSize, NetChunkLoadedForClient, NetChunkLoadError); } else { // 3. 'Generate' and save to file, then send normally. string contents = (16 * 16) + "|?"; string path = ChunkIO.GetPathForChunk(this.Map.World.RealityName, Name, x, y); File.WriteAllText(path, contents); // 4. Send it. ChunkIO.GetChunkForNet_Unloaded(player, this.Map.World.RealityName, Name, x, y, ChunkSize, NetChunkLoadedForClient, NetChunkLoadError); } } }
private void LoadChunk_Server(int x, int y) { if (!IsChunkInBounds(x, y)) { Debug.LogError("Chunk coordinate " + x + ", " + y + " (chunk space) is not in bounds."); return; } if (IsChunkLoaded(x, y)) { Debug.LogError("Chunk at " + x + ", " + y + " (chunk space) is already loaded, cannot load again!"); return; } int index = GetChunkIndex(x, y); if (IsChunkLoading(index)) { Debug.LogError("Chunk at " + x + ", " + y + " is already loading."); return; } // Flag as loading... loading.Add(index); // Instantiate object, TODO pool me. Chunk newChunk = Instantiate(ChunkPrefab.gameObject, transform).GetComponent <Chunk>(); // Create the chunk object. newChunk.Create(x, y, ChunkSize, ChunkSize, index); // Add to the chunks list. Chunks.Add(index, newChunk); // Check if is saved data... if (ChunkIO.IsChunkSaved(this.Map.World.RealityName, Name, x, y)) { // Load from disk. ChunkIO.LoadChunk(this.Map.World.RealityName, Name, x, y, ChunkSize, ChunkLoaded, ChunkLoadError); } else { // TODO add something, like generating this chunk. // Just leave a blank chunk, lol. // Mark as loaded, after 'generation'. Chunks[index].DoneLoading(); loading.Remove(index); } }
public void SaveAll() { // Saves everything about this layer to file, ready to shut down. // Async, for now. You could block until Saving == false to have sync behaviour. if (Saving) { Debug.LogError("Already saving! " + ChunksLeftToSave + " chunks to go!"); return; } Debug.Log("Saving layer '" + Name + "'"); Saving = true; saveStartTime = Time.time; // Debug. int count = 0; foreach (int index in PendingOperations.Keys) { if (!AnyPendingOperationsFor(index)) { continue; } count += PendingOperations[index].Count; } ChunksLeftToSave = 0; OperationsPendingInSave = count; // First save all loaded chunks. foreach (int index in Chunks.Keys) { Vector2Int pos = GetChunkCoordsFromIndex(index); ChunksLeftToSave++; ChunkIO.SaveChunk(this.Map.World.RealityName, Name, Tiles, pos.x, pos.y, ChunkSize, ChunkSavedEmpty); } // Done! }
private void UnloadChunk_Server(int index, Chunk chunk) { unloading.Add(index); ChunkIO.SaveChunk(this.Map.World.RealityName, Name, Tiles, chunk.X, chunk.Y, ChunkSize, ChunkSaved); }
public World(String save) { provider = new WorldProvider(this); generator = new WorldGenerator(1337, this); chunkIO = new ChunkIO(this, save); players = new Player[]{new Player(this)}; loadThread = new Thread(ChunkLoadLoop); updateThread = new Thread(ChunkUpdateLoop); loadThread.Start(); updateThread.Start(); }