void TraverseRayAndMarkVisible(Vec3i fromPos, Vec3i toPosRel, double yoffset = 0.5) { ray.origin.Set(fromPos.X + 0.5, fromPos.Y + yoffset, fromPos.Z + 0.5); ray.dir.Set(toPosRel); toPos.Set(fromPos.X + toPosRel.X, fromPos.Y + toPosRel.Y, fromPos.Z + toPosRel.Z); curpos.Set(fromPos); BlockFacing fromFace = null, toFace; int manhattenLength = fromPos.ManhattenDistanceTo(toPos); int curMhDist; while ((curMhDist = curpos.ManhattenDistanceTo(fromPos)) <= manhattenLength + 2) { // Since chunks are arranged in a uniform grid, all we have to do is to find out on // what facing (N/E/S/W/U/D) the ray leaves the chunk and move into that direction. // This may seem inaccurate, but works surpisingly well toFace = GetExitingFace(curpos); if (toFace == null) { return; } long index3d = ((long)curpos.Y * game.WorldMap.chunkMapSizeZFast + curpos.Z) * game.WorldMap.chunkMapSizeXFast + curpos.X; ClientChunk chunk = null; game.WorldMap.chunks.TryGetValue(index3d, out chunk); if (chunk != null) { chunk.SetVisible(true); if (curMhDist > 1 && !chunk.IsTraversable(fromFace, toFace)) { break; } } curpos.Offset(toFace); fromFace = toFace.GetOpposite(); if (!game.WorldMap.IsValidChunkPosFast(curpos.X, curpos.Y, curpos.Z) && (!isAboveHeightLimit || curpos.Y <= 0)) { break; } } }