Beispiel #1
0
        // 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;
            }
        }
Beispiel #3
0
        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);
        }
Beispiel #7
0
        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);
        }
Beispiel #10
0
        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));
        }
Beispiel #12
0
        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);
        }
Beispiel #19
0
        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;
                }
            }
        }
Beispiel #21
0
        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;
        }
Beispiel #23
0
        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);
        }
Beispiel #24
0
        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;
            }
        }
Beispiel #27
0
        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);
        }
Beispiel #28
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;

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