예제 #1
0
        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;
                }
            }
        }
        public override bool OnHeldInteractStep(float secondsUsed, ItemSlot slot, EntityAgent byEntity, BlockSelection blockSel, EntitySelection entitySel)
        {
            if (blockSel == null)
            {
                return(false);
            }
            if (slot.Itemstack.TempAttributes.GetInt("refilled") > 0)
            {
                return(false);
            }

            float prevsecondsused = slot.Itemstack.TempAttributes.GetFloat("secondsUsed");

            slot.Itemstack.TempAttributes.SetFloat("secondsUsed", secondsUsed);

            float remainingwater = GetRemainingWateringSeconds(slot.Itemstack);

            SetRemainingWateringSeconds(slot.Itemstack, remainingwater -= secondsUsed - prevsecondsused);


            if (remainingwater <= 0)
            {
                return(false);
            }

            IWorldAccessor world = byEntity.World;

            BlockPos targetPos = blockSel.Position;

            if (api.World.Side == EnumAppSide.Server)
            {
                var beburningBh = world.BlockAccessor.GetBlockEntity(blockSel.Position.AddCopy(blockSel.Face))?.GetBehavior <BEBehaviorBurning>();
                if (beburningBh != null)
                {
                    beburningBh.KillFire(false);
                }

                beburningBh = world.BlockAccessor.GetBlockEntity(blockSel.Position)?.GetBehavior <BEBehaviorBurning>();
                if (beburningBh != null)
                {
                    beburningBh.KillFire(false);
                }

                Vec3i voxelPos = new Vec3i();
                for (int dx = -2; dx < 2; dx++)
                {
                    for (int dy = -2; dy < 2; dy++)
                    {
                        for (int dz = -2; dz < 2; dz++)
                        {
                            int x = (int)(blockSel.HitPosition.X * 16);
                            int y = (int)(blockSel.HitPosition.Y * 16);
                            int z = (int)(blockSel.HitPosition.Z * 16);
                            if (x + dx < 0 || x + dx > 15 || y + dy < 0 || y + dy > 15 || z + dz < 0 || z + dz > 15)
                            {
                                continue;
                            }

                            voxelPos.Set(x + dx, y + dy, z + dz);

                            int   faceAndSubPosition = CollectibleBehaviorArtPigment.BlockSelectionToSubPosition(blockSel.Face, voxelPos);
                            Block decorblock         = world.BlockAccessor.GetDecor(blockSel.Position, faceAndSubPosition);

                            if (decorblock?.FirstCodePart() == "caveart")
                            {
                                world.BlockAccessor.BreakDecor(blockSel.Position, blockSel.Face, faceAndSubPosition);
                            }
                        }
                    }
                }
            }

            Block block           = world.BlockAccessor.GetBlock(blockSel.Position);
            bool  notOnSolidblock = false;

            if ((block.CollisionBoxes == null || block.CollisionBoxes.Length == 0) && !block.IsLiquid())
            {
                notOnSolidblock = true;
                targetPos       = targetPos.DownCopy();
            }

            BlockEntityFarmland be = world.BlockAccessor.GetBlockEntity(targetPos) as BlockEntityFarmland;

            if (be != null)
            {
                be.WaterFarmland(secondsUsed - prevsecondsused);
            }

            float speed = 3f;

            if (world.Side == EnumAppSide.Client)
            {
                ModelTransform tf = new ModelTransform();
                tf.EnsureDefaultValues();

                tf.Origin.Set(0.5f, 0.2f, 0.5f);
                tf.Translation.Set(-Math.Min(0.25f, speed * secondsUsed / 2), 0, 0);
                tf.Rotation.Z = GameMath.Min(60, secondsUsed * 90 * speed, 120 - remainingwater * 4);
                byEntity.Controls.UsingHeldItemTransformBefore = tf;
            }

            IPlayer byPlayer = null;

            if (byEntity is EntityPlayer)
            {
                byPlayer = byEntity.World.PlayerByUid(((EntityPlayer)byEntity).PlayerUID);
            }


            if (secondsUsed > 1 / speed)
            {
                Vec3d pos = blockSel.Position.ToVec3d().Add(blockSel.HitPosition);
                if (notOnSolidblock)
                {
                    pos.Y = (int)pos.Y + 0.05;
                }
                WaterParticles.MinPos = pos.Add(-0.125 / 2, 1 / 16f, -0.125 / 2);
                byEntity.World.SpawnParticles(WaterParticles, byPlayer);
            }

            return(true);
        }
예제 #3
0
        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);
            }
        }