private static void InvalidateVoxel( VoxelChunk Chunk, GlobalVoxelCoordinate Coordinate, int Y) { Chunk.InvalidateSlice(Y); var localCoordinate = Coordinate.GetLocalVoxelCoordinate(); // Invalidate slice cache for neighbor chunks. if (localCoordinate.X == 0) { InvalidateNeighborSlice(Chunk.Manager.ChunkData, Chunk.ID, new Point3(-1, 0, 0), Y); if (localCoordinate.Z == 0) { InvalidateNeighborSlice(Chunk.Manager.ChunkData, Chunk.ID, new Point3(-1, 0, -1), Y); } if (localCoordinate.Z == VoxelConstants.ChunkSizeZ - 1) { InvalidateNeighborSlice(Chunk.Manager.ChunkData, Chunk.ID, new Point3(-1, 0, 1), Y); } } if (localCoordinate.X == VoxelConstants.ChunkSizeX - 1) { InvalidateNeighborSlice(Chunk.Manager.ChunkData, Chunk.ID, new Point3(1, 0, 0), Y); if (localCoordinate.Z == 0) { InvalidateNeighborSlice(Chunk.Manager.ChunkData, Chunk.ID, new Point3(1, 0, -1), Y); } if (localCoordinate.Z == VoxelConstants.ChunkSizeZ - 1) { InvalidateNeighborSlice(Chunk.Manager.ChunkData, Chunk.ID, new Point3(1, 0, 1), Y); } } if (localCoordinate.Z == 0) { InvalidateNeighborSlice(Chunk.Manager.ChunkData, Chunk.ID, new Point3(0, 0, -1), Y); } if (localCoordinate.Z == VoxelConstants.ChunkSizeZ - 1) { InvalidateNeighborSlice(Chunk.Manager.ChunkData, Chunk.ID, new Point3(0, 0, 1), Y); } }
private void OnTypeSet(VoxelType NewType) { // Changing a voxel is actually a relatively rare event, so we can afford to do a bit of // bookkeeping here. var previous = _cache_Chunk.Data.Types[_cache_Index]; var blockDestroyed = false; // Change actual data _cache_Chunk.Data.Types[_cache_Index] = (byte)NewType.ID; _cache_Chunk.Data.Health[_cache_Index] = (byte)NewType.StartingHealth; // Changing the voxel type clears grass. _cache_Chunk.Data.GrassType[_cache_Index] = 0; // Did we go from empty to filled or vice versa? Update filled counter. if (previous == 0 && NewType.ID != 0) { _cache_Chunk.Data.VoxelsPresentInSlice[Coordinate.Y] += 1; } else if (previous != 0 && NewType.ID == 0) { blockDestroyed = true; _cache_Chunk.Data.VoxelsPresentInSlice[Coordinate.Y] -= 1; } if (Coordinate.Y < VoxelConstants.ChunkSizeY - 1) { InvalidateVoxel(_cache_Chunk, Coordinate, Coordinate.Y + 1); } InvalidateVoxel(_cache_Chunk, Coordinate, Coordinate.Y); // Propogate sunlight (or lack thereof) downwards. if (Coordinate.Y > 0) { var localCoordinate = Coordinate.GetLocalVoxelCoordinate(); var Y = localCoordinate.Y - 1; var sunColor = (NewType.ID == 0 || NewType.IsTransparent) ? this.SunColor : 0; var below = VoxelHandle.InvalidHandle; while (Y >= 0) { below = new VoxelHandle(Chunk, new LocalVoxelCoordinate(localCoordinate.X, Y, localCoordinate.Z)); below.SunColor = sunColor; InvalidateVoxel(Chunk, new GlobalVoxelCoordinate(Coordinate.X, Y, Coordinate.Z), Y); if (!below.IsEmpty && !below.Type.IsTransparent) { break; } Y -= 1; } } if (blockDestroyed) { // Invoke old voxel listener. _cache_Chunk.NotifyDestroyed(Coordinate.GetLocalVoxelCoordinate()); // Reveal! VoxelHelpers.RadiusReveal(_cache_Chunk.Manager.ChunkData, this, 10); } // Invoke new voxel listener. _cache_Chunk.Manager.NotifyChangedVoxel(new VoxelChangeEvent { Type = VoxelChangeEventType.VoxelTypeChanged, Voxel = this, OriginalVoxelType = previous, NewVoxelType = NewType.ID }); }