public override void DoApply(float dt, Entity entity, EntityPos pos, EntityControls controls) { if (controls.IsFlying) { pos.Motion.Add(controls.FlyVector.X, (controls.Up || controls.Down) ? 0 : controls.FlyVector.Y, controls.FlyVector.Z); float moveSpeed = dt * GlobalConstants.BaseMoveSpeed * controls.MovespeedMultiplier / 2; pos.Motion.Add(0, (controls.Up ? moveSpeed : 0) + (controls.Down ? -moveSpeed : 0), 0); } else { if (controls.IsClimbing) { pos.Motion.Add(controls.WalkVector); pos.Motion.X *= System.Math.Pow(1 - wallDragFactor, dt * 60); pos.Motion.Y *= System.Math.Pow(1 - wallDragFactor, dt * 60); pos.Motion.Z *= System.Math.Pow(1 - wallDragFactor, dt * 60); } else { float strength = airMovingStrength * (float)System.Math.Min(1, entity.Stats?.GetBlended("walkspeed") ?? 1.0) * dt * 60f; if (!controls.Jump && entity is EntityPlayer) { strength = airMovingStrengthFalling; pos.Motion.X *= (float)System.Math.Pow(0.98f, dt * 33); pos.Motion.Z *= (float)System.Math.Pow(0.98f, dt * 33); } pos.Motion.Add(controls.WalkVector.X * strength, controls.WalkVector.Y * strength, controls.WalkVector.Z * strength); } } }
public override void DoApply(float dt, Entity entity, EntityPos pos, EntityControls controls) { Block belowBlock = entity.World.BlockAccessor.GetBlock((int)pos.X, (int)(pos.Y - 0.05f), (int)pos.Z); if (!entity.Swimming && entity.Alive) { double multiplier = (entity as EntityAgent).GetWalkSpeedMultiplier(groundDragFactor); motionDelta.Set( motionDelta.X + (controls.WalkVector.X * multiplier - motionDelta.X) * belowBlock.DragMultiplier, 0, motionDelta.Z + (controls.WalkVector.Z * multiplier - motionDelta.Z) * belowBlock.DragMultiplier ); pos.Motion.Add(motionDelta.X, 0, motionDelta.Z); } if (controls.Jump && entity.World.ElapsedMilliseconds - lastJump > 500 && entity.Alive && !entity.Swimming) { lastJump = entity.World.ElapsedMilliseconds; pos.Motion.Y = GlobalConstants.BaseJumpForce * dt; EntityPlayer entityPlayer = entity as EntityPlayer; IPlayer player = entityPlayer != null?entityPlayer.World.PlayerByUid(entityPlayer.PlayerUID) : null; entity.PlayEntitySound("jump", player, false); } if (!entity.Swimming) { pos.Motion.X *= (1 - groundDragFactor); pos.Motion.Z *= (1 - groundDragFactor); } }
static void Prefix(EntityBehaviorPlayerPhysics __instance, Entity entity, float dt) { // FileLog.Log("Logs onto desktop Logger"); // Continue if entity is a player if (entity is EntityPlayer entityPlayer) { // Assign useful variables EntityControls controls = entityPlayer.Controls; string playerUID = entity.WatchedAttributes.GetString("playerUID"); IPlayer player = entity.World.PlayerByUid(playerUID); if (PlayerManager.Instance == null) { return; } if (player == null) { return; } PlayerData playerData = PlayerManager.Instance.GetOrAddPlayerData(player); // Sitting Logic if (playerData != null && playerData.IsPlayerSitting()) { // Disable Movement controls.StopAllMovement(); } } }
public override void DoApply(float dt, Entity entity, EntityPos pos, EntityControls controls) { if (controls.IsFlying) { pos.Motion.Add(controls.FlyVector.X, (controls.Up || controls.Down) ? 0 : controls.FlyVector.Y, controls.FlyVector.Z); float moveSpeed = dt * GlobalConstants.BaseMoveSpeed * controls.MovespeedMultiplier / 2; pos.Motion.Add(0, (controls.Up ? moveSpeed : 0) + (controls.Down ? -moveSpeed : 0), 0); } else { if (controls.IsClimbing) { pos.Motion.Add(controls.WalkVector); pos.Motion.X *= (1 - wallDragFactor); pos.Motion.Y *= (1 - wallDragFactor); pos.Motion.Z *= (1 - wallDragFactor); } else { pos.Motion.Add(controls.WalkVector.X * airMovingStrength, controls.WalkVector.Y * airMovingStrength, controls.WalkVector.Z * airMovingStrength); } } }
private bool HandleSteppingOnBlocks(EntityPos pos, EntityControls controls) { if (!controls.TriesToMove || (!entity.OnGround && !entity.Swimming)) { return(false); } Cuboidd entityCollisionBox = entity.CollisionBox.ToDouble(); entityCollisionBox.Translate(pos.X, pos.Y, pos.Z); Vec3d walkVec = controls.WalkVector; Vec3d testVec = new Vec3d(); Vec3d testMotion = new Vec3d(); Cuboidd stepableBox = findSteppableCollisionbox(entityCollisionBox, pos.Motion.Y, walkVec); // Must have walked into a slab if (stepableBox != null) { return (tryStep(pos, testMotion.Set(pos.Motion.X, pos.Motion.Y, pos.Motion.Z), stepableBox, entityCollisionBox) || tryStep(pos, testMotion.Set(pos.Motion.X, pos.Motion.Y, 0), findSteppableCollisionbox(entityCollisionBox, pos.Motion.Y, testVec.Set(walkVec.X, walkVec.Y, 0)), entityCollisionBox) || tryStep(pos, testMotion.Set(0, pos.Motion.Y, pos.Motion.Z), findSteppableCollisionbox(entityCollisionBox, pos.Motion.Y, testVec.Set(0, walkVec.Y, walkVec.Z)), entityCollisionBox) ); } return(false); }
public override bool Applicable(Entity entity, EntityPos pos, EntityControls controls) { return ((!controls.IsFlying && entity.Properties.Habitat != EnumHabitat.Air) && (entity.Properties.Habitat != EnumHabitat.Sea || !entity.Swimming) && !controls.IsClimbing ); }
public void TickEntityPhysics(EntityPos pos, EntityControls controls, float dt) { IBlockAccessor blockAccessor = entity.World.BlockAccessor; foreach (EntityLocomotion locomotor in Locomotors) { if (locomotor.Applicable(entity, pos, controls)) { locomotor.Apply(dt, entity, pos, controls); } } EntityAgent agent = entity as EntityAgent; if (agent?.MountedOn != null) { pos.SetFrom(agent.MountedOn.MountPosition); pos.Motion.X = 0; pos.Motion.Y = 0; pos.Motion.Z = 0; return; } pos.Motion.X = GameMath.Clamp(pos.Motion.X, -10, 10); pos.Motion.Y = GameMath.Clamp(pos.Motion.Y, -10, 10); pos.Motion.Z = GameMath.Clamp(pos.Motion.Z, -10, 10); if (!controls.NoClip) { DisplaceWithBlockCollision(pos, controls, dt); } else { pos.X += pos.Motion.X; pos.Y += pos.Motion.Y; pos.Z += pos.Motion.Z; entity.Swimming = false; entity.FeetInLiquid = false; entity.OnGround = false; } // Shake the player violently when falling at high speeds /*if (movedy < -50) * { * pos.X += (rand.NextDouble() - 0.5) / 5 * (-movedy / 50f); * pos.Z += (rand.NextDouble() - 0.5) / 5 * (-movedy / 50f); * } */ //return result; }
public virtual void GameTick(Entity entity, float dt) { EntityControls controls = ((EntityAgent)entity).Controls; TickEntityPhysics(entity.ServerPos, controls, dt); if (entity.World is IServerWorldAccessor) { entity.Pos.SetFrom(entity.ServerPos); } }
public virtual void GameTick(Entity entity, float dt) { EntityControls controls = ((EntityAgent)entity).Controls; TickEntityPhysics(entity.ServerPos, controls, dt); // this was entity.ServerPos - wtf? - apparently needed so they don't glitch through terrain o.O if (entity.World is IServerWorldAccessor) { entity.Pos.SetFrom(entity.ServerPos); } }
public virtual void TickEntityPhysicsPre(Entity entity, float dt) { prevPos.Set(entity.Pos.X, entity.Pos.Y, entity.Pos.Z); EntityControls controls = ((EntityAgent)entity).Controls; TickEntityPhysics(entity.ServerPos, controls, dt); // this was entity.ServerPos - wtf? - apparently needed so they don't glitch through terrain o.O if (entity.World.Side == EnumAppSide.Server) { entity.Pos.SetFrom(entity.ServerPos); } }
private void HandleSneaking(EntityPos pos, EntityControls controls, float dt) { if (!controls.Sneak || !entity.OnGround || pos.Motion.Y > 0) { return; } // Sneak to prevent falling off blocks Vec3d testPosition = new Vec3d(); testPosition.Set(pos.X, pos.Y - GlobalConstants.GravityPerSecond * dt, pos.Z); // Only apply this if he was on the ground in the first place if (!collisionTester.IsColliding(entity.World.BlockAccessor, sneakTestCollisionbox, testPosition)) { return; } Block belowBlock = entity.World.BlockAccessor.GetBlock((int)pos.X, (int)pos.Y - 1, (int)pos.Z); // Test for X testPosition.Set(outposition.X, outposition.Y - GlobalConstants.GravityPerSecond * dt, pos.Z); if (!collisionTester.IsColliding(entity.World.BlockAccessor, sneakTestCollisionbox, testPosition)) { // Weird hack so you can climb down ladders more easily if (belowBlock.Climbable) { outposition.X += (pos.X - outposition.X) / 10; } else { outposition.X = pos.X; } } // Test for Z testPosition.Set(pos.X, outposition.Y - GlobalConstants.GravityPerSecond * dt, outposition.Z); if (!collisionTester.IsColliding(entity.World.BlockAccessor, sneakTestCollisionbox, testPosition)) { // Weird hack so you can climb down ladders more easily if (belowBlock.Climbable) { outposition.Z += (pos.Z - outposition.Z) / 10; } else { outposition.Z = pos.Z; } } }
public override void DoApply(float dt, Entity entity, EntityPos pos, EntityControls controls) { if (entity.FeetInLiquid || entity.Swimming) { pos.Motion *= (float)Math.Pow(waterDragValue, dt * 33); } else { pos.Motion *= (float)Math.Pow(airDragValue, dt * 33); } if (controls.IsFlying) { pos.Motion *= (float)Math.Pow(GlobalConstants.AirDragFlying, dt * 33); } }
public override void DoApply(float dt, Entity entity, EntityPos pos, EntityControls controls) { if (entity.Swimming) { if ((controls.TriesToMove || controls.Jump) && entity.World.ElapsedMilliseconds - lastPush > 2000) { push = 8f; lastPush = entity.World.ElapsedMilliseconds; string playerUID = entity is EntityPlayer ? ((EntityPlayer)entity).PlayerUID : null; entity.PlayEntitySound("swim", playerUID == null ? null : entity.World.PlayerByUid(playerUID)); EntityAgent.SplashParticleProps.BasePos.Set(pos.X, pos.Y + 0.25f, pos.Z); entity.World.SpawnParticles(EntityAgent.AirBubbleParticleProps); } else { push = Math.Max(1, push - 0.1f); } double yMot = 0; if (controls.Jump) { yMot = push * 0.001f; } else { yMot = controls.FlyVector.Y * (1 + push) * 0.03f; } pos.Motion.Add( controls.FlyVector.X * (1 + push) * 0.03f, yMot, controls.FlyVector.Z * (1 + push) * 0.03f ); } // http://fooplot.com/plot/kg6l1ikyx2 /*float x = entity.Pos.Motion.Length(); * if (x > 0) * { * pos.Motion.Normalize(); * pos.Motion *= (float)Math.Log(x + 1) / 1.5f; * * }*/ }
private bool TryStepSmooth(EntityControls controls, EntityPos pos, Vec2d walkVec, float dtFac, List <Cuboidd> stepableBoxes, Cuboidd entityCollisionBox) { if (stepableBoxes == null || stepableBoxes.Count == 0) { return(false); } double gravityOffset = 0.03; // This added constant value is a fugly hack because outposition has gravity added, but has not adjusted its position to the ground floor yet var walkVecOrtho = new Vec2d(walkVec.Y, -walkVec.X).Normalize(); var maxX = Math.Abs(walkVecOrtho.X * 0.3) + 0.001; var minX = -maxX; var maxZ = Math.Abs(walkVecOrtho.Y * 0.3) + 0.001; var minZ = -maxZ; var col = new Cuboidf((float)minX, entity.CollisionBox.Y1, (float)minZ, (float)maxX, entity.CollisionBox.Y2, (float)maxZ); double newYPos = pos.Y; bool foundStep = false; foreach (var stepableBox in stepableBoxes) { double heightDiff = stepableBox.Y2 - entityCollisionBox.Y1 + gravityOffset; Vec3d steppos = new Vec3d(GameMath.Clamp(outposition.X, stepableBox.MinX, stepableBox.MaxX), outposition.Y + heightDiff, GameMath.Clamp(outposition.Z, stepableBox.MinZ, stepableBox.MaxZ)); bool canStep = !collisionTester.IsColliding(entity.World.BlockAccessor, col, steppos, false); if (canStep) { double elevateFactor = controls.Sprint ? 0.10 : controls.Sneak ? 0.025 : 0.05; if (!stepableBox.IntersectsOrTouches(entityCollisionBox)) { newYPos = Math.Max(newYPos, Math.Min(pos.Y + elevateFactor * dtFac, stepableBox.Y2 - entity.CollisionBox.Y1 + gravityOffset)); } else { newYPos = Math.Max(newYPos, pos.Y + elevateFactor * dtFac); } foundStep = true; } } if (foundStep) { pos.Y = newYPos; collisionTester.ApplyTerrainCollision(entity, pos, dtFac, ref outposition); } return(foundStep); }
public override void DoApply(float dt, Entity entity, EntityPos pos, EntityControls controls) { Block belowBlock = entity.World.BlockAccessor.GetBlock((int)pos.X, (int)(pos.Y - 0.05f), (int)pos.Z); accum = Math.Min(1, accum + dt); float frametime = 1 / 60f; while (accum > frametime) { accum -= frametime; if (!entity.Swimming && entity.Alive) { // Apply walk motion double multiplier = (entity as EntityAgent).GetWalkSpeedMultiplier(groundDragFactor); motionDelta.Set( motionDelta.X + (controls.WalkVector.X * multiplier - motionDelta.X) * belowBlock.DragMultiplier, 0, motionDelta.Z + (controls.WalkVector.Z * multiplier - motionDelta.Z) * belowBlock.DragMultiplier ); pos.Motion.Add(motionDelta.X, 0, motionDelta.Z); } if (!entity.Swimming) { // Apply ground drag double dragstrength = 1 - groundDragFactor; pos.Motion.X *= dragstrength; pos.Motion.Z *= dragstrength; } } if (controls.Jump && entity.World.ElapsedMilliseconds - lastJump > 500 && entity.Alive && !entity.Swimming) { // Apply jump motion lastJump = entity.World.ElapsedMilliseconds; pos.Motion.Y = GlobalConstants.BaseJumpForce * 1 / 60f; EntityPlayer entityPlayer = entity as EntityPlayer; IPlayer player = entityPlayer != null?entityPlayer.World.PlayerByUid(entityPlayer.PlayerUID) : null; entity.PlayEntitySound("jump", player, false); } }
public override void DoApply(float dt, Entity entity, EntityPos pos, EntityControls controls) { if (entity.Swimming && controls.TriesToMove) { return; } if (!entity.ApplyGravity) { return; } if (pos.Y > -100) { pos.Motion.Y -= (gravityPerSecond * dt + Math.Max(0, -0.015f * pos.Motion.Y)) * (entity.FeetInLiquid ? 0.33f : 1f); } }
//------------------------------------------------------------------------------------------- private void AddControl(Random rnd) { int x = rnd.Next(10000); //EntityDataSource eds = new EntityDataSource(); //eds.ID = "DetailsDataSource" + x.ToString(); //eds.EnableUpdate = true; //eds.EntityTypeFilter = table.EntityType.Name; ////eds.EntitySetName = "Accounting_Accounts"; ////eds.ContextTypeName = "WeavverEntityContext"; ////eds.Where = "it.id = @id"; ////eds.WhereParameters.Add("id", DbType.Guid, "3d322c57-2b4a-4b27-8187-2094931eb2ca"); //AddedControls.Controls.Add(eds); //DynamicDataManager ddm = new DynamicDataManager(); //ddm.ID = "DynamicDataManager3"; //ddm.AutoLoadForeignKeys = true; //DataControlReference ddr = new DataControlReference(); //ddr.ControlID = "FormView3"; //ddm.DataControls.Add(ddr); //AddedControls.Controls.Add(ddm); FormView fv = new FormView(); fv.ID = "FormView" + x.ToString(); fv.DataSourceID = "GridDataSource"; YourTemplate yt = new YourTemplate(); fv.ItemTemplate = yt; //fv.ItemTemplate.Controls.Add(de); AddedControls.Controls.Add(fv); DynamicDataManager1.RegisterControl(fv); EntityControls.Update(); }
public override bool PreAI(NPC npc) { EntityControls.ApplyFakeTarget(npc, this.FakeTarget, this.FakeTargetPosition); if (this.LockedAI0.HasValue) { npc.ai[0] = this.LockedAI0.Value; } if (this.LockedAI1.HasValue) { npc.ai[1] = this.LockedAI1.Value; } if (this.LockedAI2.HasValue) { npc.ai[2] = this.LockedAI2.Value; } if (this.LockedAI3.HasValue) { npc.ai[3] = this.LockedAI3.Value; } return(base.PreAI(npc)); }
public float[] GetControls() { IPlayer player = capi.World.Player; EntityControls c = player.Entity.Controls; return(new float[] { c.Backward ? 1 : 0, //0 c.Down ? 1 : 0, //1 c.FloorSitting ? 1 : 0, //2 c.Forward ? 1 : 0, //3 c.Jump ? 1 : 0, //4 c.Left ? 1 : 0, //5 c.LeftMouseDown ? 1 : 0, //6 c.Right ? 1 : 0, //7 c.RightMouseDown ? 1 : 0, //8 c.Sitting ? 1 : 0, //9 c.Sneak ? 1 : 0, //10 c.Sprint ? 1 : 0, //11 c.TriesToMove ? 1 : 0, // 12 c.Up ? 1 : 0, //13 }); }
public void Apply(float dt, Entity entity, EntityPos pos, EntityControls controls) { DoApply(dt, entity, pos, controls); appliedMilliseconds += (int)(dt * 1000); }
public abstract void DoApply(float dt, Entity entity, EntityPos pos, EntityControls controls);
public abstract bool Applicable(Entity entity, EntityPos pos, EntityControls controls);
public override bool Applicable(Entity entity, EntityPos pos, EntityControls controls) { return(controls.IsFlying || (!entity.Collided && !entity.FeetInLiquid)); }
public override void GameTick(Entity entity, float dt) { EntityPlayer entityplayer = entity as EntityPlayer; EntityControls controls = entityplayer.Controls; string playerUID = entity.WatchedAttributes.GetString("playerUID"); IPlayer player = entity.World.PlayerByUid(playerUID); if (entity.World is IServerWorldAccessor && ((IServerPlayer)player).ConnectionState != EnumClientState.Playing) { return; } if (player != null) { IClientWorldAccessor clientWorld = entity.World as IClientWorldAccessor; // Tyron Nov. 10 2020: This line of code was from August 2020 where it fixed jitter of other players related to climbing ladders? // Cannot repro. But what I can repro is this line breaks player animations. They are stuck in a permanent land pose, so disabled for now. //if (clientWorld != null && clientWorld.Player.ClientId != player.ClientId) return; // We pretend the entity is flying to disable gravity so that EntityBehaviorInterpolatePosition system // can work better controls.IsFlying = player.WorldData.FreeMove || (clientWorld != null && clientWorld.Player.ClientId != player.ClientId); controls.NoClip = player.WorldData.NoClip; controls.MovespeedMultiplier = player.WorldData.MoveSpeedMultiplier; } EntityPos pos = entity.World is IServerWorldAccessor ? entity.ServerPos : entity.Pos; if (controls.TriesToMove && player is IClientPlayer) { IClientPlayer cplr = player as IClientPlayer; float prevYaw = pos.Yaw; if (entity.Swimming) { float prevPitch = pos.Pitch; pos.Yaw = cplr.CameraYaw; pos.Pitch = cplr.CameraPitch; controls.CalcMovementVectors(pos, dt); pos.Yaw = prevYaw; pos.Pitch = prevPitch; } else { pos.Yaw = cplr.CameraYaw; controls.CalcMovementVectors(pos, dt); pos.Yaw = prevYaw; } float desiredYaw = (float)Math.Atan2(controls.WalkVector.X, controls.WalkVector.Z) - GameMath.PIHALF; float yawDist = GameMath.AngleRadDistance(entityplayer.WalkYaw, desiredYaw); entityplayer.WalkYaw += GameMath.Clamp(yawDist, -8 * dt * GlobalConstants.OverallSpeedMultiplier, 8 * dt * GlobalConstants.OverallSpeedMultiplier); entityplayer.WalkYaw = GameMath.Mod(entityplayer.WalkYaw, GameMath.TWOPI); if (entity.Swimming) { float desiredPitch = -(float)Math.Sin(pos.Pitch); // (float)controls.FlyVector.Y * GameMath.PI; float pitchDist = GameMath.AngleRadDistance(entityplayer.WalkPitch, desiredPitch); entityplayer.WalkPitch += GameMath.Clamp(pitchDist, -2 * dt * GlobalConstants.OverallSpeedMultiplier, 2 * dt * GlobalConstants.OverallSpeedMultiplier); entityplayer.WalkPitch = GameMath.Mod(entityplayer.WalkPitch, GameMath.TWOPI); } else { entityplayer.WalkPitch = 0; } } else { controls.CalcMovementVectors(pos, dt); } TickEntityPhysics(pos, controls, dt); }
public void TickEntityPhysics(EntityPos pos, EntityControls controls, float dt) { float dtFac = 60 * dt; // This seems to make creatures clip into the terrain. Le sigh. // Since we currently only really need it for when the creature is dead, let's just use it only there // Also running animations for all nearby living entities is pretty CPU intensive so // the AnimationManager also just ticks if the entity is in view or dead if (!entity.Alive) { AdjustCollisionBoxToAnimation(dtFac); } foreach (EntityLocomotion locomotor in Locomotors) { if (locomotor.Applicable(entity, pos, controls)) { locomotor.Apply(dt, entity, pos, controls); } } EntityAgent agent = entity as EntityAgent; if (agent?.MountedOn != null) { pos.SetFrom(agent.MountedOn.MountPosition); pos.Motion.X = 0; pos.Motion.Y = 0; pos.Motion.Z = 0; return; } pos.Motion.X = GameMath.Clamp(pos.Motion.X, -10, 10); pos.Motion.Y = GameMath.Clamp(pos.Motion.Y, -10, 10); pos.Motion.Z = GameMath.Clamp(pos.Motion.Z, -10, 10); if (!controls.NoClip) { DisplaceWithBlockCollision(pos, controls, dt); } else { pos.X += pos.Motion.X * dt * 60f; pos.Y += pos.Motion.Y * dt * 60f; pos.Z += pos.Motion.Z * dt * 60f; entity.Swimming = false; entity.FeetInLiquid = false; entity.OnGround = false; } // Shake the player violently when falling at high speeds /*if (movedy < -50) * { * pos.X += (rand.NextDouble() - 0.5) / 5 * (-movedy / 50f); * pos.Z += (rand.NextDouble() - 0.5) / 5 * (-movedy / 50f); * } */ //return result; }
public override bool Applicable(Entity entity, EntityPos pos, EntityControls controls) { return(entity.FeetInLiquid); }
public override void DoApply(float dt, Entity entity, EntityPos pos, EntityControls controls) { if (entity.Swimming && entity.Alive) { string playerUID = entity is EntityPlayer ? ((EntityPlayer)entity).PlayerUID : null; if ((controls.TriesToMove || controls.Jump) && entity.World.ElapsedMilliseconds - lastPush > 2000 && playerUID != null) { push = 8f; lastPush = entity.World.ElapsedMilliseconds; entity.PlayEntitySound("swim", playerUID == null ? null : entity.World.PlayerByUid(playerUID)); } else { push = Math.Max(1f, push - 0.1f); } Block inblock = entity.World.BlockAccessor.GetBlock((int)pos.X, (int)(pos.Y), (int)pos.Z); Block aboveblock = entity.World.BlockAccessor.GetBlock((int)pos.X, (int)(pos.Y + 1), (int)pos.Z); Block twoaboveblock = entity.World.BlockAccessor.GetBlock((int)pos.X, (int)(pos.Y + 2), (int)pos.Z); float waterY = (int)pos.Y + inblock.LiquidLevel / 8f + (aboveblock.IsLiquid() ? 9 / 8f : 0) + (twoaboveblock.IsLiquid() ? 9 / 8f : 0); float bottomSubmergedness = waterY - (float)pos.Y; // 0 = at swim line // 1 = completely submerged float swimlineSubmergedness = GameMath.Clamp(bottomSubmergedness - ((float)entity.SwimmingOffsetY), 0, 1); swimlineSubmergedness = Math.Min(1, swimlineSubmergedness + 0.075f); double yMot = 0; if (controls.Jump) { yMot = 0.005f * swimlineSubmergedness; } else { yMot = controls.FlyVector.Y * (1 + push) * 0.03f * swimlineSubmergedness; } pos.Motion.Add( controls.FlyVector.X * (1 + push) * 0.03f, yMot, controls.FlyVector.Z * (1 + push) * 0.03f ); } Block block = entity.World.BlockAccessor.GetBlock((int)pos.X, (int)pos.Y, (int)pos.Z); if (block.PushVector != null) { pos.Motion.Add(block.PushVector); } // http://fooplot.com/plot/kg6l1ikyx2 /*float x = entity.Pos.Motion.Length(); * if (x > 0) * { * pos.Motion.Normalize(); * pos.Motion *= (float)Math.Log(x + 1) / 1.5f; * * }*/ }
public void DisplaceWithBlockCollision(EntityPos pos, EntityControls controls, float dt) { IBlockAccessor blockAccess = entity.World.BlockAccessor; nextPosition.Set(pos.X + pos.Motion.X, pos.Y + pos.Motion.Y, pos.Z + pos.Motion.Z); bool falling = pos.Motion.Y < 0; bool feetInLiquidBefore = entity.FeetInLiquid; bool onGroundBefore = entity.OnGround; bool swimmingBefore = entity.Swimming; double prevYMotion = pos.Motion.Y; controls.IsClimbing = false; if (!onGroundBefore && entity.Properties.CanClimb == true) { int height = (int)Math.Ceiling(entity.CollisionBox.Y2); entityBox.Set(entity.CollisionBox).Translate(pos.X, pos.Y, pos.Z); for (int dy = 0; dy < height; dy++) { tmpPos.Set((int)pos.X, (int)pos.Y + dy, (int)pos.Z); Block nblock = blockAccess.GetBlock(tmpPos); if (!nblock.Climbable && !entity.Properties.CanClimbAnywhere) { continue; } Cuboidf[] collBoxes = nblock.GetCollisionBoxes(blockAccess, tmpPos); if (collBoxes == null) { continue; } for (int i = 0; i < collBoxes.Length; i++) { double dist = entityBox.ShortestDistanceFrom(collBoxes[i], tmpPos); controls.IsClimbing |= dist < entity.Properties.ClimbTouchDistance; if (controls.IsClimbing) { entity.ClimbingOnFace = null; break; } } } for (int i = 0; !controls.IsClimbing && i < BlockFacing.HORIZONTALS.Length; i++) { BlockFacing facing = BlockFacing.HORIZONTALS[i]; for (int dy = 0; dy < height; dy++) { tmpPos.Set((int)pos.X + facing.Normali.X, (int)pos.Y + dy, (int)pos.Z + facing.Normali.Z); Block nblock = blockAccess.GetBlock(tmpPos); if (!nblock.Climbable && !entity.Properties.CanClimbAnywhere) { continue; } Cuboidf[] collBoxes = nblock.GetCollisionBoxes(blockAccess, tmpPos); if (collBoxes == null) { continue; } for (int j = 0; j < collBoxes.Length; j++) { double dist = entityBox.ShortestDistanceFrom(collBoxes[j], tmpPos); controls.IsClimbing |= dist < entity.Properties.ClimbTouchDistance; if (controls.IsClimbing) { entity.ClimbingOnFace = facing; break; } } } } } if (controls.IsClimbing) { if (controls.WalkVector.Y == 0) { pos.Motion.Y = controls.Sneak ? Math.Max(-0.07, pos.Motion.Y - 0.07) : pos.Motion.Y; if (controls.Jump) { pos.Motion.Y = 0.04; } } nextPosition.Set(pos.X + pos.Motion.X, pos.Y + pos.Motion.Y, pos.Z + pos.Motion.Z); } collisionTester.ApplyTerrainCollision(entity, pos, ref outposition, !(entity is EntityPlayer)); bool isStepping = HandleSteppingOnBlocks(pos, controls); HandleSneaking(pos, controls, dt); if (blockAccess.IsNotTraversable((int)(pos.X + pos.Motion.X), (int)pos.Y, (int)pos.Z)) { outposition.X = pos.X; } if (blockAccess.IsNotTraversable((int)pos.X, (int)(pos.Y + pos.Motion.Y), (int)pos.Z)) { outposition.Y = pos.Y; } if (blockAccess.IsNotTraversable((int)pos.X, (int)pos.Y, (int)(pos.Z + pos.Motion.Z))) { outposition.Z = pos.Z; } pos.SetPos(outposition); // Set the players motion to zero if he collided. if ((nextPosition.X < outposition.X && pos.Motion.X < 0) || (nextPosition.X > outposition.X && pos.Motion.X > 0)) { pos.Motion.X = 0; } if ((nextPosition.Y < outposition.Y && pos.Motion.Y < 0) || (nextPosition.Y > outposition.Y && pos.Motion.Y > 0)) { pos.Motion.Y = 0; } if ((nextPosition.Z < outposition.Z && pos.Motion.Z < 0) || (nextPosition.Z > outposition.Z && pos.Motion.Z > 0)) { pos.Motion.Z = 0; } Block block = blockAccess.GetBlock((int)pos.X, (int)(pos.Y), (int)pos.Z); Block aboveblock = blockAccess.GetBlock((int)pos.X, (int)(pos.Y + 1), (int)pos.Z); Block middleBlock = blockAccess.GetBlock((int)pos.X, (int)(pos.Y + entity.CollisionBox.Y1 + entity.CollisionBox.Y2 * 0.66f), (int)pos.Z); entity.OnGround = (entity.CollidedVertically && falling && !controls.IsClimbing) || isStepping; entity.FeetInLiquid = block.IsLiquid() && ((block.LiquidLevel + (aboveblock.LiquidLevel > 0 ? 1 : 0)) / 8f >= pos.Y - (int)pos.Y); entity.Swimming = middleBlock.IsLiquid(); // Console.WriteLine(entity.World.Side + ": "+ entity.OnGround + " / " + pos.Y); if (!onGroundBefore && entity.OnGround) { entity.OnFallToGround(prevYMotion); } if ((!entity.Swimming && !feetInLiquidBefore && entity.FeetInLiquid) || (!entity.FeetInLiquid && !swimmingBefore && entity.Swimming)) { entity.OnCollideWithLiquid(); } if ((swimmingBefore && !entity.Swimming && !entity.FeetInLiquid) || (feetInLiquidBefore && !entity.FeetInLiquid && !entity.Swimming)) { entity.OnExitedLiquid(); } if (!falling || entity.OnGround || controls.IsClimbing) { entity.PositionBeforeFalling.Set(outposition); } Cuboidd testedEntityBox = collisionTester.entityBox; for (int y = (int)testedEntityBox.Y1; y <= (int)testedEntityBox.Y2; y++) { for (int x = (int)testedEntityBox.X1; x <= (int)testedEntityBox.X2; x++) { for (int z = (int)testedEntityBox.Z1; z <= (int)testedEntityBox.Z2; z++) { collisionTester.tmpPos.Set(x, y, z); collisionTester.tempCuboid.Set(x, y, z, x + 1, y + 1, z + 1); if (collisionTester.tempCuboid.IntersectsOrTouches(testedEntityBox)) { // Saves us a few cpu cycles if (x == (int)pos.X && y == (int)pos.Y && z == (int)pos.Z) { block.OnEntityInside(entity.World, entity, collisionTester.tmpPos); continue; } blockAccess.GetBlock(x, y, z).OnEntityInside(entity.World, entity, collisionTester.tmpPos); } } } } }
public void DisplaceWithBlockCollision(EntityPos pos, EntityControls controls, float dt) { IBlockAccessor blockAccess = entity.World.BlockAccessor; float dtFac = 60 * dt; moveDelta.Set(pos.Motion.X * dtFac, pos.Motion.Y * dtFac, pos.Motion.Z * dtFac); nextPosition.Set(pos.X + moveDelta.X, pos.Y + moveDelta.Y, pos.Z + moveDelta.Z); bool falling = pos.Motion.Y < 0; bool feetInLiquidBefore = entity.FeetInLiquid; bool onGroundBefore = entity.OnGround; bool swimmingBefore = entity.Swimming; double prevYMotion = pos.Motion.Y; controls.IsClimbing = false; if (!onGroundBefore && entity.Properties.CanClimb == true) { int height = (int)Math.Ceiling(entity.CollisionBox.Y2); entityBox.Set(entity.CollisionBox).Translate(pos.X, pos.Y, pos.Z); for (int dy = 0; dy < height; dy++) { tmpPos.Set((int)pos.X, (int)pos.Y + dy, (int)pos.Z); Block nblock = blockAccess.GetBlock(tmpPos); if (!nblock.Climbable && !entity.Properties.CanClimbAnywhere) { continue; } Cuboidf[] collBoxes = nblock.GetCollisionBoxes(blockAccess, tmpPos); if (collBoxes == null) { continue; } for (int i = 0; i < collBoxes.Length; i++) { double dist = entityBox.ShortestDistanceFrom(collBoxes[i], tmpPos); controls.IsClimbing |= dist < entity.Properties.ClimbTouchDistance; if (controls.IsClimbing) { entity.ClimbingOnFace = null; break; } } } for (int i = 0; !controls.IsClimbing && i < BlockFacing.HORIZONTALS.Length; i++) { BlockFacing facing = BlockFacing.HORIZONTALS[i]; for (int dy = 0; dy < height; dy++) { tmpPos.Set((int)pos.X + facing.Normali.X, (int)pos.Y + dy, (int)pos.Z + facing.Normali.Z); Block nblock = blockAccess.GetBlock(tmpPos); if (!nblock.Climbable && !(entity.Properties.CanClimbAnywhere && entity.Alive)) { continue; } Cuboidf[] collBoxes = nblock.GetCollisionBoxes(blockAccess, tmpPos); if (collBoxes == null) { continue; } for (int j = 0; j < collBoxes.Length; j++) { double dist = entityBox.ShortestDistanceFrom(collBoxes[j], tmpPos); controls.IsClimbing |= dist < entity.Properties.ClimbTouchDistance; if (controls.IsClimbing) { entity.ClimbingOnFace = facing; entity.ClimbingOnCollBox = collBoxes[j]; break; } } } } } if (controls.IsClimbing) { if (controls.WalkVector.Y == 0) { pos.Motion.Y = controls.Sneak ? Math.Max(-0.07, pos.Motion.Y - 0.07) : pos.Motion.Y; if (controls.Jump) { pos.Motion.Y = 0.035 * dt * 60f; } } // what was this for? it causes jitter //moveDelta.Y = pos.Motion.Y * dt * 60f; //nextPosition.Set(pos.X + moveDelta.X, pos.Y + moveDelta.Y, pos.Z + moveDelta.Z); } collisionTester.ApplyTerrainCollision(entity, pos, dtFac, ref outposition, stepHeight); if (!entity.Properties.CanClimbAnywhere) { controls.IsStepping = HandleSteppingOnBlocks(pos, moveDelta, dtFac, controls); } HandleSneaking(pos, controls, dt); if (entity.CollidedHorizontally && !controls.IsClimbing && !controls.IsStepping) { if (blockAccess.GetBlock((int)pos.X, (int)(pos.Y), (int)pos.Z).LiquidLevel >= 7 || (blockAccess.GetBlock((int)pos.X, (int)(pos.Y - 0.05), (int)pos.Z).LiquidLevel >= 7)) { pos.Motion.Y += 0.2 * dt; controls.IsStepping = true; } } if (blockAccess.IsNotTraversable((pos.X + pos.Motion.X * dt * 60f), pos.Y, pos.Z)) { outposition.X = pos.X; } if (blockAccess.IsNotTraversable(pos.X, (pos.Y + pos.Motion.Y * dt * 60f), pos.Z)) { outposition.Y = pos.Y; } if (blockAccess.IsNotTraversable(pos.X, pos.Y, (pos.Z + pos.Motion.Z * dt * 60f))) { outposition.Z = pos.Z; } pos.SetPos(outposition); // Set the motion to zero if he collided. if ((nextPosition.X < outposition.X && pos.Motion.X < 0) || (nextPosition.X > outposition.X && pos.Motion.X > 0)) { pos.Motion.X = 0; } if ((nextPosition.Y < outposition.Y && pos.Motion.Y < 0) || (nextPosition.Y > outposition.Y && pos.Motion.Y > 0)) { pos.Motion.Y = 0; } if ((nextPosition.Z < outposition.Z && pos.Motion.Z < 0) || (nextPosition.Z > outposition.Z && pos.Motion.Z > 0)) { pos.Motion.Z = 0; } float offX = entity.CollisionBox.X2 - entity.OriginCollisionBox.X2; float offZ = entity.CollisionBox.Z2 - entity.OriginCollisionBox.Z2; int posX = (int)(pos.X + offX); int posZ = (int)(pos.Z + offZ); Block block = blockAccess.GetBlock(posX, (int)(pos.Y), posZ); Block aboveblock = blockAccess.GetBlock(posX, (int)(pos.Y + 1), posZ); Block middleBlock = blockAccess.GetBlock(posX, (int)(pos.Y + entity.SwimmingOffsetY), posZ); entity.OnGround = (entity.CollidedVertically && falling && !controls.IsClimbing) || controls.IsStepping; entity.FeetInLiquid = block.IsLiquid() && ((block.LiquidLevel + (aboveblock.LiquidLevel > 0 ? 1 : 0)) / 8f >= pos.Y - (int)pos.Y); entity.InLava = block.LiquidCode == "lava"; entity.Swimming = middleBlock.IsLiquid(); if (!onGroundBefore && entity.OnGround) { entity.OnFallToGround(prevYMotion); } if ((!entity.Swimming && !feetInLiquidBefore && entity.FeetInLiquid) || (!entity.FeetInLiquid && !swimmingBefore && entity.Swimming)) { entity.OnCollideWithLiquid(); } if ((swimmingBefore && !entity.Swimming && !entity.FeetInLiquid) || (feetInLiquidBefore && !entity.FeetInLiquid && !entity.Swimming)) { entity.OnExitedLiquid(); } if (!falling || entity.OnGround || controls.IsClimbing) { entity.PositionBeforeFalling.Set(outposition); } Cuboidd testedEntityBox = collisionTester.entityBox; for (int y = (int)testedEntityBox.Y1; y <= (int)testedEntityBox.Y2; y++) { for (int x = (int)testedEntityBox.X1; x <= (int)testedEntityBox.X2; x++) { for (int z = (int)testedEntityBox.Z1; z <= (int)testedEntityBox.Z2; z++) { collisionTester.tmpPos.Set(x, y, z); collisionTester.tempCuboid.Set(x, y, z, x + 1, y + 1, z + 1); if (collisionTester.tempCuboid.IntersectsOrTouches(testedEntityBox)) { // Saves us a few cpu cycles if (x == (int)pos.X && y == (int)pos.Y && z == (int)pos.Z) { block.OnEntityInside(entity.World, entity, collisionTester.tmpPos); continue; } blockAccess.GetBlock(x, y, z).OnEntityInside(entity.World, entity, collisionTester.tmpPos); } } } } }
public override void OnGameTick(float dt) { if (!Active) { return; } // For land dwellers only check horizontal distance double sqDistToTarget = entity.Properties.Habitat == API.Common.EnumHabitat.Land ? target.SquareDistanceTo(entity.ServerPos.X, target.Y, entity.ServerPos.Z) : target.SquareDistanceTo(entity.ServerPos.X, entity.ServerPos.Y, entity.ServerPos.Z) ; if (sqDistToTarget < targetDistance * targetDistance) { Stop(); OnGoalReached?.Invoke(); return; } bool stuck = (entity.CollidedVertically && entity.Controls.IsClimbing) || (entity.ServerPos.SquareDistanceTo(prevPos) < 0.005 * 0.005) || // This used to test motion, but that makes no sense, we want to test if the entity moved, not if it had motion (entity.CollidedHorizontally && entity.ServerPos.Motion.Y <= 0) ; prevPos.Set(entity.ServerPos.X, entity.ServerPos.Y, entity.ServerPos.Z); stuckCounter = stuck ? (stuckCounter + 1) : 0; if (GlobalConstants.OverallSpeedMultiplier > 0 && stuckCounter > 20 / GlobalConstants.OverallSpeedMultiplier) { //entity.World.SpawnParticles(10, ColorUtil.WhiteArgb, prevPos, prevPos, new Vec3f(0, 0, 0), new Vec3f(0, -1, 0), 1, 1); Stop(); OnStuck?.Invoke(); return; } EntityControls controls = entity.MountedOn == null ? entity.Controls : entity.MountedOn.Controls; if (controls == null) { return; } targetVec.Set( (float)(target.X - entity.ServerPos.X), (float)(target.Y - entity.ServerPos.Y), (float)(target.Z - entity.ServerPos.Z) ); float desiredYaw = 0; if (sqDistToTarget >= 0.01) { desiredYaw = (float)Math.Atan2(targetVec.X, targetVec.Z); } float yawDist = GameMath.AngleRadDistance(entity.ServerPos.Yaw, desiredYaw); entity.ServerPos.Yaw += GameMath.Clamp(yawDist, -curTurnRadPerSec * dt * GlobalConstants.OverallSpeedMultiplier, curTurnRadPerSec * dt * GlobalConstants.OverallSpeedMultiplier); entity.ServerPos.Yaw = entity.ServerPos.Yaw % GameMath.TWOPI; double cosYaw = Math.Cos(entity.ServerPos.Yaw); double sinYaw = Math.Sin(entity.ServerPos.Yaw); controls.WalkVector.Set(sinYaw, GameMath.Clamp(targetVec.Y, -1, 1), cosYaw); controls.WalkVector.Mul(movingSpeed * GlobalConstants.OverallSpeedMultiplier); // Make it walk along the wall, but not walk into the wall, which causes it to climb if (entity.Properties.RotateModelOnClimb && entity.Controls.IsClimbing && entity.ClimbingOnFace != null && entity.Alive) { BlockFacing facing = entity.ClimbingOnFace; if (Math.Sign(facing.Normali.X) == Math.Sign(controls.WalkVector.X)) { controls.WalkVector.X = 0; } if (Math.Sign(facing.Normali.Z) == Math.Sign(controls.WalkVector.Z)) { controls.WalkVector.Z = 0; } } // entity.World.SpawnParticles(0.3f, ColorUtil.WhiteAhsl, target, target, new Vec3f(), new Vec3f(), 0.1f, 0.1f, 3f, EnumParticleModel.Cube); if (entity.Swimming) { controls.FlyVector.Set(controls.WalkVector); controls.FlyVector.X *= 0.85f; controls.FlyVector.Z *= 0.85f; Vec3d pos = entity.Pos.XYZ; Block inblock = entity.World.BlockAccessor.GetBlock((int)pos.X, (int)(pos.Y), (int)pos.Z); Block aboveblock = entity.World.BlockAccessor.GetBlock((int)pos.X, (int)(pos.Y + 1), (int)pos.Z); float waterY = (int)pos.Y + inblock.LiquidLevel / 8f + (aboveblock.IsLiquid() ? 9 / 8f : 0); float bottomSubmergedness = waterY - (float)pos.Y; // 0 = at swim line // 1 = completely submerged float swimlineSubmergedness = GameMath.Clamp(bottomSubmergedness - ((float)entity.SwimmingOffsetY), 0, 1); swimlineSubmergedness = Math.Min(1, swimlineSubmergedness + 0.075f); controls.FlyVector.Y = GameMath.Clamp(controls.FlyVector.Y, 0.002f, 0.004f) * swimlineSubmergedness; if (entity.CollidedHorizontally) { controls.FlyVector.Y = 0.05f; } } }