// Tick Events are called by the Network Managers public void ClientTick(float dt) { if (firstTick) { firstTick = false; mechanicalPowerMod.SendNetworkBlocksUpdateRequestToServer(this.networkId); } if (speed < 0.001f) { return; } // 50fps is baseline speed for client and server (1000/50 = 20ms) //float weirdOffset = 5f; // Server seems to complete a work item quicker than on the client, does it update the angle more quickly or something? o.O float f = dt * (50f);// + weirdOffset); clientSpeed += GameMath.Clamp(speed - clientSpeed, f * -0.01f, f * 0.01f); UpdateAngle(f * (TurnDir == EnumRotDirection.Clockwise ^ DirectionHasReversed ? clientSpeed : -clientSpeed)); // Since the server may be running at different tick speeds, // we slowly sync angle updates from server to reduce // rotation jerkiness on the client // Each tick, add 5% of server<->client angle difference float diff = f * GameMath.AngleRadDistance(angle, serverSideAngle); angle += GameMath.Clamp(diff, -0.002f * Math.Abs(diff), 0.002f * Math.Abs(diff)); }
public override void OnGameTick(float dt) { if (World.Side == EnumAppSide.Server) { base.OnGameTick(dt); return; } if (!AnimManager.ActiveAnimationsByAnimCode.ContainsKey("feed")) { if (ServerPos.Y < Pos.Y - 0.25 && !Collided) { SetAnimation("glide", 1); } else { SetAnimation("fly", 2); } } base.OnGameTick(dt); if (ServerPos.SquareDistanceTo(Pos.XYZ) > 0.01) { float desiredYaw = (float)Math.Atan2(ServerPos.X - Pos.X, ServerPos.Z - Pos.Z); float yawDist = GameMath.AngleRadDistance(LocalPos.Yaw, desiredYaw); Pos.Yaw += GameMath.Clamp(yawDist, -35 * dt, 35 * dt); Pos.Yaw = Pos.Yaw % GameMath.TWOPI; } }
private void onHurt() { var eplr = capi.World.Player.Entity; strength = eplr.WatchedAttributes.GetFloat("onHurt"); if (strength == 0 || capi.World.Player.Entity.RemainingActivityTime("invulnerable") <= 0) { return; } duration = GameMath.Clamp(200 + (int)(strength * 10), 200, 600) * 3; damangeVignettingUntil = capi.ElapsedMilliseconds + duration; float angle = eplr.WatchedAttributes.GetFloat("onHurtDir"); if (angle < -99) { capi.Render.ShaderUniforms.DamageVignettingSide = 0; } else { float angleDist = GameMath.AngleRadDistance(eplr.Pos.Yaw - GameMath.PIHALF, angle); capi.Render.ShaderUniforms.DamageVignettingSide = GameMath.Clamp(angleDist / GameMath.PIHALF, -1, 1); } }
public override bool ContinueExecute(float dt) { EntityPos own = entity.ServerPos; EntityPos his = targetEntity.ServerPos; float desiredYaw = (float)Math.Atan2(his.X - own.X, his.Z - own.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; bool correctYaw = Math.Abs(yawDist) < 20 * GameMath.DEG2RAD; if (correctYaw && !didStartAnim) { didStartAnim = true; base.StartExecute(); } if (lastCheckOrAttackMs + damagePlayerAtMs > entity.World.ElapsedMilliseconds) { return(true); } if (!damageInflicted && correctYaw) { if (!hasDirectContact(targetEntity, minDist, minVerDist)) { return(false); } bool alive = targetEntity.Alive; targetEntity.ReceiveDamage( new DamageSource() { Source = EnumDamageSource.Entity, SourceEntity = entity, Type = damageType, DamageTier = damageTier, KnockbackStrength = knockbackStrength }, damage * GlobalConstants.CreatureDamageModifier ); if (alive && !targetEntity.Alive) { bhEmo?.TryTriggerState("saturated", targetEntity.EntityId); } damageInflicted = true; } if (lastCheckOrAttackMs + attackDurationMs > entity.World.ElapsedMilliseconds) { return(true); } return(false); }
public override bool ContinueExecute(float dt) { EntityPos own = entity.ServerPos; EntityPos his = targetEntity.ServerPos; float desiredYaw = (float)Math.Atan2(his.X - own.X, his.Z - own.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; if (lastCheckOrAttackMs + damagePlayerAtMs > entity.World.ElapsedMilliseconds) { return(true); } if (!damageInflicted) { if (!hasDirectContact(targetEntity)) { return(false); } bool alive = targetEntity.Alive; entity.GetBehavior <EntityBehaviorProgram>()?.ConsumeEnergy(25); if (entity.LeftHandItemSlot.Itemstack?.Collectible.Tool != null) { damage = entity.LeftHandItemSlot.Itemstack.Collectible.GetAttackPower(entity.LeftHandItemSlot.Itemstack); damageTier = entity.LeftHandItemSlot.Itemstack.Collectible.ToolTier; } ((EntityAgent)targetEntity).ReceiveDamage( new DamageSource() { Source = EnumDamageSource.Entity, SourceEntity = prog.owner?.Entity != null ? prog.owner?.Entity : entity, Type = damageType, DamageTier = damageTier }, damage ); if (alive && !targetEntity.Alive) { this.entity.GetBehavior <EntityBehaviorEmotionStates>()?.TryTriggerState("saturated"); } damageInflicted = true; } if (lastCheckOrAttackMs + attackDurationMs > entity.World.ElapsedMilliseconds) { return(true); } return(false); }
private float[] GetFirstPersonHandsMatrix(EntityAgent entity, float[] viewMat, float deltaTime) { var modelMat = Mat4f.Invert(Mat4f.Create(), viewMat); // If the hands haven't been rendered in the last 10 render ticks, reset wobble and such. if (_renderTick - _lastTickHandsRendered > 10) { _moveWobble = 0; _lastYaw = entity.Pos.Yaw;; _yawDifference = 0; } _lastTickHandsRendered = _renderTick; if (entity.Controls.TriesToMove) { var moveSpeed = entity.Controls.MovespeedMultiplier * (float)entity.GetWalkSpeedMultiplier(); _moveWobble += moveSpeed * deltaTime * 5.0F; } else { var target = (float)(Math.Round(_moveWobble / Math.PI) * Math.PI); var speed = deltaTime * (0.2F + Math.Abs(target - _moveWobble) * 4); if (Math.Abs(target - _moveWobble) < speed) { _moveWobble = target; } else { _moveWobble += Math.Sign(target - _moveWobble) * speed; } } _moveWobble = _moveWobble % (GameMath.PI * 2); var moveWobbleOffsetX = GameMath.Sin((_moveWobble + GameMath.PI)) * 0.03F; var moveWobbleOffsetY = GameMath.Sin(_moveWobble * 2) * 0.02F; _yawDifference += GameMath.AngleRadDistance(_lastYaw, entity.Pos.Yaw); _yawDifference *= (1 - 0.075F); _lastYaw = entity.Pos.Yaw; var yawRotation = -_yawDifference / 2; var pitchRotation = (entity.Pos.Pitch - GameMath.PI) / 4; Mat4f.RotateY(modelMat, modelMat, yawRotation); Mat4f.Translate(modelMat, modelMat, 0.0F, -0.35F, -0.20F); Mat4f.RotateY(modelMat, modelMat, -yawRotation); Mat4f.RotateX(modelMat, modelMat, pitchRotation / 2); Mat4f.Translate(modelMat, modelMat, 0.0F, 0.0F, -0.20F); Mat4f.RotateX(modelMat, modelMat, pitchRotation); Mat4f.RotateY(modelMat, modelMat, yawRotation); Mat4f.Translate(modelMat, modelMat, moveWobbleOffsetX, moveWobbleOffsetY, 0.0F); Mat4f.RotateY(modelMat, modelMat, 90.0F * GameMath.DEG2RAD); return(modelMat); }
void calcSidewaysSwivelForPlayer(float dt) { double nowAngle = Math.Atan2(entity.Pos.Motion.Z, entity.Pos.Motion.X); double walkspeedsq = entity.Pos.Motion.LengthSq(); if (walkspeedsq > 0.001 && entity.OnGround) { float angledist = GameMath.AngleRadDistance((float)prevAngleSwing, (float)nowAngle); sidewaysSwivelAngle -= GameMath.Clamp(angledist, -0.05f, 0.05f) * dt * 40 * (float)Math.Min(0.025f, walkspeedsq) * 80 * (eagent?.Controls.Backward == true ? -1 : 1); sidewaysSwivelAngle = GameMath.Clamp(sidewaysSwivelAngle, -0.3f, 0.3f); } sidewaysSwivelAngle *= Math.Min(0.99f, 1 - 0.1f * dt * 60f); prevAngleSwing = nowAngle; }
public override bool ContinueExecute(float dt) { if (entity.OnGround || entity.World.Rand.NextDouble() < 0.03) { ReadjustFlyHeight(); } wanderDuration -= dt; double dy = desiredYPos - entity.ServerPos.Y; double yMot = GameMath.Clamp(dy, -1, 1); float yawDist = GameMath.AngleRadDistance(entity.ServerPos.Yaw, desiredYaw); if (!entity.FeetInLiquid) { entity.ServerPos.Yaw += GameMath.Clamp(yawDist, -curTurnRadPerSec * dt * (yMot < 0 ? 0.25f : 1), curTurnRadPerSec * dt * (yMot < 0 ? 0.25f : 1)); entity.ServerPos.Yaw = entity.ServerPos.Yaw % GameMath.TWOPI; } double cosYaw = Math.Cos(entity.ServerPos.Yaw); double sinYaw = Math.Sin(entity.ServerPos.Yaw); entity.Controls.WalkVector.Set(sinYaw, yMot, cosYaw); entity.Controls.WalkVector.Mul(moveSpeed); if (yMot < 0) { entity.Controls.WalkVector.Mul(0.75); } if (entity.Swimming) { entity.Controls.WalkVector.Y = 2 * moveSpeed; entity.Controls.FlyVector.Y = 2 * moveSpeed; } if (entity.CollidedHorizontally) { wanderDuration -= 10 * dt; } return(wanderDuration > 0); }
public override bool ContinueExecute(float dt) { Vec3f targetVec = new Vec3f(); targetVec.Set( (float)(targetEntity.ServerPos.X - entity.ServerPos.X), (float)(targetEntity.ServerPos.Y - entity.ServerPos.Y), (float)(targetEntity.ServerPos.Z - entity.ServerPos.Z) ); float desiredYaw = (float)Math.Atan2(targetVec.X, targetVec.Z); float yawDist = GameMath.AngleRadDistance(entity.ServerPos.Yaw, desiredYaw); entity.ServerPos.Yaw += GameMath.Clamp(yawDist, -curTurnRadPerSec * dt, curTurnRadPerSec * dt); entity.ServerPos.Yaw = entity.ServerPos.Yaw % GameMath.TWOPI; return(Math.Abs(yawDist) > 0.01); }
void calcSidewaysSwivelForEntity(float dt) { double dx = entity.Pos.X - prevPosXSwing; double dz = entity.Pos.Z - prevPosZSwing; double nowAngle = Math.Atan2(dz, dx); if (dx * dx + dz * dz > 0.001 && entity.OnGround) { float angledist = GameMath.AngleRadDistance((float)prevAngleSwing, (float)nowAngle); sidewaysSwivelAngle -= GameMath.Clamp(angledist, -0.05f, 0.05f) * dt * 40; // * (eagent?.Controls.Backward == true ? 1 : -1); sidewaysSwivelAngle = GameMath.Clamp(sidewaysSwivelAngle, -0.3f, 0.3f); } sidewaysSwivelAngle *= Math.Min(0.99f, 1 - 0.1f * dt * 60f); prevAngleSwing = nowAngle; prevPosXSwing = entity.Pos.X; prevPosZSwing = entity.Pos.Z; }
// Tick Events are called by the Network Managers public void ClientTick(long tickNumber) { if (speed < 0.001) { return; } clientSpeed += GameMath.Clamp(speed - clientSpeed, -0.01f, 0.01f); UpdateAngle(clientSpeed); // Since the server may be running at different tick speeds, // we slowly sync angle updates from server to reduce // rotation jerkiness on the client // Each tick, add 5% of server<->client angle difference float diff = GameMath.AngleRadDistance(angle, serverSideAngle); angle += GameMath.Clamp(diff, -0.002f * Math.Abs(diff), 0.002f * Math.Abs(diff)); }
public void loadModelMatrixForPlayer(Entity entity, bool isSelf, float dt) { EntityPlayer entityPlayer = capi.World.Player.Entity; EntityPlayer eplr = entity as EntityPlayer; Mat4f.Identity(ModelMat); if (!isSelf) { Mat4f.Translate(ModelMat, ModelMat, (float)(entity.Pos.X - entityPlayer.CameraPos.X), (float)(entity.Pos.Y - entityPlayer.CameraPos.Y), (float)(entity.Pos.Z - entityPlayer.CameraPos.Z)); } float rotX = entity.Properties.Client.Shape != null ? entity.Properties.Client.Shape.rotateX : 0; float rotY = entity.Properties.Client.Shape != null ? entity.Properties.Client.Shape.rotateY : 0; float rotZ = entity.Properties.Client.Shape != null ? entity.Properties.Client.Shape.rotateZ : 0; float bodyYaw = 0; if (eagent != null) { float yawDist = GameMath.AngleRadDistance(bodyYawLerped, eagent.BodyYaw); bodyYawLerped += GameMath.Clamp(yawDist, -dt * 8, dt * 8); bodyYaw = bodyYawLerped; } float bodyPitch = eplr == null ? 0 : eplr.WalkPitch; Mat4f.RotateX(ModelMat, ModelMat, entity.Pos.Roll + rotX * GameMath.DEG2RAD); Mat4f.RotateY(ModelMat, ModelMat, bodyYaw + (180 + rotY) * GameMath.DEG2RAD); Mat4f.RotateZ(ModelMat, ModelMat, bodyPitch + rotZ * GameMath.DEG2RAD); //float str = (float)entity.Pos.Motion.Length(); //Mat4f.RotateX(ModelMat, ModelMat, eplr.Controls.Left ? str : -str); float scale = entity.Properties.Client.Size; Mat4f.Scale(ModelMat, ModelMat, new float[] { scale, scale, scale }); Mat4f.Translate(ModelMat, ModelMat, -0.5f, 0, -0.5f); }
public override void OnReceivedServerPos(bool isTeleport, ref EnumHandling handled) { // Don't interpolate for ourselves if (entity == ((IClientWorldAccessor)entity.World).Player.Entity) { return; } handled = EnumHandling.PreventDefault; posDiffX = entity.ServerPos.X - entity.Pos.X; posDiffY = entity.ServerPos.Y - entity.Pos.Y; posDiffZ = entity.ServerPos.Z - entity.Pos.Z; rollDiff = GameMath.AngleRadDistance(entity.Pos.Roll, entity.ServerPos.Roll); pitchDiff = GameMath.AngleRadDistance(entity.Pos.Pitch, entity.ServerPos.Pitch); headpitchDiff = GameMath.AngleRadDistance(entity.Pos.HeadPitch, entity.ServerPos.HeadPitch); serverposApplied = false; accum = 0; }
public override void OnGameTick(float deltaTime) { long nowEllapsedMillisecond = entity.World.ElapsedMilliseconds; long serverPosAgeMs = nowEllapsedMillisecond - lastServerPosMilliseconds; // Lag. Stop extrapolation (extrapolation begins after 200ms) if (serverPosAgeMs > 220) { return; } //if (entity.ServerPos.Motion.LengthSq() == 0) return; double percent = (nowEllapsedMillisecond - lastGameMs) / 200.0; int signPX = Math.Sign(posDiffX); int signPY = Math.Sign(posDiffY); int signPZ = Math.Sign(posDiffZ); entity.Pos.X += GameMath.Clamp(entity.ServerPos.X - entity.Pos.X, -signPX * percent * posDiffX, signPX * percent * posDiffX); entity.Pos.Y += GameMath.Clamp(entity.ServerPos.Y - entity.Pos.Y, -signPY * percent * posDiffY, signPY * percent * posDiffY); entity.Pos.Z += GameMath.Clamp(entity.ServerPos.Z - entity.Pos.Z, -signPZ * percent * posDiffZ, signPZ * percent * posDiffZ); int signR = Math.Sign(rollDiff); int signY = Math.Sign(yawDiff); int signP = Math.Sign(pitchDiff); // Dunno why the 0.7, but it's too fast otherwise entity.Pos.Roll += 0.7f * (float)GameMath.Clamp(entity.ServerPos.Roll - entity.Pos.Roll, -signR * percent * rollDiff, signR * percent * rollDiff); entity.Pos.Yaw += 0.7f * (float)GameMath.Clamp(GameMath.AngleRadDistance(entity.Pos.Yaw, entity.ServerPos.Yaw), -signY * percent * yawDiff, signY * percent * yawDiff); entity.Pos.Yaw = entity.Pos.Yaw % GameMath.TWOPI; entity.Pos.Pitch += 0.7f * (float)GameMath.Clamp(GameMath.AngleRadDistance(entity.Pos.Pitch, entity.ServerPos.Pitch), -signP * percent * pitchDiff, signP * percent * pitchDiff); entity.Pos.Pitch = entity.Pos.Pitch % GameMath.TWOPI; lastGameMs = nowEllapsedMillisecond; }
public override bool ContinueExecute(float dt) { if (entity.OnGround || entity.World.Rand.NextDouble() < 0.03) { ReadjustFlyHeight(); } wanderDuration -= dt; float yawDist = GameMath.AngleRadDistance(entity.ServerPos.Yaw, desiredYaw); entity.ServerPos.Yaw += GameMath.Clamp(yawDist, -curTurnRadPerSec * dt, curTurnRadPerSec * dt); entity.ServerPos.Yaw = entity.ServerPos.Yaw % GameMath.TWOPI; double cosYaw = Math.Cos(entity.ServerPos.Yaw); double sinYaw = Math.Sin(entity.ServerPos.Yaw); entity.Controls.WalkVector.Set(sinYaw, desiredYMotion, cosYaw); entity.Controls.WalkVector.Mul(moveSpeed); if (entity.Swimming) { entity.Controls.WalkVector.Y = -2 * moveSpeed; } if (entity.CollidedHorizontally) { wanderDuration -= 10 * dt; } return(wanderDuration > 0); }
public override void OnGameTick(float dt) { if (asyncSearchObject != null) { if (!asyncSearchObject.Finished) { return; } AfterFoundPath(); } if (!Active) { return; } bool nearHorizontally = false; int offset = 0; bool nearAllDirs = IsNearTarget(offset++, ref nearHorizontally) || IsNearTarget(offset++, ref nearHorizontally) || IsNearTarget(offset++, ref nearHorizontally) ; if (nearAllDirs) { waypointToReachIndex += offset; lastWaypointIncTotalMs = entity.World.ElapsedMilliseconds; } target = waypoints[Math.Min(waypoints.Count - 1, waypointToReachIndex)]; bool onlastWaypoint = waypointToReachIndex == waypoints.Count - 1; if (waypointToReachIndex >= waypoints.Count) { Stop(); OnGoalReached?.Invoke(); return; } bool stuck = (entity.CollidedVertically && entity.Controls.IsClimbing) || (entity.CollidedHorizontally && entity.ServerPos.Motion.Y <= 0) || (nearHorizontally && !nearAllDirs && entity.Properties.Habitat == EnumHabitat.Land) || (entity.CollidedHorizontally && waypoints.Count > 1 && waypointToReachIndex < waypoints.Count && entity.World.ElapsedMilliseconds - lastWaypointIncTotalMs > 2000) // If it takes more than 2 seconds to reach next waypoint (waypoints are always 1 block apart) //|| (entity.Swimming && false) ; // This used to test motion, but that makes no sense, we want to test if the entity moved, not if it had motion double distsq = prevPrevPos.SquareDistanceTo(prevPos); stuck |= (distsq < 0.01 * 0.01) ? (entity.World.Rand.NextDouble() < GameMath.Clamp(1 - distsq * 1.2, 0.1, 0.9)) : false; // Test movement progress between two points in 150 millisecond intervalls prevPosAccum += dt; if (prevPosAccum > 0.2) { prevPosAccum = 0; prevPrevPos.Set(prevPos); prevPos.Set(entity.ServerPos.X, entity.ServerPos.Y, entity.ServerPos.Z); } // Long duration tests to make sure we're not just wobbling around in the same spot distCheckAccum += dt; if (distCheckAccum > 2) { distCheckAccum = 0; if (sqDistToTarget - lastDistToTarget < 0.1) { stuck = true; stuckCounter += 30; } else if (!stuck) { stuckCounter = 0; // Only reset the stuckCounter in same tick as doing this test; otherwise the stuckCounter gets set to 0 every 2 or 3 ticks even if the entity collided horizontally (because motion vecs get set to 0 after the collision, so won't collide in the successive tick) } lastDistToTarget = sqDistToTarget; } if (stuck) { stuckCounter++; } if (GlobalConstants.OverallSpeedMultiplier > 0 && stuckCounter > 40 / 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) ); targetVec.Normalize(); float desiredYaw = 0; if (sqDistToTarget >= 0.01) { desiredYaw = (float)Math.Atan2(targetVec.X, targetVec.Z); } float nowMoveSpeed = movingSpeed; if (sqDistToTarget < 1) { nowMoveSpeed = Math.Max(0.005f, movingSpeed * Math.Max(sqDistToTarget, 0.2f)); } float yawDist = GameMath.AngleRadDistance(entity.ServerPos.Yaw, desiredYaw); float turnSpeed = curTurnRadPerSec * dt * GlobalConstants.OverallSpeedMultiplier * movingSpeed; entity.ServerPos.Yaw += GameMath.Clamp(yawDist, -turnSpeed, turnSpeed); 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(nowMoveSpeed * 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.ClimbingIntoFace != null && entity.Alive) { BlockFacing facing = entity.ClimbingIntoFace; if (Math.Sign(facing.Normali.X) == Math.Sign(controls.WalkVector.X)) { controls.WalkVector.X = 0; } if (Math.Sign(facing.Normali.Y) == Math.Sign(controls.WalkVector.Y)) { controls.WalkVector.Y = -controls.WalkVector.Y; } 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.Properties.Habitat == EnumHabitat.Underwater) { controls.FlyVector.Set(controls.WalkVector); Vec3d pos = entity.Pos.XYZ; Block inblock = entity.World.BlockAccessor.GetLiquidBlock((int)pos.X, (int)(pos.Y), (int)pos.Z); Block aboveblock = entity.World.BlockAccessor.GetLiquidBlock((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 = 1f - Math.Min(1f, swimlineSubmergedness + 0.5f); if (swimlineSubmergedness > 0f) { //Push the fish back underwater if part is poking out ... (may need future adaptation for sharks[?], probably by changing SwimmingOffsetY) controls.FlyVector.Y = GameMath.Clamp(controls.FlyVector.Y, -0.04f, -0.02f) * (1f - swimlineSubmergedness); } else { float factor = movingSpeed * GlobalConstants.OverallSpeedMultiplier / (float)Math.Sqrt(targetVec.X * targetVec.X + targetVec.Z * targetVec.Z); controls.FlyVector.Y = targetVec.Y * factor; } if (entity.CollidedHorizontally) { //TODO } } else if (entity.Swimming) { controls.FlyVector.Set(controls.WalkVector); Vec3d pos = entity.Pos.XYZ; Block inblock = entity.World.BlockAccessor.GetLiquidBlock((int)pos.X, (int)(pos.Y), (int)pos.Z); Block aboveblock = entity.World.BlockAccessor.GetLiquidBlock((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.5f); controls.FlyVector.Y = GameMath.Clamp(controls.FlyVector.Y, 0.02f, 0.04f) * swimlineSubmergedness; if (entity.CollidedHorizontally) { controls.FlyVector.Y = 0.05f; } } }
public override void OnFrame(float dt) { if (this.player == null) { this.player = entityPlayer.Player; } float diff = GameMath.AngleRadDistance(entity.BodyYaw, entity.Pos.Yaw); if (Math.Abs(diff) > GameMath.PIHALF * 1.2f) { turnOpposite = true; } if (turnOpposite) { if (Math.Abs(diff) < GameMath.PIHALF * 0.9f) { turnOpposite = false; } else { diff = 0; } } entity.HeadYaw += (diff - entity.HeadYaw) * dt * 6; entity.HeadYaw = GameMath.Clamp(entity.HeadYaw, -0.75f, 0.75f); entity.HeadPitch = GameMath.Clamp((entity.Pos.Pitch - GameMath.PI) * 0.75f, -1.2f, 1.2f); if (player?.Entity == null || player.Entity.MountedOn != null || (player as IClientPlayer).CameraMode == EnumCameraMode.Overhead) { entity.BodyYaw = entity.Pos.Yaw; } else { float yawDist = GameMath.AngleRadDistance(entity.BodyYaw, entity.Pos.Yaw); bool ismoving = player.Entity.Controls.TriesToMove || player.Entity.ServerControls.TriesToMove; bool attachedToClimbWall = false;// player.Entity.Controls.IsClimbing && player.Entity.Controls.IsClimbing && (entity.BodyYaw - player.Entity.ClimbingOnFace.HorizontalAngleIndex * 90 * GameMath.DEG2RAD) < 0.02; float threshold = 1f - (ismoving ? 0.99f : 0) + (attachedToClimbWall ? 3 : 0); ICoreClientAPI capi = entity.Api as ICoreClientAPI; if (player.PlayerUID == capi.World.Player.PlayerUID && capi.Settings.Bool["immersiveFpMode"] && false) { entity.BodyYaw = entity.Pos.Yaw; } else { if (Math.Abs(yawDist) > threshold || rotateTpYawNow) { float speed = 0.05f + Math.Abs(yawDist) * 3.5f; entity.BodyYaw += GameMath.Clamp(yawDist, -dt * speed, dt * speed); rotateTpYawNow = Math.Abs(yawDist) > 0.01f; } } } base.OnFrame(dt); }
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 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; // 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, -10 * dt, 10 * dt); 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, 2 * dt); entityplayer.WalkPitch = GameMath.Mod(entityplayer.WalkPitch, GameMath.TWOPI); //Console.WriteLine(entityplayer.WalkPitch); } else { entityplayer.WalkPitch = 0; } } else { controls.CalcMovementVectors(pos, dt); } TickEntityPhysics(pos, controls, dt); }
public override void OnGameTick(float dt) { if (!Active) { return; } int wayPointIndex = Math.Min(waypoints.Count - 1, waypointToReachIndex); Vec3d target = waypoints[wayPointIndex]; // Due to the nature of gravity and going down slope we sometimes end up at the next waypoint. So lets also test for the next waypoint // Doesn't seem to fully fix the issue though int nextwayPointIndex = Math.Min(waypoints.Count - 1, waypointToReachIndex + 1); Vec3d nexttarget = waypoints[nextwayPointIndex]; // For land dwellers only check horizontal distance double sqDistToTarget = Math.Min(target.SquareDistanceTo(entity.ServerPos.X, entity.ServerPos.Y, entity.ServerPos.Z), target.SquareDistanceTo(entity.ServerPos.X, entity.ServerPos.Y + 1, entity.ServerPos.Z)); // One block above is also ok double horsqDistToTarget = target.HorizontalSquareDistanceTo(entity.ServerPos.X, entity.ServerPos.Z); double sqDistToNextTarget = Math.Min(nexttarget.SquareDistanceTo(entity.ServerPos.X, entity.ServerPos.Y, entity.ServerPos.Z), nexttarget.SquareDistanceTo(entity.ServerPos.X, entity.ServerPos.Y + 1, entity.ServerPos.Z)); // One block above is also ok bool nearHorizontally = horsqDistToTarget < 1; bool nearAllDirs = sqDistToTarget < targetDistance * targetDistance; bool nearAllDirsNext = sqDistToNextTarget < targetDistance * targetDistance; //float speedMul = 1;// entity.Properties.Habitat == API.Common.EnumHabitat.Land && waypointToReachIndex >= waypoints.Count - 1 ? Math.Min(1, GameMath.Sqrt(horsqDistToTarget)) : 1; //Console.WriteLine(speedMul); if (nearAllDirs || nearAllDirsNext) { waypointToReachIndex++; if (nearAllDirsNext && wayPointIndex != nextwayPointIndex) { waypointToReachIndex++; } lastWaypointIncTotalMs = entity.World.ElapsedMilliseconds; if (waypointToReachIndex >= waypoints.Count) { Stop(); OnGoalReached?.Invoke(); return; } else { target = waypoints[waypointToReachIndex]; } } 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) || (nearHorizontally && !nearAllDirs && entity.Properties.Habitat == API.Common.EnumHabitat.Land) || (waypoints.Count > 1 && waypointToReachIndex < waypoints.Count && entity.World.ElapsedMilliseconds - lastWaypointIncTotalMs > 2000) // If it takes more than 2 seconds to reach next waypoint (waypoints are always 1 block apart) ; prevPos.Set(entity.ServerPos.X, entity.ServerPos.Y, entity.ServerPos.Z); stuckCounter = stuck ? (stuckCounter + 1) : 0; if (GlobalConstants.OverallSpeedMultiplier > 0 && stuckCounter > 60 / 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);// * speedMul); // 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); 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.5f); controls.FlyVector.Y = GameMath.Clamp(controls.FlyVector.Y, 0.02f, 0.04f) * swimlineSubmergedness; if (entity.CollidedHorizontally) { controls.FlyVector.Y = 0.05f; } } }
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; } } }
public void OnRenderFrame(float deltaTime, EnumRenderStage stage) { // Don't interpolate for ourselves if (entity == ((IClientWorldAccessor)entity.World).Player.Entity) { return; } float interval = 0.2f; accum += deltaTime; if (accum > interval || !(entity is EntityAgent)) { posDiffX = entity.ServerPos.X - entity.Pos.X; posDiffY = entity.ServerPos.Y - entity.Pos.Y; posDiffZ = entity.ServerPos.Z - entity.Pos.Z; rollDiff = entity.ServerPos.Roll - entity.Pos.Roll; yawDiff = entity.ServerPos.Yaw - entity.Pos.Yaw; pitchDiff = entity.ServerPos.Pitch - entity.Pos.Pitch; // "|| accum > 1" mitigates items at the edge of block constantly jumping up and down if (entity.ServerPos.BasicallySameAsIgnoreMotion(entity.Pos, 0.05f) || accum > 1) { if (!serverposApplied) { entity.Pos.SetPos(entity.ServerPos); } serverposApplied = true; return; } } double percentPosx = Math.Abs(posDiffX) * deltaTime / interval; double percentPosy = Math.Abs(posDiffY) * deltaTime / interval; double percentPosz = Math.Abs(posDiffZ) * deltaTime / interval; double percentyawdiff = Math.Abs(yawDiff) * deltaTime / interval; double percentrolldiff = Math.Abs(rollDiff) * deltaTime / interval; double percentpitchdiff = Math.Abs(pitchDiff) * deltaTime / interval; int signPX = Math.Sign(percentPosx); int signPY = Math.Sign(percentPosy); int signPZ = Math.Sign(percentPosz); entity.Pos.X += GameMath.Clamp(posDiffX, -signPX * percentPosx, signPX * percentPosx); entity.Pos.Y += GameMath.Clamp(posDiffY, -signPY * percentPosy, signPY * percentPosy); entity.Pos.Z += GameMath.Clamp(posDiffZ, -signPZ * percentPosz, signPZ * percentPosz); int signR = Math.Sign(percentrolldiff); int signY = Math.Sign(percentyawdiff); int signP = Math.Sign(percentpitchdiff); // Dunno why the 0.7, but it's too fast otherwise entity.Pos.Roll += 0.7f * (float)GameMath.Clamp(rollDiff, -signR * percentrolldiff, signR * percentrolldiff); entity.Pos.Yaw += 0.7f * (float)GameMath.Clamp(GameMath.AngleRadDistance(entity.Pos.Yaw, entity.ServerPos.Yaw), -signY * percentyawdiff, signY * percentyawdiff); entity.Pos.Yaw = entity.Pos.Yaw % GameMath.TWOPI; entity.Pos.Pitch += 0.7f * (float)GameMath.Clamp(GameMath.AngleRadDistance(entity.Pos.Pitch, entity.ServerPos.Pitch), -signP * percentpitchdiff, signP * percentpitchdiff); entity.Pos.Pitch = entity.Pos.Pitch % GameMath.TWOPI; }
private float handleDamaged(IPlayer player, float damage, DamageSource dmgSource) { EnumDamageType type = dmgSource.Type; double angleProtectionRange = 120 / 2 * GameMath.DEG2RAD; // Reduce damage if player holds a shield ItemSlot[] shieldSlots = new ItemSlot[] { player.Entity.LeftHandItemSlot, player.Entity.RightHandItemSlot }; foreach (var shieldSlot in shieldSlots) { var attr = shieldSlot.Itemstack?.ItemAttributes?["shield"]; if (attr == null || !attr.Exists) { continue; } string usetype = player.Entity.Controls.Sneak ? "active" : "passive"; float dmgabsorb = attr["damageAbsorption"][usetype].AsFloat(0); float chance = attr["protectionChance"][usetype].AsFloat(0); (player as IServerPlayer)?.SendMessage(GlobalConstants.DamageLogChatGroup, Lang.Get("{0:0.#} of {1:0.#} damage blocked by shield", Math.Min(dmgabsorb, damage), damage), EnumChatType.Notification); double dx; double dz; if (dmgSource.HitPosition != null) { dx = dmgSource.HitPosition.X; dz = dmgSource.HitPosition.Z; } else if (dmgSource.SourceEntity != null) { dx = dmgSource.SourceEntity.Pos.X - player.Entity.Pos.X; dz = dmgSource.SourceEntity.Pos.Z - player.Entity.Pos.Z; } else if (dmgSource.SourcePos != null) { dx = dmgSource.SourcePos.X - player.Entity.Pos.X; dz = dmgSource.SourcePos.Z - player.Entity.Pos.Z; } else { break; } double attackYaw = Math.Atan2((double)dx, (double)dz); double playerYaw = player.Entity.Pos.Yaw + GameMath.PIHALF; bool inProtectionRange = Math.Abs(GameMath.AngleRadDistance((float)playerYaw, (float)attackYaw)) < angleProtectionRange; if (inProtectionRange && api.World.Rand.NextDouble() < chance) { damage = Math.Max(0, damage - dmgabsorb); var loc = shieldSlot.Itemstack.ItemAttributes["blockSound"].AsString("held/shieldblock"); api.World.PlaySoundAt(AssetLocation.Create(loc, shieldSlot.Itemstack.Collectible.Code.Domain).WithPathPrefixOnce("sounds/").WithPathAppendixOnce(".ogg"), player, null); if (api.Side == EnumAppSide.Server) { shieldSlot.Itemstack.Collectible.DamageItem(api.World, dmgSource.SourceEntity, shieldSlot, 1); shieldSlot.MarkDirty(); } } } if (damage <= 0) { return(0); } // The code below only the server needs to execute if (api.Side == EnumAppSide.Client) { return(damage); } // Does not protect against non-attack damages if (type != EnumDamageType.BluntAttack && type != EnumDamageType.PiercingAttack && type != EnumDamageType.SlashingAttack) { return(damage); } if (dmgSource.Source == EnumDamageSource.Internal || dmgSource.Source == EnumDamageSource.Suicide) { return(damage); } ItemSlot armorSlot; IInventory inv = player.InventoryManager.GetOwnInventory(GlobalConstants.characterInvClassName); double rnd = api.World.Rand.NextDouble(); int attackTarget; if ((rnd -= 0.2) < 0) { // Head armorSlot = inv[12]; attackTarget = 0; } else if ((rnd -= 0.5) < 0) { // Body armorSlot = inv[13]; attackTarget = 1; } else { // Legs armorSlot = inv[14]; attackTarget = 2; } // Apply full damage if no armor is in this slot if (armorSlot.Empty || !(armorSlot.Itemstack.Item is ItemWearable)) { EnumCharacterDressType[] dressTargets = clothingDamageTargetsByAttackTacket[attackTarget]; EnumCharacterDressType target = dressTargets[api.World.Rand.Next(dressTargets.Length)]; ItemSlot targetslot = player.Entity.GearInventory[(int)target]; if (!targetslot.Empty) { // Wolf: 10 hp damage = 10% condition loss // Ram: 10 hp damage = 2.5% condition loss // Bronze locust: 10 hp damage = 5% condition loss float mul = 0.25f; if (type == EnumDamageType.SlashingAttack) { mul = 1f; } if (type == EnumDamageType.PiercingAttack) { mul = 0.5f; } float diff = -damage / 100 * mul; if (Math.Abs(diff) > 0.05) { api.World.PlaySoundAt(ripSound, player.Entity); } (targetslot.Itemstack.Collectible as ItemWearable)?.ChangeCondition(targetslot, diff); } return(damage); } ProtectionModifiers protMods = (armorSlot.Itemstack.Item as ItemWearable).ProtectionModifiers; int weaponTier = dmgSource.DamageTier; float flatDmgProt = protMods.FlatDamageReduction; float percentProt = protMods.RelativeProtection; for (int tier = 1; tier <= weaponTier; tier++) { bool aboveTier = tier > protMods.ProtectionTier; float flatLoss = aboveTier ? protMods.PerTierFlatDamageReductionLoss[1] : protMods.PerTierFlatDamageReductionLoss[0]; float percLoss = aboveTier ? protMods.PerTierRelativeProtectionLoss[1] : protMods.PerTierRelativeProtectionLoss[0]; if (aboveTier && protMods.HighDamageTierResistant) { flatLoss /= 2; percLoss /= 2; } flatDmgProt -= flatLoss; percentProt *= 1 - percLoss; } // Durability loss is the one before the damage reductions float durabilityLoss = 0.5f + damage * Math.Max(0.5f, (weaponTier - protMods.ProtectionTier) * 3); int durabilityLossInt = GameMath.RoundRandom(api.World.Rand, durabilityLoss); // Now reduce the damage damage = Math.Max(0, damage - flatDmgProt); damage *= 1 - Math.Max(0, percentProt); armorSlot.Itemstack.Collectible.DamageItem(api.World, player.Entity, armorSlot, durabilityLossInt); if (armorSlot.Empty) { api.World.PlaySoundAt(new AssetLocation("sounds/effect/toolbreak"), player); } return(damage); }
public override void BeforeRender(float dt) { if (meshRefOpaque == null && meshRefOit == null) { return; } if (capi.IsGamePaused) { return; } if (HeadControl && player == null && entity is EntityPlayer) { player = capi.World.PlayerByUid((entity as EntityPlayer).PlayerUID); } isSpectator = player != null && player.WorldData.CurrentGameMode == EnumGameMode.Spectator; if (isSpectator) { return; } curAnimator.FastMode = !DoRenderHeldItem && !capi.Settings.Bool["highQualityAnimations"]; if (DisplayChatMessages && messageTextures.Count > 0) { MessageTexture tex = messageTextures.Last(); if (capi.World.ElapsedMilliseconds > tex.receivedTime + 3500 + 100 * (tex.message.Length - 10)) { messageTextures.RemoveAt(messageTextures.Count - 1); tex.tex.Dispose(); if (messageTextures.Count > 0) { tex = messageTextures[messageTextures.Count - 1]; long msvisible = tex.receivedTime + 3500 + 100 * (tex.message.Length - 10) - capi.World.ElapsedMilliseconds; tex.receivedTime += Math.Max(0, 1000 - msvisible); } } } if (HeadControl) { /*if (player == api.World.Player && api.Render.CameraType == EnumCameraMode.FirstPerson) * { * AttachmentPointAndPose apap = null; * curAnimator.AttachmentPointByCode.TryGetValue("Eyes", out apap); * float[] tmpMat = Mat4f.Create(); * * for (int i = 0; i < 16; i++) tmpMat[i] = ModelMat[i]; * AttachmentPoint ap = apap.AttachPoint; * * float[] mat = apap.Pose.AnimModelMatrix; * Mat4f.Mul(tmpMat, tmpMat, mat); * * Mat4f.Translate(tmpMat, tmpMat, (float)ap.PosX / 16f, (float)ap.PosY / 16f, (float)ap.PosZ / 16f); * Mat4f.RotateX(tmpMat, tmpMat, (float)(ap.RotationX) * GameMath.DEG2RAD); * Mat4f.RotateY(tmpMat, tmpMat, (float)(ap.RotationY) * GameMath.DEG2RAD); * Mat4f.RotateZ(tmpMat, tmpMat, (float)(ap.RotationZ) * GameMath.DEG2RAD); * float[] vec = new float[] { 0,0,0, 0 }; * float[] outvec = Mat4f.MulWithVec4(tmpMat, vec); * * api.Render.CameraOffset.Translation.Set(outvec[0], outvec[1] + 1, outvec[2]); * }*/ float diff = GameMath.AngleRadDistance(bodyYaw, entity.Pos.Yaw); if (Math.Abs(diff) > GameMath.PIHALF * 1.2f) { opposite = true; } if (opposite) { if (Math.Abs(diff) < GameMath.PIHALF * 0.9f) { opposite = false; } else { diff = 0; } } headYaw += (diff - headYaw) * dt * 6; headYaw = GameMath.Clamp(headYaw, -0.75f, 0.75f); curAnimator.HeadYaw = headYaw; curAnimator.HeadPitch = GameMath.Clamp((entity.Pos.Pitch - GameMath.PI) * 0.75f, -1.2f, 1.2f); if (capi.World.Player.CameraMode == EnumCameraMode.Overhead || capi.World.Player.Entity.MountedOn != null) { bodyYaw = entity.Pos.Yaw; } else { float yawDist = GameMath.AngleRadDistance(bodyYaw, entity.Pos.Yaw); if (Math.Abs(yawDist) > 1f - (capi.World.Player.Entity.Controls.TriesToMove ? 0.99f : 0) || rotateTpYawNow) { bodyYaw += GameMath.Clamp(yawDist, -dt * 3, dt * 3); rotateTpYawNow = Math.Abs(yawDist) > 0.01f; } } } else { curAnimator.HeadYaw = entity.Pos.Yaw; curAnimator.HeadPitch = entity.Pos.Pitch; } curAnimator.OnFrame(dt); }
public void OnRenderFrame(float deltaTime, EnumRenderStage stage) { // Don't interpolate for ourselves if (entity == ((IClientWorldAccessor)entity.World).Player.Entity) { return; } if ((entity.World.Api as ICoreClientAPI).IsGamePaused) { return; } // When mounted, the entities position is set by the physics sim bool isMounted = (entity as EntityAgent)?.MountedOn != null; float interval = 0.2f; accum += deltaTime; if (accum > interval * 2 || !(entity is EntityAgent)) { posDiffX = entity.ServerPos.X - entity.Pos.X; posDiffY = entity.ServerPos.Y - entity.Pos.Y; posDiffZ = entity.ServerPos.Z - entity.Pos.Z; rollDiff = entity.ServerPos.Roll - entity.Pos.Roll; //yawDiff = entity.ServerPos.Yaw - entity.Pos.Yaw; pitchDiff = entity.ServerPos.Pitch - entity.Pos.Pitch; double posDiffSq = posDiffX * posDiffX + posDiffY * posDiffY + posDiffZ * posDiffZ; // "|| accum > 1" mitigates items at the edge of block constantly jumping up and down if (entity.ServerPos.BasicallySameAsIgnoreMotion(entity.Pos, 0.05f) || (accum > 1 && posDiffSq < 0.1 * 0.1)) { if (!serverposApplied && !isMounted) { entity.Pos.SetPos(entity.ServerPos); } serverposApplied = true; return; } } double percentPosx = Math.Abs(posDiffX) * deltaTime / interval; double percentPosy = Math.Abs(posDiffY) * deltaTime / interval; double percentPosz = Math.Abs(posDiffZ) * deltaTime / interval; double percentyawdiff = Math.Abs(GameMath.AngleRadDistance(entity.Pos.Yaw, entity.ServerPos.Yaw)) * deltaTime / interval; double percentheadyawdiff = Math.Abs(GameMath.AngleRadDistance(entity.Pos.HeadYaw, entity.ServerPos.HeadYaw)) * deltaTime / interval; double percentrolldiff = Math.Abs(rollDiff) * deltaTime / interval; double percentpitchdiff = Math.Abs(pitchDiff) * deltaTime / interval; double percentheadpitchdiff = Math.Abs(headpitchDiff) * deltaTime / interval; int signPX = Math.Sign(percentPosx); int signPY = Math.Sign(percentPosy); int signPZ = Math.Sign(percentPosz); if (!isMounted) { entity.Pos.X += GameMath.Clamp(posDiffX, -signPX * percentPosx, signPX * percentPosx); entity.Pos.Y += GameMath.Clamp(posDiffY, -signPY * percentPosy, signPY * percentPosy); entity.Pos.Z += GameMath.Clamp(posDiffZ, -signPZ * percentPosz, signPZ * percentPosz); } int signR = Math.Sign(percentrolldiff); int signY = Math.Sign(percentyawdiff); int signP = Math.Sign(percentpitchdiff); int signHY = Math.Sign(percentheadyawdiff); int signHP = Math.Sign(percentheadpitchdiff); // Dunno why the 0.7, but it's too fast otherwise entity.Pos.Roll += 0.7f * (float)GameMath.Clamp(rollDiff, -signR * percentrolldiff, signR * percentrolldiff); entity.Pos.Yaw += 0.7f * (float)GameMath.Clamp(GameMath.AngleRadDistance(entity.Pos.Yaw, entity.ServerPos.Yaw), -signY * percentyawdiff, signY * percentyawdiff); entity.Pos.Yaw = entity.Pos.Yaw % GameMath.TWOPI; entity.Pos.Pitch += 0.7f * (float)GameMath.Clamp(GameMath.AngleRadDistance(entity.Pos.Pitch, entity.ServerPos.Pitch), -signP * percentpitchdiff, signP * percentpitchdiff); entity.Pos.Pitch = entity.Pos.Pitch % GameMath.TWOPI; entity.Pos.HeadYaw += 0.7f * (float)GameMath.Clamp(GameMath.AngleRadDistance(entity.Pos.HeadYaw, entity.ServerPos.HeadYaw), -signHY * percentheadyawdiff, signHY * percentheadyawdiff); entity.Pos.HeadYaw = entity.Pos.HeadYaw % GameMath.TWOPI; entity.Pos.HeadPitch += 0.7f * (float)GameMath.Clamp(GameMath.AngleRadDistance(entity.Pos.HeadPitch, entity.ServerPos.HeadPitch), -signHP * percentheadpitchdiff, signHP * percentheadpitchdiff); entity.Pos.HeadPitch = entity.Pos.HeadPitch % GameMath.TWOPI; if (entity is EntityAgent eagent) { double percentbodyyawdiff = Math.Abs(GameMath.AngleRadDistance(eagent.BodyYaw, eagent.BodyYawServer)) * deltaTime / interval; int signBY = Math.Sign(percentbodyyawdiff); eagent.BodyYaw += 0.7f * (float)GameMath.Clamp(GameMath.AngleRadDistance(eagent.BodyYaw, eagent.BodyYawServer), -signBY * percentbodyyawdiff, signBY * percentbodyyawdiff); eagent.BodyYaw = eagent.BodyYaw % GameMath.TWOPI; } }
public override void OnGameTick(float dt) { if (World.Side == EnumAppSide.Server) { base.OnGameTick(dt); return; } if (!AnimManager.ActiveAnimationsByAnimCode.ContainsKey("feed") && !AnimManager.ActiveAnimationsByAnimCode.ContainsKey("rest")) { if (ServerPos.Y < Pos.Y - 0.05 && !Collided) { SetAnimation("glide", 1); } if ((ServerPos.Y > Pos.Y - 0.02 || Collided) && !FeetInLiquid) { SetAnimation("fly", 2.5f); } if (FeetInLiquid) { (Properties.Client.Renderer as EntityShapeRenderer).AddRenderFlags |= 1 << 12; } else { (Properties.Client.Renderer as EntityShapeRenderer).AddRenderFlags &= ~(1 << 12); } if (FeetInLiquid && flapPauseDt <= 0 && Api.World.Rand.NextDouble() < 0.07) { flapPauseDt = 2 + 6 * (float)Api.World.Rand.NextDouble(); StopAnimation("fly"); } if (flapPauseDt > 0) { flapPauseDt -= dt; if (flapPauseDt <= 0) { SetAnimation("fly", 2.5f); } } else { if (FeetInLiquid) { EntityPos herepos = Pos; double width = SelectionBox.XSize * 0.75f; SplashParticleProps.BasePos.Set(herepos.X - width / 2, herepos.Y - 0.05, herepos.Z - width / 2); SplashParticleProps.AddPos.Set(width, 0, width); SplashParticleProps.AddVelocity.Set(0, 0, 0); SplashParticleProps.QuantityMul = 0.01f; World.SpawnParticles(SplashParticleProps); SpawnWaterMovementParticles(1, 0, +0.05, 0); } } } base.OnGameTick(dt); if (cnt++ > 30) { float affectedness = World.BlockAccessor.GetLightLevel(SidedPos.XYZ.AsBlockPos, EnumLightLevelType.OnlySunLight) < 14 ? 1 : 0; windMotion = Api.ModLoader.GetModSystem <WeatherSystemBase>().WeatherDataSlowAccess.GetWindSpeed(SidedPos.XYZ) * affectedness; cnt = 0; } if (AnimManager.ActiveAnimationsByAnimCode.ContainsKey("fly")) { SidedPos.X += Math.Max(0, (windMotion - 0.2) / 20.0); } if (ServerPos.SquareDistanceTo(Pos.XYZ) > 0.01 && !FeetInLiquid) { float desiredYaw = (float)Math.Atan2(ServerPos.X - Pos.X, ServerPos.Z - Pos.Z); float yawDist = GameMath.AngleRadDistance(SidedPos.Yaw, desiredYaw); Pos.Yaw += GameMath.Clamp(yawDist, -35 * dt, 35 * dt); Pos.Yaw = Pos.Yaw % GameMath.TWOPI; } }
public override bool ContinueExecute(float dt) { if (!(entity.LeftHandItemSlot.Itemstack?.Collectible is ItemArrow)) { return(false); } float dx = (float)(targetEntity.ServerPos.X - entity.ServerPos.X); float dy = (float)((targetEntity.ServerPos.Y + targetEntity.LocalEyePos.Y) - (entity.ServerPos.Y + (entity.LocalEyePos.Y - 0.2))); float dz = (float)(targetEntity.ServerPos.Z - entity.ServerPos.Z); float desiredYaw = (float)Math.Atan2(dx, dz); float yawDist = GameMath.AngleRadDistance(entity.ServerPos.Yaw, desiredYaw); entity.ServerPos.Yaw += yawDist; entity.ServerPos.Yaw = entity.ServerPos.Yaw % GameMath.TWOPI; float pitch = entity.ServerPos.Pitch; float desiredPitch = (float)Math.Atan2(dy, Math.Sqrt(dz * dz + dx * dx)); float pitchDist = GameMath.AngleRadDistance(pitch, desiredPitch); pitch += pitchDist; pitch = pitch % GameMath.TWOPI; if (bodyPitch) { entity.ServerPos.Pitch = pitch; } if (lastCheckOrAttackMs + damagePlayerAtMs > entity.World.ElapsedMilliseconds) { return(true); } if (hasDirectContact(targetEntity)) { AmmuntionPouch pouch = new AmmuntionPouch() { Damage = 3 + entity.LeftHandItemSlot.Itemstack.ItemAttributes["damage"].AsFloat(0), DropChance = 1 - entity.LeftHandItemSlot.Itemstack.ItemAttributes["breakChanceOnImpact"].AsFloat(0.5f), Weight = 0.2f, Projectile = new AssetLocation("arrow-" + entity.LeftHandItemSlot.Itemstack.Collectible.Variant["material"]), ProjectileStack = entity.LeftHandItemSlot.TakeOut(1) }; entity.LeftHandItemSlot.MarkDirty(); EntityProperties type = entity.World.GetEntityType(pouch.Projectile); Entity projectile = entity.World.ClassRegistry.CreateEntity(type); projectile = pouch.getRangedEntity(projectile, prog.owner?.Entity != null ? prog.owner?.Entity : entity, entity.Stats.GetBlended("rangedWeaponsDamage")); Vec3d pos = entity.ServerPos.XYZ.Add(0, entity.LocalEyePos.Y - 0.2, 0); Vec3d aheadPos = pos.AheadCopy(1, pitch + randomizeAngle(spreadAngle), entity.ServerPos.Yaw + (90 * GameMath.DEG2RAD * 50 * 0.02f) + randomizeAngle(spreadAngle)); Vec3d velocity = (aheadPos - pos) * shotVelocity * entity.Stats.GetBlended("bowDrawingStrength"); projectile.ServerPos.SetPos(entity.ServerPos.BehindCopy(0.21).XYZ.Add(0, entity.LocalEyePos.Y - 0.2, 0).Ahead(0.25, 0, entity.ServerPos.Yaw + GameMath.PIHALF)); projectile.ServerPos.Motion.Set(velocity); projectile.Pos.SetFrom(projectile.ServerPos); projectile.World = entity.World; entity.World.SpawnEntity(projectile); } if (lastCheckOrAttackMs + fullClip > entity.World.ElapsedMilliseconds) { return(true); } return(false); }
public override bool ContinueExecute(float dt) { Vec3f targetVec = new Vec3f(); targetVec.Set( (float)(targetEntity.ServerPos.X - entity.ServerPos.X), (float)(targetEntity.ServerPos.Y - entity.ServerPos.Y), (float)(targetEntity.ServerPos.Z - entity.ServerPos.Z) ); float desiredYaw = (float)Math.Atan2(targetVec.X, targetVec.Z); float yawDist = GameMath.AngleRadDistance(entity.ServerPos.Yaw, desiredYaw); entity.ServerPos.Yaw += GameMath.Clamp(yawDist, -curTurnRadPerSec * dt, curTurnRadPerSec * dt); entity.ServerPos.Yaw = entity.ServerPos.Yaw % GameMath.TWOPI; if (Math.Abs(yawDist) > 0.02) { return(true); } if (animMeta != null) { animMeta.EaseInSpeed = 1f; animMeta.EaseOutSpeed = 1f; entity.AnimManager.StartAnimation(animMeta); } accum += dt; if (accum > releaseAtMs / 1000f && !didThrow) { didThrow = true; EntityProperties type = entity.World.GetEntityType(new AssetLocation("thrownstone-granite")); Entity entitypr = entity.World.ClassRegistry.CreateEntity(type); ((EntityThrownStone)entitypr).FiredBy = entity; ((EntityThrownStone)entitypr).Damage = 1; ((EntityThrownStone)entitypr).ProjectileStack = new ItemStack(entity.World.GetItem(new AssetLocation("stone-granite"))); ((EntityThrownStone)entitypr).NonCollectible = true; Vec3d pos = entity.ServerPos.XYZ.Add(0, entity.LocalEyePos.Y, 0); Vec3d aheadPos = targetEntity.ServerPos.XYZ.Add(0, targetEntity.LocalEyePos.Y, 0); double distf = Math.Pow(pos.SquareDistanceTo(aheadPos), 0.1); Vec3d velocity = (aheadPos - pos).Normalize() * GameMath.Clamp(distf - 1f, 0.1f, 1f); entitypr.ServerPos.SetPos( entity.ServerPos.BehindCopy(0.21).XYZ.Add(0, entity.LocalEyePos.Y, 0) ); entitypr.ServerPos.Motion.Set(velocity); entitypr.Pos.SetFrom(entitypr.ServerPos); entitypr.World = entity.World; entity.World.SpawnEntity(entitypr); } return(accum < durationMs / 1000f); }