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