public void Run(World world) { if (Area.Size > 16 * 16 * 128) { Console.WriteLine("[LightingEngine] Tried to run a too big update"); return; } for (int x = Area.X1; x <= Area.X2; x++) { for (int z = Area.Z1; z <= Area.Z2; z++) { if (!world.IsLoaded(x, z)) continue; for (int y = Area.Y1; y <= Area.Y2; y++) { int oldLight = world.GetLight(Type, x, y, z); int newLight = 0; int blockType = world.GetBlockType(x, y, z); int lightBlocked = Math.Max(1, Block.LightAbsorbs[blockType]); int lightEmitted = 0; if (Type == LightType.Sky) { // Blocks directly hit by sky light scatter light if (world.RecievesSkyLight(x, y, z)) lightEmitted = 15; } else if (Type == LightType.Block) { lightEmitted = Block.LightEmits[blockType]; } // All light gets absorbed, no need to check neighbors if (lightBlocked >= 15 && lightEmitted == 0) newLight = 0; else { // Find the highest light from the neighbors newLight = Math.Max(0, GetHighestNeighbor(world, x, y, z) - lightBlocked); // Emitted light always takes precedence if (lightEmitted > newLight) newLight = lightEmitted; } // Light changed, scatter it to neighbors if (oldLight != newLight) { world.SetLight(Type, x, y, z, newLight); int neighborLight = Math.Max(0, newLight - 1); // Definitely update blocks we already passed in the loop engine.TryUpdateTile(Type, x - 1, y, z, neighborLight); engine.TryUpdateTile(Type, x, y - 1, z, neighborLight); engine.TryUpdateTile(Type, x, y, z - 1, neighborLight); // Only update following blocks if we aren't going to update them in this loop if (x + 1 >= Area.X2) engine.TryUpdateTile(Type, x + 1, y, z, neighborLight); if (y + 1 >= Area.Y2) engine.TryUpdateTile(Type, x, y + 1, z, neighborLight); if (z + 1 >= Area.Z2) engine.TryUpdateTile(Type, x, y, z + 1, neighborLight); } } } } }