public void update(float dt)
        {
            if (pinned)
            {
                if (pinnedTo != null)
                {
                    if (pinnedTo.ShouldDespawn && pinnedTo.DespawnReason?.reason != EnumDespawnReason.Unload)
                    {
                        UnPin();
                        return;
                    }

                    // New ideas:
                    // don't apply force onto the player/entity on compression
                    // apply huge forces onto the player on strong extension (to prevent massive stretching) (just set player motion to 0 or so. or we add a new countermotion field thats used in EntityControlledPhysics?)

                    float weight = pinnedTo.Properties.Weight;
                    float counterTensionStrength = GameMath.Clamp(50f / weight, 0.1f, 2f);

                    bool  extraResist           = (pinnedTo as EntityAgent)?.Controls.Sneak == true || pinnedTo.AnimManager?.IsAnimationActive("sit") == true || pinnedTo.AnimManager?.IsAnimationActive("sleep") == true;
                    float tensionResistStrength = weight / 10f * (extraResist ? 200 : 0);

                    pinOffsetTransform.Identity();
                    pinOffsetTransform.RotateY(pinnedTo.SidedPos.Yaw - pinnedToOffsetStartYaw);
                    tmpvec.Set(pinnedToOffset.X, pinnedToOffset.Y, pinnedToOffset.Z, 1);
                    Vec4f outvec = pinOffsetTransform.TransformVector(tmpvec);

                    EntityPos pos = pinnedTo.SidedPos;
                    Pos.Set(pos.X + outvec.X, pos.Y + outvec.Y, pos.Z + outvec.Z);

                    bool pushable = !(pinnedTo is EntityPlayer eplr && eplr.Player.WorldData.CurrentGameMode == EnumGameMode.Creative);

                    if (pushable && extension > 0) // Do not act on compressive force
                    {
                        float f = counterTensionStrength * dt * 0.003f;
                        pos.Motion.Add(
                            GameMath.Clamp(Math.Abs(TensionDirection.X) - tensionResistStrength, 0, 400) * f * Math.Sign(TensionDirection.X),
                            GameMath.Clamp(Math.Abs(TensionDirection.Y) - tensionResistStrength, 0, 400) * f * Math.Sign(TensionDirection.Y),
                            GameMath.Clamp(Math.Abs(TensionDirection.Z) - tensionResistStrength, 0, 400) * f * Math.Sign(TensionDirection.Z)
                            );
                    }

                    Velocity.Set(0, 0, 0);
                }
                else
                {
                    Velocity.Set(0, 0, 0);

                    accum1s += dt;

                    if (accum1s >= 1)
                    {
                        accum1s = 0;
                        Block block = cs.api.World.BlockAccessor.GetBlock(PinnedToBlockPos);
                        if (!block.HasBehavior <BlockBehaviorRopeTieable>())
                        {
                            UnPin();
                        }
                    }
                }

                return;
            }

            // Calculate the force on this ball
            Vec3f force = Tension.Clone();

            force.Y -= GravityStrength * 10;

            // Calculate the acceleration
            Vec3f acceleration = force * (float)InvMass;

            if (CollideFlags == 0)
            {
                acceleration.X += (float)cs.windSpeed.X * InvMass;
            }


            // Update velocity
            Vec3f nextVelocity = Velocity + (acceleration * dt);

            // Damp the velocity
            nextVelocity *= dampFactor;

            // Collision detection
            float size = 0.1f;

            cs.pp.HandleBoyancy(Pos, nextVelocity, cs.boyant, GravityStrength, dt, size);
            CollideFlags = cs.pp.UpdateMotion(Pos, nextVelocity, size);

            dt *= 0.99f;
            Pos.Add(nextVelocity.X * dt, nextVelocity.Y * dt, nextVelocity.Z * dt);


            Velocity.Set(nextVelocity);
            Tension.Set(0, 0, 0);
        }
Example #2
0
        /// <summary>
        /// Updates the velocity vector according to the amount of passed time, gravity and terrain collision.
        /// </summary>
        /// <param name="pos"></param>
        /// <param name="motion"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        public EnumCollideFlags UpdateMotion(Vec3d pos, Vec3f motion, float size)
        {
            particleCollBox.Set(
                pos.X - size / 2, pos.Y - 0 / 2, pos.Z - size / 2,
                pos.X + size / 2, pos.Y + size / 2, pos.Z + size / 2
                );

            motion.X = GameMath.Clamp(motion.X, -MotionCap, MotionCap);
            motion.Y = GameMath.Clamp(motion.Y, -MotionCap, MotionCap);
            motion.Z = GameMath.Clamp(motion.Z, -MotionCap, MotionCap);

            EnumCollideFlags flags = 0;

            minPos.Set(
                (int)(particleCollBox.X1 + Math.Min(0, motion.X)),
                (int)(particleCollBox.Y1 + Math.Min(0, motion.Y) - 1), // -1 for the extra high collision box of fences
                (int)(particleCollBox.Z1 + Math.Min(0, motion.Z))
                );

            maxPos.Set(
                (int)(particleCollBox.X2 + Math.Max(0, motion.X)),
                (int)(particleCollBox.Y2 + Math.Max(0, motion.Y)),
                (int)(particleCollBox.Z2 + Math.Max(0, motion.Z))
                );

            CollisionBoxList.Clear();
            BlockAccess.WalkBlocks(minPos, maxPos, (cblock, bpos) => {
                Cuboidf[] collisionBoxes = cblock.GetParticleCollisionBoxes(BlockAccess, bpos);

                for (int i = 0; collisionBoxes != null && i < collisionBoxes.Length; i++)
                {
                    CollisionBoxList.Add(collisionBoxes[i], bpos, cblock);
                }
            }, false);


            //  Y - Collision (Vertical)
            EnumPushDirection pushDirection = EnumPushDirection.None;

            for (int i = 0; i < CollisionBoxList.Count; i++)
            {
                blockCollBox = CollisionBoxList.cuboids[i];

                motion.Y = (float)blockCollBox.pushOutY(particleCollBox, motion.Y, ref pushDirection);

                if (pushDirection != EnumPushDirection.None)
                {
                    flags |= EnumCollideFlags.CollideY;
                }
            }


            particleCollBox.Translate(0, motion.Y, 0);


            // X - Collision (Horizontal)
            for (int i = 0; i < CollisionBoxList.Count; i++)
            {
                blockCollBox = CollisionBoxList.cuboids[i];

                motion.X = (float)blockCollBox.pushOutX(particleCollBox, motion.X, ref pushDirection);

                if (pushDirection != EnumPushDirection.None)
                {
                    flags |= EnumCollideFlags.CollideX;
                }
            }

            particleCollBox.Translate(motion.X, 0, 0);


            // Z - Collision (Horizontal)
            for (int i = 0; i < CollisionBoxList.Count; i++)
            {
                blockCollBox = CollisionBoxList.cuboids[i];

                motion.Z = (float)blockCollBox.pushOutZ(particleCollBox, motion.Z, ref pushDirection);

                if (pushDirection != EnumPushDirection.None)
                {
                    flags |= EnumCollideFlags.CollideZ;
                }
            }


            return(flags);
        }