public static ClientChunk ReadChunk(this NetIncomingMessage msg)
        {
            Debug.Assert(msg != null);

            var chunk = new ClientChunk();

            // Read all the tiles from the message
            for (var x = 0; x < Chunk.ChunkSize; x++)
            {
                for (var y = 0; y < Chunk.ChunkSize; y++)
                {
                    // False means no tile, so ignore it
                    if (!msg.ReadBoolean())
                    {
                        continue;
                    }

                    msg.ReadPadBits();
                    chunk.Tiles[x][y] = msg.ReadTile();
                }
            }
            msg.ReadPadBits();
            chunk.UpdateColliders();

            Debug.Assert(chunk != null);
            return(chunk);
        }
        public ClientChunk CreateClientChunk(ChunkOctree<ClientChunk> octree, long x, long y, long z)
        {
            var existing = octree.Get(x, y, z);

            if (existing != null)
            {
                return existing;
            }

            var @new = new ClientChunk(x, y, z);
            octree.Set(@new);

            return @new;
        }
        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;
                }
            }
        }
Exemple #4
0
        public void OnChunkRecieve(ChunkPacket packet)
        {
            var chunkX = packet.X;
            var chunkY = packet.Y;
            var data   = packet.ChunkData;

            if (!UnityClient.Map.Chunks.Any(cp => cp.Key.Equals($"{chunkX}_{chunkY}")))
            {
                var chunkParent = new GameObject($"chunk_{chunkX}_{chunkY}");

                ClientChunk c = new ClientChunk()
                {
                    x          = chunkX,
                    y          = chunkY,
                    GameObject = chunkParent
                };

                Debug.Log("Rendering Chunk " + chunkX + " " + chunkY);
                for (var x = 0; x < 16; x++)
                {
                    for (var y = 0; y < 16; y++)
                    {
                        var tileId = data[x, y];

                        var tilePosition = new Position(chunkX * 16 + x, chunkY * 16 + y);

                        c.Tiles[x, y] = new MapTile(tilePosition, tileId);

                        TileFactory.BuildAndInstantiate(new TileOptions()
                        {
                            Parent   = chunkParent,
                            Position = tilePosition,
                            TileId   = tileId
                        });
                    }
                }

                // To be a tracked chunk
                UnityClient.Map.AddChunk(c);
            }
        }
        public void CullInvisibleChunks()
        {
            if (!ClientSettings.Occlusionculling || game.WorldMap.chunks.Count < 100)
            {
                return;
            }

            Vec3d camPos = game.player.Entity.CameraPos;

            centerpos.Set((int)(camPos.X / chunksize), (int)(camPos.Y / chunksize), (int)(camPos.Z / chunksize));

            isAboveHeightLimit = centerpos.Y >= game.WorldMap.ChunkMapSizeY;

            playerViewVec = EntityPos.GetViewVector(game.mousePitch, game.mouseYaw).Normalize();

            lock (game.WorldMap.chunksLock)
            {
                foreach (var val in game.WorldMap.chunks)
                {
                    val.Value.SetVisible(false);
                }

                // We sometimes have issues with chunks adjacent to the player getting culled, so lets make these always visible
                for (int dx = -1; dx <= 1; dx++)
                {
                    for (int dy = -1; dy <= 1; dy++)
                    {
                        for (int dz = -1; dz <= 1; dz++)
                        {
                            long        index3d = game.WorldMap.ChunkIndex3D(dx + centerpos.X, dy + centerpos.Y, dz + centerpos.Z);
                            ClientChunk chunk   = null;

                            if (game.WorldMap.chunks.TryGetValue(index3d, out chunk))
                            {
                                chunk.SetVisible(true);
                            }
                        }
                    }
                }
            }


            // Add some 15 extra degrees to the field of view angle for safety
            float fov = GameMath.Cos(game.MainCamera.Fov + 15 * GameMath.DEG2RAD);

            for (int i = 0; i < cubicShellPositions.Length; i++)
            {
                Vec3i vec = cubicShellPositions[i];

                float dotProd = playerViewVec.Dot(cubicShellPositionsNormalized[i]);
                if (dotProd <= fov / 2)
                {
                    // Outside view frustum
                    continue;
                }

                // It seems that one trace can cause issues where chunks are culled when they shouldn't
                // 2 traces with a y-offset seems to mitigate most of that issue
                TraverseRayAndMarkVisible(centerpos, vec, 0.25);
                TraverseRayAndMarkVisible(centerpos, vec, 0.75);
            }
        }