private static void UpdateVoxelRamps(ChunkManager Chunks, VoxelHandle V) { if (!V.IsValid) { return; } if (V.IsEmpty || !V.IsVisible || V.Type == null || !V.Type.CanRamp) { V.RampType = RampType.None; return; } var vAbove = VoxelHelpers.GetVoxelAbove(V); if (vAbove.IsValid && !vAbove.IsEmpty) { V.RampType = RampType.None; return; } var compositeRamp = RampType.None; foreach (var vertex in TopVerticies) { // If there are no empty neighbors, no slope. if (!VoxelHelpers.EnumerateVertexNeighbors2D(V.Coordinate, vertex) .Any(n => { var handle = Chunks.CreateVoxelHandle(n); return(!handle.IsValid || handle.IsEmpty); })) { continue; } switch (vertex) { case VoxelVertex.FrontTopLeft: compositeRamp |= RampType.TopFrontLeft; break; case VoxelVertex.FrontTopRight: compositeRamp |= RampType.TopFrontRight; break; case VoxelVertex.BackTopLeft: compositeRamp |= RampType.TopBackLeft; break; case VoxelVertex.BackTopRight: compositeRamp |= RampType.TopBackRight; break; } } V.RampType = compositeRamp; }
public static float GetTotalWaterHeightCells(ChunkManager ChunkManager, VoxelHandle vox) { float tot = 0; var localVoxelCoordinate = vox.Coordinate.GetLocalVoxelCoordinate(); for (var y = vox.Coordinate.Y; y < ChunkManager.World.WorldSizeInVoxels.Y; y++) { var v = ChunkManager.CreateVoxelHandle(new GlobalVoxelCoordinate(vox.Coordinate.X, y, vox.Coordinate.Z)); tot += v.LiquidLevel / (float)WaterManager.maxWaterLevel; if (y > vox.Coordinate.Y && v.LiquidLevel == 0) { return(tot); } } return(tot); }
private static VertexColorInfo CalculateVertexLight(VoxelHandle Vox, VoxelVertex Vertex, ChunkManager chunks) { var neighborsEmpty = 0; var neighborsChecked = 0; var color = new VertexColorInfo(); color.DynamicColor = 0; color.SunColor = 0; foreach (var c in VoxelHelpers.EnumerateVertexNeighbors(Vox.Coordinate, Vertex)) { var v = chunks.CreateVoxelHandle(c); if (!v.IsValid) { continue; } color.SunColor += v.Sunlight ? 255 : 0; if (!v.IsEmpty || !v.IsExplored) { if (v.Type.EmitsLight) { color.DynamicColor = 255; } neighborsEmpty += 1; neighborsChecked += 1; } else { neighborsChecked += 1; } } var boost = GetAmbienceBoost(Vertex); var proportionHit = (float)neighborsEmpty / (float)neighborsChecked; color.AmbientColor = (int)Math.Min((1.0f - proportionHit) * 255.0f, 255); color.SunColor = (int)Math.Min((float)color.SunColor / (float)neighborsChecked + boost * 255.0f, 255); return(color); }
private void DiscreteUpdate(ChunkManager ChunkManager, VoxelChunk chunk) { for (var y = 0; y < VoxelConstants.ChunkSizeY; ++y) { // Apply 'liquid present' tracking in voxel data to skip entire slices. if (chunk.Data.LiquidPresent[y] == 0) { continue; } var layerOrder = SlicePermutations[MathFunctions.RandInt(0, SlicePermutations.Length)]; for (var i = 0; i < layerOrder.Length; ++i) { var x = layerOrder[i] % VoxelConstants.ChunkSizeX; var z = (layerOrder[i] >> VoxelConstants.XDivShift) % VoxelConstants.ChunkSizeZ; var currentVoxel = VoxelHandle.UnsafeCreateLocalHandle(chunk, new LocalVoxelCoordinate(x, y, z)); if (currentVoxel.TypeID != 0) { continue; } if (currentVoxel.LiquidType == LiquidType.None || currentVoxel.LiquidLevel < 1) { continue; } // Evaporate. if (currentVoxel.LiquidLevel <= EvaporationLevel && MathFunctions.RandEvent(0.01f)) { if (currentVoxel.LiquidType == LiquidType.Lava) { currentVoxel.Type = Library.GetVoxelType("Stone"); } NeedsMinimapUpdate = true; currentVoxel.QuickSetLiquid(LiquidType.None, 0); continue; } var voxBelow = ChunkManager.CreateVoxelHandle(new GlobalVoxelCoordinate(currentVoxel.Coordinate.X, currentVoxel.Coordinate.Y - 1, currentVoxel.Coordinate.Z)); if (voxBelow.IsValid && voxBelow.IsEmpty) { // Fall into the voxel below. // Special case: No liquid below, just drop down. if (voxBelow.LiquidType == LiquidType.None) { NeedsMinimapUpdate = true; CreateSplash(currentVoxel.Coordinate.ToVector3(), currentVoxel.LiquidType); voxBelow.QuickSetLiquid(currentVoxel.LiquidType, currentVoxel.LiquidLevel); currentVoxel.QuickSetLiquid(LiquidType.None, 0); continue; } var belowType = voxBelow.LiquidType; var aboveType = currentVoxel.LiquidType; var spaceLeftBelow = maxWaterLevel - voxBelow.LiquidLevel; if (spaceLeftBelow >= currentVoxel.LiquidLevel) { NeedsMinimapUpdate = true; CreateSplash(currentVoxel.Coordinate.ToVector3(), aboveType); voxBelow.LiquidLevel += currentVoxel.LiquidLevel; currentVoxel.QuickSetLiquid(LiquidType.None, 0); HandleLiquidInteraction(voxBelow, aboveType, belowType); continue; } if (spaceLeftBelow > 0) { NeedsMinimapUpdate = true; CreateSplash(currentVoxel.Coordinate.ToVector3(), aboveType); currentVoxel.LiquidLevel = (byte)(currentVoxel.LiquidLevel - maxWaterLevel + voxBelow.LiquidLevel); voxBelow.LiquidLevel = maxWaterLevel; HandleLiquidInteraction(voxBelow, aboveType, belowType); continue; } } else if (voxBelow.IsValid && currentVoxel.LiquidType == LiquidType.Lava && !voxBelow.IsEmpty && voxBelow.GrassType > 0) { voxBelow.GrassType = 0; } if (currentVoxel.LiquidLevel <= 1) { continue; } // Nothing left to do but spread. RollArray(NeighborPermutations[MathFunctions.RandInt(0, NeighborPermutations.Length)], NeighborScratch, MathFunctions.RandInt(0, 4)); for (var n = 0; n < NeighborScratch.Length; ++n) { var neighborOffset = VoxelHelpers.ManhattanNeighbors2D[NeighborScratch[n]]; var neighborVoxel = new VoxelHandle(Chunks, currentVoxel.Coordinate + neighborOffset); if (neighborVoxel.IsValid && neighborVoxel.IsEmpty) { if (neighborVoxel.LiquidLevel < currentVoxel.LiquidLevel) { NeedsMinimapUpdate = true; var amountToMove = (int)(currentVoxel.LiquidLevel * GetSpreadRate(currentVoxel.LiquidType)); if (neighborVoxel.LiquidLevel + amountToMove > maxWaterLevel) { amountToMove = maxWaterLevel - neighborVoxel.LiquidLevel; } if (amountToMove > 2) { CreateSplash(neighborVoxel.Coordinate.ToVector3(), currentVoxel.LiquidType); } var newWater = currentVoxel.LiquidLevel - amountToMove; var sourceType = currentVoxel.LiquidType; var destType = neighborVoxel.LiquidType; currentVoxel.QuickSetLiquid(newWater == 0 ? LiquidType.None : sourceType, (byte)newWater); neighborVoxel.QuickSetLiquid(destType == LiquidType.None ? sourceType : destType, (byte)(neighborVoxel.LiquidLevel + amountToMove)); HandleLiquidInteraction(neighborVoxel, sourceType, destType); break; } } } } } }
/// <summary> /// Snaps the supplied coordinate into valid world space. Returns nearest valid voxel to the point. /// </summary> /// <param name="chunks"></param> /// <param name="pos"></param> /// <returns></returns> public static VoxelHandle FindValidVoxelNear(ChunkManager chunks, Microsoft.Xna.Framework.Vector3 pos) { var clampedPos = MathFunctions.Clamp(pos, chunks.Bounds) + Microsoft.Xna.Framework.Vector3.Down * 0.05f; return(chunks.CreateVoxelHandle(GlobalVoxelCoordinate.FromVector3(clampedPos))); }