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;
                }
            }
        }