public static void ScatterNodes(Queue <Vector3i> nodes, bool generator) { while (nodes.Count > 0) { Vector3i pos = nodes.Dequeue(); Block block = Map.GetBlock(pos.x, pos.y, pos.z); int light = MapLight.GetSunlight(pos.x, pos.y, pos.z) - block.GetLightStep(); if (light <= LightUtils.MinLight) { continue; } for (int i = 0; i < 6; i++) { Vector3i nextPos = pos + Vector3i.directions[i]; if (Map.InBounds(nextPos.x, nextPos.y, nextPos.z)) { block = Map.GetBlock(nextPos.x, nextPos.y, nextPos.z); if (block.IsTransparent() && SetMax((byte)light, nextPos.x, nextPos.y, nextPos.z)) { nodes.Enqueue(nextPos); if (!generator) { Map.FlagChunkForUpdate(nextPos.x, nextPos.y, nextPos.z); } } } } } }
// Scatters the initial light throughout the map. public static void Scatter(int worldX, int worldZ, Queue <Vector3i> sunNodes, Queue <Vector3i> lightNodes) { for (int x = worldX; x < worldX + Chunk.Size; x++) { for (int z = worldZ; z < worldZ + Chunk.Size; z++) { int ray = MapLight.GetRay(x, z); int maxY = ComputeMaxY(x, z, ray); for (int y = ray; y <= maxY; y++) { if (y >= Map.Height) { continue; } sunNodes.Enqueue(new Vector3i(x, y, z)); byte light = Map.GetBlock(x, y, z).LightEmitted(); if (light > LightUtils.MinLight) { MapLight.SetLight(x, y, z, light); lightNodes.Enqueue(new Vector3i(x, y, z)); } } } } ScatterNodes(sunNodes, true); BlockLightEngine.ScatterNodes(lightNodes, true); }
public static Color32 GetBlockLight(Vector3i pos) { byte light = lightOutput[MapLight.GetLightSafe(pos.x, pos.y, pos.z)]; byte sun = lightOutput[MapLight.GetSunlightSafe(pos.x, pos.y, pos.z)]; return(new Color32(light, light, light, sun)); }
public static Color32 GetBlockLight(int x, int y, int z) { byte light = lightOutput[MapLight.GetLightSafe(x, y, z)]; byte sun = lightOutput[MapLight.GetSunlightSafe(x, y, z)]; return(new Color32(light, light, light, sun)); }
public static void SetBlocksAdvanced(List <BlockInstance> blocks, bool undo) { List <BlockInstance> prevBlocks = new List <BlockInstance>(); for (int i = 0; i < blocks.Count; i++) { BlockInstance blockInst = blocks[i]; int x = blockInst.x; int y = blockInst.y; int z = blockInst.z; if (!InBounds(x, y, z)) { continue; } if (!blockInst.block.CanPlace(Vector3i.zero, x, y, z)) { continue; } BlockInstance prevInst = new BlockInstance(GetBlock(x, y, z), x, y, z); if (blockInst.block.ID == BlockID.Air) { if (!prevInst.block.CanDelete()) { continue; } else { prevInst.block.OnDelete(x, y, z); } } else { blockInst.block.OnPlace(Vector3i.zero, x, y, z); } if (undo) { prevBlocks.Add(new BlockInstance(GetBlock(x, y, z), x, y, z)); } SetBlock(x, y, z, blocks[i].block); MapLight.RecomputeLighting(x, y, z); FlagChunkForUpdate(x, y, z); } UpdateMeshes(); if (undo) { UndoManager.RegisterAction(prevBlocks, blocks); } }
// Returns the highest point in the world between this column and each neighbor column. private static int ComputeMaxY(int x, int z, int ray) { ray = Mathf.Max(ray, MapLight.GetRaySafe(x - 1, z)); ray = Mathf.Max(ray, MapLight.GetRaySafe(x + 1, z)); ray = Mathf.Max(ray, MapLight.GetRaySafe(x, z - 1)); ray = Mathf.Max(ray, MapLight.GetRaySafe(x, z + 1)); return(ray); }
public static void Recompute(Vector3i pos, Queue <Vector3i> nodes) { int oldSunHeight = MapLight.GetRay(pos.x, pos.z); ComputeRayAtPosition(pos.x, pos.z); int newSunHeight = MapLight.GetRay(pos.x, pos.z); if (newSunHeight < oldSunHeight) { for (int ty = newSunHeight; ty <= oldSunHeight; ty++) { pos.y = ty; if (ty < Map.Height) { MapLight.SetSunlight(pos.x, pos.y, pos.z, LightUtils.MinLight); } nodes.Enqueue(pos); } ScatterNodes(nodes, false); return; } if (newSunHeight > oldSunHeight) { for (int ty = oldSunHeight; ty <= newSunHeight; ty++) { pos.y = ty; if (ty < Map.Height) { MapLight.SetSunlight(pos.x, pos.y, pos.z, LightUtils.MaxLight); } nodes.Enqueue(pos); } RemoveNodes(nodes); return; } if (newSunHeight == oldSunHeight) { if (Map.GetBlock(pos.x, pos.y, pos.z).IsTransparent()) { Update(pos, nodes); } else { Remove(pos, nodes); } } }
private static void RemoveNodes(Queue <Vector3i> nodes) { Queue <Vector3i> newLights = new Queue <Vector3i>(); while (nodes.Count > 0) { Vector3i pos = nodes.Dequeue(); if (pos.y < 0 || pos.y >= Map.Height) { continue; } int light = MapLight.GetLight(pos.x, pos.y, pos.z) - 1; MapLight.SetLight(pos.x, pos.y, pos.z, LightUtils.MinLight); if (light <= LightUtils.MinLight) { continue; } for (int i = 0; i < 6; i++) { Vector3i nextPos = pos + Vector3i.directions[i]; if (Map.InBounds(nextPos.x, nextPos.z)) { Block block = Map.GetBlock(nextPos.x, nextPos.y, nextPos.z); if (block.IsTransparent()) { if (MapLight.GetLight(nextPos.x, nextPos.y, nextPos.z) <= light) { nodes.Enqueue(nextPos); } else { newLights.Enqueue(nextPos); } } if (block.LightEmitted() > LightUtils.MinLight) { newLights.Enqueue(nextPos); } Map.FlagChunkForUpdate(nextPos.x, nextPos.y, nextPos.z); } } } ScatterNodes(newLights, false); }
public static bool SetMax(byte light, int x, int y, int z) { byte oldLight = MapLight.GetLight(x, y, z); if (oldLight < light) { MapLight.SetLight(x, y, z, light); return(true); } return(false); }
private void QueueBlocksForUnflowing() { for (int i = 0; i < blocksToUnflow.Count; i++) { BlockInstance b = blocksToUnflow[i]; MapLight.RecomputeLighting(b.x, b.y, b.z); Map.FlagChunkForUpdate(b.x, b.y, b.z); unflowQueue.Enqueue(blocksToUnflow[i]); } Map.UpdateMeshes(); blocksToUnflow = new List <BlockInstance>(128); }
private static bool SetMax(byte light, int x, int y, int z) { if (y >= MapLight.GetRay(x, z)) { return(false); } byte oldLight = MapLight.GetSunlight(x, y, z); if (oldLight < light) { MapLight.SetSunlight(x, y, z, light); return(true); } return(false); }
public static void Recompute(Vector3i pos, Queue <Vector3i> nodes) { byte oldLight = MapLight.GetLight(pos.x, pos.y, pos.z); byte light = Map.GetBlock(pos.x, pos.y, pos.z).LightEmitted(); if (oldLight > light) { Remove(pos, nodes); } if (light > LightUtils.MinLight) { MapLight.SetLight(pos.x, pos.y, pos.z, light); Scatter(pos, nodes); } else { Update(pos, nodes); } }
protected Vector3 TryFindLand(Vector3i center) { Vector3i?land = null; for (int x = center.x - 20; x <= center.x + 20; x++) { for (int z = center.z - 20; z <= center.z + 20; z++) { int height = MapLight.GetRaySafe(x, z); Block surface = Map.GetBlockSafe(x, height - 1, z); if (!surface.IsFluid()) { Vector3i current = new Vector3i(x, height, z); if (!land.HasValue) { land = current; } else { int dis = center.DistanceSquared(current); int oldDis = center.DistanceSquared(land.Value); if (dis < oldDis) { land = current; } } } } } if (land.HasValue) { return(land.Value.ToVector3()); } return(new Vector3(center.x, MapLight.GetRay(center.x, center.z), center.z)); }
public static void SetBlockAdvanced(int x, int y, int z, Block block, Vector3i normal, bool undo) { if (InBounds(x, y, z)) { if (!block.CanPlace(normal, x, y, z)) { return; } BlockInstance prevInst = new BlockInstance(GetBlock(x, y, z), x, y, z); BlockInstance newBlock = new BlockInstance(block, x, y, z); if (block.ID == BlockID.Air) { if (!prevInst.block.CanDelete()) { return; } prevInst.block.OnDelete(x, y, z); } else { block.OnPlace(normal, x, y, z); } if (undo) { UndoManager.RegisterAction(prevInst, newBlock); } SetBlock(x, y, z, block); MapLight.RecomputeLighting(x, y, z); FlagChunkForUpdate(x, y, z); UpdateMeshes(); } }
public static void BeginPlay() { MapLight.GenerateAllLight(); }
private static void Remove(Vector3i pos, Queue <Vector3i> nodes) { MapLight.SetLight(pos.x, pos.y, pos.z, LightUtils.MaxLight); nodes.Enqueue(pos); RemoveNodes(nodes); }
private static void ComputeRayAtPosition(int x, int z) { int surface = Map.GetSurface(x, z); MapLight.SetRay(x, z, (byte)(surface + 1)); }