public void QueueChunkUpdate(Vector3i chunkPos, bool lowPrioriity) { if (LoadedChunks.TryGetValue(chunkPos, out var chunk)) { QueueChunkUpdate(chunk, lowPrioriity); } }
private void SetChunkNeighborhood(TerrainChunk chunk) { TerrainChunk xUp; TerrainChunk xDown; TerrainChunk zUp; TerrainChunk zDown; LoadedChunks.TryGetValue(new Vector2i(chunk.Position.X + 1, chunk.Position.Z), out xUp); LoadedChunks.TryGetValue(new Vector2i(chunk.Position.X - 1, chunk.Position.Z), out xDown); LoadedChunks.TryGetValue(new Vector2i(chunk.Position.X, chunk.Position.Z + 1), out zUp); LoadedChunks.TryGetValue(new Vector2i(chunk.Position.X, chunk.Position.Z - 1), out zDown); if (xUp != null) { chunk.SetNeighbors(xUp, TerrainNeighbor.XUp); xUp.SetNeighbors(chunk, TerrainNeighbor.XDown); } if (xDown != null) { chunk.SetNeighbors(xDown, TerrainNeighbor.XDown); xDown.SetNeighbors(chunk, TerrainNeighbor.XUp); } if (zUp != null) { chunk.SetNeighbors(zUp, TerrainNeighbor.ZUp); zUp.SetNeighbors(chunk, TerrainNeighbor.ZDown); } if (zDown != null) { chunk.SetNeighbors(zDown, TerrainNeighbor.ZDown); zDown.SetNeighbors(chunk, TerrainNeighbor.ZUp); } }
/// <summary> /// Get the relative Chunk from a world position. /// </summary> /// <param name="chunkPosition"></param> /// <param name="worldPosition"></param> /// <returns></returns> /// <exception cref="ArgumentOutOfRangeException"></exception> public Chunk GetRelativeChunk(Direction chunkPosition, Vector3Int worldPosition) { switch (chunkPosition) { case Direction.Left: return(LoadedChunks.TryGetValue(worldPosition + new Vector3Int(-8, 0, 0), out var leftChunk) ? leftChunk : null); case Direction.Right: return(LoadedChunks.TryGetValue(worldPosition + new Vector3Int(8, 0, 0), out var rightChunk) ? rightChunk : null); case Direction.Bottom: return(LoadedChunks.TryGetValue(worldPosition + new Vector3Int(0, -4, 0), out var bottomChunk) ? bottomChunk : null); case Direction.Top: return(LoadedChunks.TryGetValue(worldPosition + new Vector3Int(0, 4, 0), out var topChunk) ? topChunk : null); case Direction.Back: return(LoadedChunks.TryGetValue(worldPosition + new Vector3Int(0, 0, -8), out var backChunk) ? backChunk : null); case Direction.Front: return(LoadedChunks.TryGetValue(worldPosition + new Vector3Int(0, 0, 8), out var frontChunk) ? frontChunk : null); default: throw new ArgumentOutOfRangeException(nameof(chunkPosition), chunkPosition, null); } }
public override BlockData GetBlockData(int x, int y, int z) { var chunkInWorld = ChunkInWorld(x, y, z); var blockInChunk = BlockInChunk(x, y, z); return(LoadedChunks.TryGetValue(chunkInWorld, out Chunk chunk) ? chunk.GetBlockData(blockInChunk) : null); }
public Chunk GetChunk(Vector2Int chunkPosition) { Chunk result; LoadedChunks.TryGetValue(chunkPosition, out result); return(result); }
public override LightLevel GetBlockLightLevel(int x, int y, int z) { var chunkInWorld = ChunkInWorld(x, y, z); var blockInChunk = BlockInChunk(x, y, z); return(LoadedChunks.TryGetValue(chunkInWorld, out Chunk chunk) ? chunk.GetLightLevel(blockInChunk) : LightLevel.Zero); }
public override Block GetBlock(int x, int y, int z) { var chunkInWorld = ChunkInWorld(x, y, z); var blockInChunk = BlockInChunk(x, y, z); return(LoadedChunks.TryGetValue(chunkInWorld, out Chunk chunk) ? GameRegistry.GetBlock(chunk.GetBlock(blockInChunk)) : BlockRegistry.BlockAir); }
public Tile this[Vector2Int worldPosition] { get { Vector2Int chunkPosition = Chunk.CalculateResidingChunk(worldPosition); Chunk chunk; if (LoadedChunks.TryGetValue(chunkPosition, out chunk)) { return(chunk.GetTile(Tile.TilePositionInRelationToChunk(worldPosition))); } return(null); } }
public List <Chunk> GetChunks(List <Vector2Int> chunkPositions) { List <Chunk> result = new List <Chunk>(); for (int i = chunkPositions.Count - 1; i >= 0; --i) { Chunk value; if (LoadedChunks.TryGetValue(chunkPositions[i], out value)) { result.Add(value); chunkPositions.RemoveAt(i); } } return(result); }
/// <summary> /// Checks the <see cref="LoadedChunks"/> dictionary for the relevent chunk position /// Returns null if not present /// </summary> /// <param name="chunk">The coordinate of the chunk we wish to find</param> /// <returns></returns> public LoadedChunk2 GetLoadedChunk(Vec2i chunk) { LoadedChunk2 lChunk; if (InSubworld) { if (SubworldChunks.TryGetValue(chunk, out lChunk)) { return(lChunk); } } if (LoadedChunks.TryGetValue(chunk, out lChunk)) { return(lChunk); } return(null); }
public override void SetBlockData(int x, int y, int z, BlockData data) { var chunkInWorld = ChunkInWorld(x, y, z); var blockInChunk = BlockInChunk(x, y, z); if (LoadedChunks.TryGetValue(chunkInWorld, out var chunk)) { chunk.SetBlockData(blockInChunk, data); } var pos = new Vector3i(x, y, z); lock (_queuedLightUpdates) { if (!_queuedLightUpdates.Contains(pos)) { _queuedLightUpdates.Enqueue(pos); } } if (blockInChunk.X == 0) { QueueChunkUpdate(chunkInWorld + new Vector3i(-1, 0, 0), false); } else if (blockInChunk.X == Chunk.Size - 1) { QueueChunkUpdate(chunkInWorld + new Vector3i(+1, 0, 0), false); } if (blockInChunk.Y == 0) { QueueChunkUpdate(chunkInWorld + new Vector3i(0, -1, 0), false); } else if (blockInChunk.Y == Chunk.Size - 1) { QueueChunkUpdate(chunkInWorld + new Vector3i(0, +1, 0), false); } if (blockInChunk.Z == 0) { QueueChunkUpdate(chunkInWorld + new Vector3i(0, 0, -1), false); } else if (blockInChunk.Z == Chunk.Size - 1) { QueueChunkUpdate(chunkInWorld + new Vector3i(0, 0, +1), false); } QueueChunkUpdate(chunk, false); }
public override void SetBlockLightLevel(int x, int y, int z, LightLevel lightLevel) { var chunkInWorld = ChunkInWorld(x, y, z); var blockInChunk = BlockInChunk(x, y, z); if (!LoadedChunks.TryGetValue(chunkInWorld, out var chunk)) { return; } chunk.SetLightLevel(blockInChunk, lightLevel); if (blockInChunk.X == 0) { QueueChunkUpdate(chunkInWorld + new Vector3i(-1, 0, 0), false); } else if (blockInChunk.X == Chunk.Size - 1) { QueueChunkUpdate(chunkInWorld + new Vector3i(+1, 0, 0), false); } if (blockInChunk.Y == 0) { QueueChunkUpdate(chunkInWorld + new Vector3i(0, -1, 0), false); } else if (blockInChunk.Y == Chunk.Size - 1) { QueueChunkUpdate(chunkInWorld + new Vector3i(0, +1, 0), false); } if (blockInChunk.Z == 0) { QueueChunkUpdate(chunkInWorld + new Vector3i(0, 0, -1), false); } else if (blockInChunk.Z == Chunk.Size - 1) { QueueChunkUpdate(chunkInWorld + new Vector3i(0, 0, +1), false); } QueueChunkUpdate(chunk, false); }
public override void SetBlock(int x, int y, int z, Block block, bool update, bool lowPriority) { var chunkInWorld = ChunkInWorld(x, y, z); var blockInChunk = BlockInChunk(x, y, z); if (LoadedChunks.TryGetValue(chunkInWorld, out var chunk)) { if (chunk.GetBlock(blockInChunk) == block.Id) { return; } chunk.SetBlock(blockInChunk, block.Id); } else { chunk = new Chunk(this, chunkInWorld); chunk.SetBlock(blockInChunk, block.Id); lock (LoadedChunks) { LoadedChunks.Add(chunkInWorld, chunk); } } if (!update) { return; } var pos = new Vector3i(x, y, z); lock (_queuedLightUpdates) { if (!_queuedLightUpdates.Contains(pos)) { _queuedLightUpdates.Enqueue(pos); } } if (blockInChunk.X == 0) { QueueChunkUpdate(chunkInWorld + new Vector3i(-1, 0, 0), lowPriority); } else if (blockInChunk.X == Chunk.Size - 1) { QueueChunkUpdate(chunkInWorld + new Vector3i(+1, 0, 0), lowPriority); } if (blockInChunk.Y == 0) { QueueChunkUpdate(chunkInWorld + new Vector3i(0, -1, 0), lowPriority); } else if (blockInChunk.Y == Chunk.Size - 1) { QueueChunkUpdate(chunkInWorld + new Vector3i(0, +1, 0), lowPriority); } if (blockInChunk.Z == 0) { QueueChunkUpdate(chunkInWorld + new Vector3i(0, 0, -1), lowPriority); } else if (blockInChunk.Z == Chunk.Size - 1) { QueueChunkUpdate(chunkInWorld + new Vector3i(0, 0, +1), lowPriority); } QueueChunkUpdate(chunk, lowPriority); }
private void LoadThread() { var chunksWaitingForNeighbours = new HashSet <Vector3i>(); while (!_unloaded) { //Remove chunks waiting that have been unloaded var chunksToRemove = chunksWaitingForNeighbours.Where( chunkPos => !_populatedChunks.Contains(chunkPos) && !_chunksReadyToAdd.ContainsKey(chunkPos) || _populatedChunks.Contains(chunkPos) && !LoadedChunks.ContainsKey(chunkPos)).ToList(); chunksToRemove.ForEach(chunkPos => chunksWaitingForNeighbours.Remove(chunkPos)); //Update chunks waiting for neighbours var chunksToUpdate = chunksWaitingForNeighbours.Where( chunkPos => BlockFaceHelper.Faces.All( face => _populatedChunks.Contains(chunkPos + face.GetNormali()))) .ToList(); foreach (var chunkPos in chunksToUpdate) { QueueChunkUpdate(chunkPos, true); chunksWaitingForNeighbours.Remove(chunkPos); } var playerChunksLists = new List <List <Vector3i> >(); foreach (var playerEntity in PlayerEntities) { var playerChunksToLoad = new List <Vector3i>(); var playerChunk = ChunkInWorld(playerEntity.Position.ToVector3i()); //Load 7x7x7 around player for (var x = -3; x <= 3; x++) { for (var y = -3; y <= 3; y++) { for (var z = -3; z <= 3; z++) { var chunkPos = playerChunk + new Vector3i(x, y, z); if (playerChunksToLoad.Contains(chunkPos)) { continue; } if (_populatedChunks.Contains(chunkPos) || _chunksReadyToAdd.ContainsKey(chunkPos)) { //Reset chunk time so it will not be unloaded if (LoadedChunks.TryGetValue(chunkPos, out var chunk)) { chunk.Time = DateTime.Now; } continue; } playerChunksToLoad.Add(chunkPos); } } } //Load 61x3x61 terrain if overworld //heightmap(x*Chunk.Size + Chunk.Size/2, z*Chunk.Size + Chunk.Size/2) var height = 0 + Chunk.Size / 2; var heightMapChunkY = ChunkInWorld(0, height, 0).Y; for (var x = -30; x <= 30; x++) { for (var y = -1; y <= 1; y++) { for (var z = -30; z <= 30; z++) { if (x <= 3 && x >= -3 && y <= 3 && y >= -3 && z <= 3 && z >= -3) { continue; } var chunkPos = new Vector3i(playerChunk.X + x, heightMapChunkY + y, playerChunk.Z + z); if (_populatedChunks.Contains(chunkPos) || _chunksReadyToAdd.ContainsKey(chunkPos)) { //Reset chunk time so it will not be unloaded if (LoadedChunks.TryGetValue(chunkPos, out var chunk)) { chunk.Time = DateTime.Now; } continue; } playerChunksToLoad.Add(chunkPos); } } } playerChunksToLoad.Sort( (v0, v1) => (int)(v0.ToVector3() - playerChunk.ToVector3()).LengthSquared - (int)(v1.ToVector3() - playerChunk.ToVector3()).LengthSquared); //Cap player chunk load tasks to 16 if (playerChunksToLoad.Count > 16) { playerChunksToLoad.RemoveRange(16, playerChunksToLoad.Count - 16); } playerChunksLists.Add(playerChunksToLoad); } var merged = ExtensionHelper.ZipMerge(playerChunksLists.ToArray()); foreach (var chunkPos in merged) { var cachedChunk = LoadChunk(chunkPos); if (cachedChunk.IsEmpty) { //Empty chunks dont need to be added to LoadedChunks lock (_populatedChunks) { _populatedChunks.Add(chunkPos); } } else { lock (_chunksReadyToAdd) { _chunksReadyToAdd.Add(chunkPos, cachedChunk); } chunksWaitingForNeighbours.Add(chunkPos); } } Thread.Sleep(10); } }
public override void Update() { if (_unloaded) { return; } //Update entities foreach (var playerEntity in PlayerEntities) { playerEntity.Update(); } foreach (var entity in Entities) { entity.Update(); } lock (_chunksReadyToRemove) { while (_chunksReadyToRemove.Count > 0) { var chunkPos = _chunksReadyToRemove.First(); if (LoadedChunks.TryGetValue(chunkPos, out var chunk)) { lock (LoadedChunks) { LoadedChunks.Remove(chunkPos); } _populatedChunks.Remove(chunkPos); chunk.Dispose(); } _chunksReadyToRemove.Remove(chunkPos); } } lock (_chunksReadyToAdd) { while (_chunksReadyToAdd.Count > 0) { var entry = _chunksReadyToAdd.First(); lock (LoadedChunks) { if (!LoadedChunks.ContainsKey(entry.Key)) { LoadedChunks.Add(entry.Key, new Chunk(entry.Value)); } else { Logger.Error("Chunk has already been loaded! " + entry.Key); } } _populatedChunks.Add(entry.Key); _chunksReadyToAdd.Remove(entry.Key); } } while (_chunksReadyToUploadHp.Count > 0) { lock (_chunksReadyToUploadHp) { _chunksReadyToUploadHp.Dequeue().Upload(); } } while (_chunksReadyToUploadLp.Count > 0) { lock (_chunksReadyToUploadLp) { _chunksReadyToUploadLp.Dequeue().Upload(); } } }