From ce00e72773b8497098a2a89d6b7539b73d65d46f Mon Sep 17 00:00:00 2001 From: gmriggs Date: Mon, 30 Apr 2018 19:36:44 -0400 Subject: [PATCH 01/14] Monster movement --- Source/ACE.Entity/Enum/MovementParams.cs | 24 ++ Source/ACE.Entity/Position.cs | 26 +++ Source/ACE.Server/Entity/Landblock.cs | 4 +- Source/ACE.Server/Managers/EmoteManager.cs | 2 +- .../ACE.Server/Managers/LandblockManager.cs | 8 +- .../Network/Motion/UniversalMotion.cs | 10 +- Source/ACE.Server/WorldObjects/Creature.cs | 17 ++ .../WorldObjects/Creature_Navigation.cs | 10 + Source/ACE.Server/WorldObjects/Monster.cs | 215 ++++++++++++++++++ .../WorldObjects/Monster_Awareness.cs | 14 ++ Source/ACE.Server/WorldObjects/Player.cs | 4 +- .../ACE.Server/WorldObjects/Player_Monster.cs | 54 +++++ .../WorldObjects/WorldObject_Networking.cs | 12 + 13 files changed, 387 insertions(+), 13 deletions(-) create mode 100644 Source/ACE.Entity/Enum/MovementParams.cs create mode 100644 Source/ACE.Server/WorldObjects/Monster.cs create mode 100644 Source/ACE.Server/WorldObjects/Monster_Awareness.cs create mode 100644 Source/ACE.Server/WorldObjects/Player_Monster.cs diff --git a/Source/ACE.Entity/Enum/MovementParams.cs b/Source/ACE.Entity/Enum/MovementParams.cs new file mode 100644 index 0000000000..75cd02f0a2 --- /dev/null +++ b/Source/ACE.Entity/Enum/MovementParams.cs @@ -0,0 +1,24 @@ +namespace ACE.Entity.Enum +{ + public enum MovementParams + { + CanWalk = (1 << 0), + CanRun = (1 << 1), + CanSideStep = (1 << 2), + CanWalkBackwards = (1 << 3), + CanCharge = (1 << 4), + FailWalk = (1 << 5), + UseFinalHeading = (1 << 6), + Sticky = (1 << 7), + MoveAway = (1 << 8), + MoveTowards = (1 << 9), + UseSpheres = (1 << 10), + SetHoldKey = (1 << 11), + Autonomous = (1 << 12), + ModifyRawState = (1 << 13), + ModifyInterpretedState = (1 << 14), + CancelMoveTo = (1 << 15), + StopCompletely = (1 << 16), + DisableJumpDuringLink = (1 << 17) + } +} diff --git a/Source/ACE.Entity/Position.cs b/Source/ACE.Entity/Position.cs index 1a9721e3cc..512e942865 100644 --- a/Source/ACE.Entity/Position.cs +++ b/Source/ACE.Entity/Position.cs @@ -32,6 +32,12 @@ public Vector3 Pos { return new Vector3(PositionX, PositionY, PositionZ); } + set + { + PositionX = value.X; + PositionY = value.Y; + PositionZ = value.Z; + } } public Quaternion Rotation @@ -40,6 +46,26 @@ public Quaternion Rotation { return new Quaternion(RotationX, RotationY, RotationZ, RotationW); } + set + { + RotationW = value.W; + RotationX = value.X; + RotationY = value.Y; + RotationZ = value.Z; + } + } + + public Vector3 GlobalPos + { + get + { + return ToGlobal(); + } + } + + public void Rotate(Vector3 dir) + { + Rotation = Quaternion.CreateFromYawPitchRoll(0, 0, (float)Math.Atan2(dir.Y, dir.X)); } [JsonProperty("positionX")] diff --git a/Source/ACE.Server/Entity/Landblock.cs b/Source/ACE.Server/Entity/Landblock.cs index 584032a05a..36be9ce91a 100644 --- a/Source/ACE.Server/Entity/Landblock.cs +++ b/Source/ACE.Server/Entity/Landblock.cs @@ -51,7 +51,7 @@ public class Landblock : IActor /// private readonly Physics.Common.Landblock _landblock; - private readonly Dictionary worldObjects = new Dictionary(); + public readonly Dictionary worldObjects = new Dictionary(); private readonly Dictionary adjacencies = new Dictionary(); /// @@ -487,7 +487,7 @@ private void UpdateStatus(int pcount) /// /// Gets all landblocks in range of a position. (for indoors positions that is just this landblock) /// - private List GetLandblocksInRange(Position pos, float distance) + public List GetLandblocksInRange(Position pos, float distance) { List inRange = new List(); diff --git a/Source/ACE.Server/Managers/EmoteManager.cs b/Source/ACE.Server/Managers/EmoteManager.cs index b64df5aff0..161d02690c 100644 --- a/Source/ACE.Server/Managers/EmoteManager.cs +++ b/Source/ACE.Server/Managers/EmoteManager.cs @@ -905,7 +905,7 @@ public void ExecuteEmote(BiotaPropertiesEmote emote, BiotaPropertiesEmoteAction } else { - if (sourceObject.CurrentMotionState.Commands[0].Motion == startingMotion.Commands[0].Motion) + if (sourceObject.CurrentMotionState.Commands.Count > 0 && sourceObject.CurrentMotionState.Commands[0].Motion == startingMotion.Commands[0].Motion) { actionChain.AddDelaySeconds(emoteAction.Delay); actionChain.AddAction(sourceObject, () => diff --git a/Source/ACE.Server/Managers/LandblockManager.cs b/Source/ACE.Server/Managers/LandblockManager.cs index 1cf9c31e64..be319373db 100644 --- a/Source/ACE.Server/Managers/LandblockManager.cs +++ b/Source/ACE.Server/Managers/LandblockManager.cs @@ -154,25 +154,25 @@ private static void SetAdjacencies(LandblockId landblockId, bool autoLoad) if (y > 0) SetAdjacency(landblockId, landblockId.SouthWest, Adjacency.SouthWest, autoLoad); - if (y < 255) + if (y < 254) SetAdjacency(landblockId, landblockId.NorthWest, Adjacency.NorthWest, autoLoad); } - if (x < 255) + if (x < 254) { SetAdjacency(landblockId, landblockId.East, Adjacency.East, autoLoad); if (y > 0) SetAdjacency(landblockId, landblockId.SouthEast, Adjacency.SouthEast, autoLoad); - if (y < 255) + if (y < 254) SetAdjacency(landblockId, landblockId.NorthEast, Adjacency.NorthEast, autoLoad); } if (y > 0) SetAdjacency(landblockId, landblockId.South, Adjacency.South, autoLoad); - if (y < 255) + if (y < 254) SetAdjacency(landblockId, landblockId.North, Adjacency.North, autoLoad); } diff --git a/Source/ACE.Server/Network/Motion/UniversalMotion.cs b/Source/ACE.Server/Network/Motion/UniversalMotion.cs index cf02d2b23a..c865e7dbd9 100644 --- a/Source/ACE.Server/Network/Motion/UniversalMotion.cs +++ b/Source/ACE.Server/Network/Motion/UniversalMotion.cs @@ -10,7 +10,7 @@ namespace ACE.Server.Network.Motion { public class UniversalMotion : MotionState { - public uint Flag { get; set; } = 0x0041EE0F; + public MovementParams Flag { get; set; } = (MovementParams)0x0041EE0F; public float MinimumDistance { get; set; } = 0.00f; @@ -43,7 +43,7 @@ public class UniversalMotion : MotionState /// public MotionStance Stance { get; } - public MovementData MovementData { get; } + public MovementData MovementData { get; set; } public List Commands { get; } = new List(); @@ -124,7 +124,7 @@ public override byte[] GetPayload(ObjectGuid animationTargetGuid, SequenceManage writer.Write(TargetGuid.Full); Position.Serialize(writer, false); - writer.Write(Flag); + writer.Write((uint)Flag); writer.Write(DistanceFrom); writer.Write(MinimumDistance); writer.Write(FailDistance); @@ -146,14 +146,14 @@ public override byte[] GetPayload(ObjectGuid animationTargetGuid, SequenceManage // movement type yet - coded it up but had not used or tested. writer.Write(TargetGuid.Full); writer.Write(Heading); - writer.Write(Flag); + writer.Write((uint)Flag); writer.Write(Speed); writer.Write(DesiredHeading); // always 0.0 in every pcap of this type. break; } case MovementTypes.TurnToHeading: { - writer.Write(Flag); + writer.Write((uint)Flag); writer.Write(Speed); writer.Write(Heading); break; diff --git a/Source/ACE.Server/WorldObjects/Creature.cs b/Source/ACE.Server/WorldObjects/Creature.cs index 31ccebb4fa..e30ddf94fc 100644 --- a/Source/ACE.Server/WorldObjects/Creature.cs +++ b/Source/ACE.Server/WorldObjects/Creature.cs @@ -81,6 +81,8 @@ private void SetEphemeralValues() GenerateWieldList(); Value = null; // Creatures don't have value. By setting this to null, it effectively disables the Value property. (Adding/Subtracting from null results in null) + + QueueNextTick(); } @@ -556,5 +558,20 @@ public override void ActOnUse(Player player) //player.Session.Network.EnqueueSend(sendUseDoneEvent); player.SendUseDoneEvent(); } + + public override void HeartBeat() + { + base.HeartBeat(); + } + + public static readonly float TickInterval = 1.0f; + + public void QueueNextTick() + { + var nextTick = new ActionChain(); + nextTick.AddDelaySeconds(TickInterval); + nextTick.AddAction(this, () => DoTick()); + nextTick.EnqueueChain(); + } } } diff --git a/Source/ACE.Server/WorldObjects/Creature_Navigation.cs b/Source/ACE.Server/WorldObjects/Creature_Navigation.cs index 53d63ae09a..62ec4fdba1 100644 --- a/Source/ACE.Server/WorldObjects/Creature_Navigation.cs +++ b/Source/ACE.Server/WorldObjects/Creature_Navigation.cs @@ -1,6 +1,7 @@ using System; using System.Numerics; using ACE.Entity.Enum; +using ACE.Server.Entity; using ACE.Server.Entity.Actions; using ACE.Server.Network.Motion; using ACE.Server.Physics; @@ -66,7 +67,16 @@ public float Rotate(WorldObject target) public void MoveTo(WorldObject target) { + if (this is Player) + return; + var motion = new UniversalMotion(CurrentMotionState.Stance, target.Location, target.Guid); + motion.MovementTypes = MovementTypes.MoveToObject; + motion.Flag |= MovementParams.CanCharge | MovementParams.FailWalk | MovementParams.UseFinalHeading | MovementParams.Sticky | MovementParams.MoveAway; + motion.WalkRunThreshold = 1.0f; + + CurrentMotionState = motion; + CurrentLandblock.EnqueueBroadcastMotion(this, motion); } } } diff --git a/Source/ACE.Server/WorldObjects/Monster.cs b/Source/ACE.Server/WorldObjects/Monster.cs new file mode 100644 index 0000000000..860976600c --- /dev/null +++ b/Source/ACE.Server/WorldObjects/Monster.cs @@ -0,0 +1,215 @@ +using System; +using ACE.Entity.Enum; +using ACE.Server.Entity; +using ACE.Server.Entity.Actions; +using ACE.Server.Network.Motion; +using System.Numerics; +using ACE.Server.Physics; + +namespace ACE.Server.WorldObjects +{ + partial class Creature + { + public enum State + { + Idle, + Awake + }; + + [Flags] + public enum Tolerance + { + None = 0, // attack targets in range + NoAttack = 1, // never attack + ID = 2, // attack when ID'd or attacked + Unknown = 4, // unused? + Provoke = 8, // used in conjunction with 32 + Unknown2 = 16, // unused? + Target = 32, // only target original attacker + Retaliate = 64 // only attack after attacked + }; + + public State MonsterState = State.Idle; + public bool IsAwake = false; + public bool IsMoving = false; + public bool IsTurning = false; + + public double LastMoveTime; + + public WorldObject AttackTarget; + + // TODO: determine from quickness / run speed + public static readonly float RunSpeed = 2.5f; + + /// + /// Construct a new monster from a weenie and a guid + /// + /*public Monster(Weenie weenie, ObjectGuid guid) : base(weenie, guid) + { + }*/ + + /// + /// Construct a new monster from a Biota + /// + /*public Monster(Biota biota) : base(biota) + { + }*/ + + public void Think() + { + if (!IsMoving) return; + Movement(); + } + + /// + /// Called every ~1 second + /// + public void DoTick() + { + Think(); + QueueNextTick(); + } + + /// + /// Called when player is in range + /// + public void WakeUp() + { + MonsterState = State.Awake; + IsAwake = true; + DoAttackStance(); + + // start turning and moving towards target + StartTurn(); + } + + public void DoAttackStance() + { + // TODO: get attack stance based on weapon type + var attackStance = MotionStance.UaNoShieldAttack; + + var motion = new UniversalMotion(attackStance); + motion.MovementData.CurrentStyle = (uint)attackStance; + motion.MovementData.ForwardCommand = (uint)MotionCommand.Ready; + + CurrentMotionState = motion; + CurrentLandblock.EnqueueBroadcastMotion(this, motion); + } + + /// + /// Starts the process of monster turning towards the attack target + /// + public void StartTurn() + { + IsTurning = true; + var time = EstimateTurnTo(); + + MoveTo(AttackTarget); + + var actionChain = new ActionChain(); + actionChain.AddDelaySeconds(time); + actionChain.AddAction(this, () => OnTurnComplete()); + actionChain.EnqueueChain(); + } + + /// + /// Called when the TurnTo process has completed + /// + public void OnTurnComplete() + { + IsTurning = false; + StartMove(); + } + + /// + /// Starts the process of monster moving towards the attack target + /// + public void StartMove() + { + LastMoveTime = Timer.CurrentTime; + IsMoving = true; + + /*var time = EstimateMoveTo(); + + var actionChain = new ActionChain(); + actionChain.AddDelaySeconds(time); + actionChain.AddAction(this, () => OnMoveComplete()); + actionChain.EnqueueChain();*/ + } + + /// + /// Called when the MoveTo process has completed + /// + public void OnMoveComplete() + { + IsMoving = false; + StartAttack(); + } + + /// + /// Starts the process of monster attacking target + /// + public void StartAttack() + { + //Console.WriteLine("StartAttack"); + } + + /// + /// Estimates the time it will take the monster to turn and move towards target + /// + /// + public float EstimateTargetTime() + { + return EstimateTurnTo() + EstimateMoveTo(); + } + + /// + /// Estimates the time it will take the monster to turn towards target + /// + public float EstimateTurnTo() + { + var angle = GetAngle(AttackTarget); + var rotateTime = Math.PI / (360.0f / angle); + return (float)rotateTime; + } + + /// + /// Estimates the time it will take the monster to move towards target + /// + /// + public float EstimateMoveTo() + { + var dist = (AttackTarget.Location.GlobalPos - Location.GlobalPos).Length(); + return dist / RunSpeed; + } + + public static readonly float MaxMeleeRange = 3.0f; + + /// + /// Returns TRUE if monster is within target melee range + /// + public bool IsMeleeRange() + { + var dist = (AttackTarget.Location.GlobalPos - Location.GlobalPos).Length(); + return dist <= MaxMeleeRange; + } + + public void Movement() + { + UpdatePosition(); + LastMoveTime = Timer.CurrentTime; + if (IsMeleeRange()) + OnMoveComplete(); + } + + public void UpdatePosition() + { + var deltaTime = (float)(Timer.CurrentTime - LastMoveTime); + var dir = Vector3.Normalize(AttackTarget.Location.GlobalPos - Location.GlobalPos); + var movement = dir * deltaTime * RunSpeed; + Location.Pos += movement; + Location.Rotate(dir); + SendUpdatePosition(); + } + } +} diff --git a/Source/ACE.Server/WorldObjects/Monster_Awareness.cs b/Source/ACE.Server/WorldObjects/Monster_Awareness.cs new file mode 100644 index 0000000000..197394524a --- /dev/null +++ b/Source/ACE.Server/WorldObjects/Monster_Awareness.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ACE.Server.WorldObjects +{ + /// + /// Determines when a monster wakes up from idle state + /// + partial class Monster + { + public const float RadiusAwareness = 35.0f; + } +} diff --git a/Source/ACE.Server/WorldObjects/Player.cs b/Source/ACE.Server/WorldObjects/Player.cs index f7629877dd..b3fad0337c 100644 --- a/Source/ACE.Server/WorldObjects/Player.cs +++ b/Source/ACE.Server/WorldObjects/Player.cs @@ -308,7 +308,9 @@ public void HandleActionQueryHealth(ObjectGuid queryId) // Remember the selected Target selectedTarget = queryId; HealthQueryTarget = queryId.Full; - CurrentLandblock.GetObject(queryId).QueryHealth(Session); + var obj = CurrentLandblock.GetObject(queryId); + if (obj != null) + obj.QueryHealth(Session); } public void HandleActionQueryItemMana(ObjectGuid queryId) diff --git a/Source/ACE.Server/WorldObjects/Player_Monster.cs b/Source/ACE.Server/WorldObjects/Player_Monster.cs new file mode 100644 index 0000000000..a18d06dbd4 --- /dev/null +++ b/Source/ACE.Server/WorldObjects/Player_Monster.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ACE.Server.Entity; +using ACE.Entity.Enum.Properties; + +namespace ACE.Server.WorldObjects +{ + /// + /// Handles player->monster visibility checks + /// + partial class Player + { + public void CheckMonsters() + { + // get all monsters within range + /*var nearbyMonsters = */GetMonstersInRange(); + } + + /// + /// Returns all monsters within 2D distance of player + /// + public void GetMonstersInRange(float range = Monster.RadiusAwareness) + { + var distSq = range * range; + + var landblocks = CurrentLandblock.GetLandblocksInRange(Location, range); + + foreach (var landblock in landblocks) + { + var monsters = landblock.worldObjects.Values.OfType().ToList(); + foreach (var monster in monsters) + { + if (this == monster) continue; + + if (Location.SquaredDistanceTo(monster.Location) < distSq) + { + //Console.WriteLine("Found monster in range! " + monster.Name); + + var attackable = monster.GetProperty(PropertyBool.Attackable) ?? false; + var tolerance = (Tolerance)(monster.GetProperty(PropertyInt.Tolerance) ?? 0); + + if (attackable && monster.MonsterState == State.Idle/* && tolerance == Tolerance.None*/) + { + monster.AttackTarget = this; + monster.WakeUp(); + } + } + } + } + } + } +} diff --git a/Source/ACE.Server/WorldObjects/WorldObject_Networking.cs b/Source/ACE.Server/WorldObjects/WorldObject_Networking.cs index cddb6c5683..38eeeee9f8 100644 --- a/Source/ACE.Server/WorldObjects/WorldObject_Networking.cs +++ b/Source/ACE.Server/WorldObjects/WorldObject_Networking.cs @@ -1240,12 +1240,22 @@ public void ClearPreviousLocation() /// public void PhysicsUpdatePosition(ACE.Entity.Position newPosition) { + var player = this as Player; + + // currently only processes players + if (player == null) return; + //var previousLocation = Location; if (PhysicsObj != null) { var dist = (newPosition.Pos - PhysicsObj.Position.Frame.Origin).Length(); if (dist > Physics.PhysicsGlobals.EPSILON) { + /*var dir = newPosition.GetCurrentDir(); + var rads = Math.Atan2(dir.Y, dir.X); + var angle = rads * 57.2958f; + Console.WriteLine("Angle: " + angle);*/ + var curCell = Physics.Common.LScape.get_landcell(Location.Cell); if (curCell != null) { @@ -1254,6 +1264,8 @@ public void PhysicsUpdatePosition(ACE.Entity.Position newPosition) PhysicsObj.set_request_pos(newPosition.Pos, newPosition.Rotation, curCell); PhysicsObj.update_object_server(); + + player.CheckMonsters(); } } } From f704641d59dbb072e7c9397af20263e6ceaea32b Mon Sep 17 00:00:00 2001 From: gmriggs Date: Mon, 30 Apr 2018 20:26:29 -0400 Subject: [PATCH 02/14] Fixing corpse rotation --- Source/ACE.Entity/Position.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/ACE.Entity/Position.cs b/Source/ACE.Entity/Position.cs index 512e942865..f4802e36cb 100644 --- a/Source/ACE.Entity/Position.cs +++ b/Source/ACE.Entity/Position.cs @@ -65,7 +65,7 @@ public Vector3 GlobalPos public void Rotate(Vector3 dir) { - Rotation = Quaternion.CreateFromYawPitchRoll(0, 0, (float)Math.Atan2(dir.Y, dir.X)); + Rotation = Quaternion.CreateFromYawPitchRoll(0, 0, (float)Math.Atan2(dir.Y, dir.X)) * Quaternion.CreateFromYawPitchRoll(0, 0, -(float)Math.PI / 2.0f); } [JsonProperty("positionX")] From fd79204a736ba73c3e14903b4bf5e95ee02f8b34 Mon Sep 17 00:00:00 2001 From: gmriggs Date: Mon, 30 Apr 2018 22:34:11 -0400 Subject: [PATCH 03/14] Updated corpse positions, and monster re-chase players --- Source/ACE.Server/WorldObjects/Monster.cs | 46 +++++++++++++++---- Source/ACE.Server/WorldObjects/WorldObject.cs | 3 ++ 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/Source/ACE.Server/WorldObjects/Monster.cs b/Source/ACE.Server/WorldObjects/Monster.cs index 860976600c..36ded15343 100644 --- a/Source/ACE.Server/WorldObjects/Monster.cs +++ b/Source/ACE.Server/WorldObjects/Monster.cs @@ -34,6 +34,14 @@ public enum Tolerance public bool IsMoving = false; public bool IsTurning = false; + public bool IsDead + { + get + { + return Health.Current <= 0; + } + } + public double LastMoveTime; public WorldObject AttackTarget; @@ -57,8 +65,12 @@ public enum Tolerance public void Think() { - if (!IsMoving) return; - Movement(); + if (!IsAwake || IsDead) return; + + if (!IsMoving && !IsMeleeRange()) + StartTurn(); + else + Movement(); } /// @@ -78,9 +90,6 @@ public void WakeUp() MonsterState = State.Awake; IsAwake = true; DoAttackStance(); - - // start turning and moving towards target - StartTurn(); } public void DoAttackStance() @@ -173,25 +182,33 @@ public float EstimateTurnTo() return (float)rotateTime; } + /// + /// Gets the distance to target, with radius excluded + /// + public float GetDistanceToTarget() + { + var dist = (AttackTarget.Location.GlobalPos - Location.GlobalPos).Length(); + dist -= AttackTarget.PhysicsObj.GetRadius() - PhysicsObj.GetRadius(); + return dist; + } + /// /// Estimates the time it will take the monster to move towards target /// /// public float EstimateMoveTo() { - var dist = (AttackTarget.Location.GlobalPos - Location.GlobalPos).Length(); - return dist / RunSpeed; + return GetDistanceToTarget() / RunSpeed; } - public static readonly float MaxMeleeRange = 3.0f; + public static readonly float MaxMeleeRange = 1.0f; /// /// Returns TRUE if monster is within target melee range /// public bool IsMeleeRange() { - var dist = (AttackTarget.Location.GlobalPos - Location.GlobalPos).Length(); - return dist <= MaxMeleeRange; + return GetDistanceToTarget() <= MaxMeleeRange; } public void Movement() @@ -211,5 +228,14 @@ public void UpdatePosition() Location.Rotate(dir); SendUpdatePosition(); } + + public void SetFinalPosition() + { + var playerDir = AttackTarget.Location.GetCurrentDir(); + Location.Pos = AttackTarget.Location.Pos + playerDir * (AttackTarget.PhysicsObj.GetRadius() + PhysicsObj.GetRadius()); + var dir = Vector3.Normalize(AttackTarget.Location.GlobalPos - Location.GlobalPos); + Location.Rotate(dir); + SendUpdatePosition(); + } } } diff --git a/Source/ACE.Server/WorldObjects/WorldObject.cs b/Source/ACE.Server/WorldObjects/WorldObject.cs index 680d7d3b9e..0b78a20a21 100644 --- a/Source/ACE.Server/WorldObjects/WorldObject.cs +++ b/Source/ACE.Server/WorldObjects/WorldObject.cs @@ -729,6 +729,9 @@ public virtual void TakeDamage(WorldObject source, float _amount, bool crit = fa monster.Health.Current = (uint)newMonsterHealth; else { + if (player != null && player.MeleeTarget != null) + monster.SetFinalPosition(); + monster.Health.Current = 0; monster.Die(); From a1965d5d4f27c27b0d327b1c45d93539751e676c Mon Sep 17 00:00:00 2001 From: gmriggs Date: Mon, 30 Apr 2018 23:00:23 -0400 Subject: [PATCH 04/14] Fixing animation break --- Source/ACE.Server/WorldObjects/Monster.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/ACE.Server/WorldObjects/Monster.cs b/Source/ACE.Server/WorldObjects/Monster.cs index 36ded15343..2510bbc8b9 100644 --- a/Source/ACE.Server/WorldObjects/Monster.cs +++ b/Source/ACE.Server/WorldObjects/Monster.cs @@ -67,7 +67,7 @@ public void Think() { if (!IsAwake || IsDead) return; - if (!IsMoving && !IsMeleeRange()) + if (!IsTurning && !IsMoving && !IsMeleeRange()) StartTurn(); else Movement(); From 0e5aa62c257b87f43e02c5758be7a87b893cd68b Mon Sep 17 00:00:00 2001 From: gmriggs Date: Tue, 1 May 2018 12:18:18 -0400 Subject: [PATCH 05/14] Updating landblock for monsters (not working) --- Source/ACE.Entity/LandblockId.cs | 23 +++++++- Source/ACE.Entity/Position.cs | 70 +++++++++++++++++++++-- Source/ACE.Server/WorldObjects/Monster.cs | 11 +++- 3 files changed, 98 insertions(+), 6 deletions(-) diff --git a/Source/ACE.Entity/LandblockId.cs b/Source/ACE.Entity/LandblockId.cs index a90074e48e..c3ed0c272c 100644 --- a/Source/ACE.Entity/LandblockId.cs +++ b/Source/ACE.Entity/LandblockId.cs @@ -5,7 +5,7 @@ namespace ACE.Entity { public struct LandblockId { - public uint Raw { get; } + public uint Raw { get; set; } public LandblockId(uint raw) { @@ -64,6 +64,27 @@ public bool IsAdjacentTo(LandblockId block) { return (Math.Abs(this.LandblockX - block.LandblockX) <= 1 && Math.Abs(this.LandblockY - block.LandblockY) <= 1); } + + public bool TransitionX(int blockOffset) + { + var newX = LandblockX + blockOffset; + if (newX < 0 || newX > 254) + return false; + + Raw = (uint)newX << 24 | (uint)LandblockY << 16; + return true; + } + + public bool TransitionY(int blockOffset) + { + var newY = LandblockY + blockOffset; + if (newY < 0 || newY > 254) + return false; + + Raw = (uint)LandblockX << 24 | (uint)LandblockY << 16; + return true; + } + public override bool Equals(object obj) { if (obj is LandblockId) diff --git a/Source/ACE.Entity/Position.cs b/Source/ACE.Entity/Position.cs index f4802e36cb..7ce1172817 100644 --- a/Source/ACE.Entity/Position.cs +++ b/Source/ACE.Entity/Position.cs @@ -34,12 +34,19 @@ public Vector3 Pos } set { - PositionX = value.X; - PositionY = value.Y; - PositionZ = value.Z; + SetPosition(value); } } + public bool SetPosition(Vector3 pos) + { + PositionX = pos.X; + PositionY = pos.Y; + PositionZ = pos.Z; + + return SetLandblock(); + } + public Quaternion Rotation { get @@ -154,10 +161,65 @@ public Position InFrontOf(double distanceInFront = 3.0f, bool rotate180 = false) return new Position(LandblockId.Raw, PositionX + dx, PositionY + dy, PositionZ + 0.5f, 0f, 0f, qz, qw); } - public Position() + /// + /// Handles the Position crossing over landblock boundaries + /// + public bool SetLandblock() { + var changedBlock = false; + + if (PositionX < 0) + { + var blockOffset = (int)PositionX / BlockLength - 1; + if (LandblockId.TransitionX(blockOffset)) + { + PositionX += BlockLength * blockOffset; + changedBlock = true; + } + else + PositionX = 0; + } + + if (PositionX > BlockLength) + { + var blockOffset = (int)PositionX / BlockLength; + if (LandblockId.TransitionX(blockOffset)) + { + PositionX -= BlockLength * blockOffset; + changedBlock = true; + } + else + PositionX = BlockLength; + } + + if (PositionY < 0) + { + var blockOffset = (int)PositionY / BlockLength - 1; + if (LandblockId.TransitionY(blockOffset)) + { + PositionY += BlockLength * blockOffset; + changedBlock = true; + } + else + PositionY = 0; + } + + if (PositionY > BlockLength) + { + var blockOffset = (int)PositionY / BlockLength; + if (LandblockId.TransitionY(blockOffset)) + { + PositionY -= BlockLength * blockOffset; + changedBlock = true; + } + else + PositionY = BlockLength; + } + return changedBlock; } + public Position() { } + public Position(uint newCell, float newPositionX, float newPositionY, float newPositionZ, float newRotationX, float newRotationY, float newRotationZ, float newRotationW) { LandblockId = new LandblockId(newCell); diff --git a/Source/ACE.Server/WorldObjects/Monster.cs b/Source/ACE.Server/WorldObjects/Monster.cs index 2510bbc8b9..c96985c468 100644 --- a/Source/ACE.Server/WorldObjects/Monster.cs +++ b/Source/ACE.Server/WorldObjects/Monster.cs @@ -5,6 +5,7 @@ using ACE.Server.Network.Motion; using System.Numerics; using ACE.Server.Physics; +using ACE.Server.Managers; namespace ACE.Server.WorldObjects { @@ -224,7 +225,9 @@ public void UpdatePosition() var deltaTime = (float)(Timer.CurrentTime - LastMoveTime); var dir = Vector3.Normalize(AttackTarget.Location.GlobalPos - Location.GlobalPos); var movement = dir * deltaTime * RunSpeed; - Location.Pos += movement; + if (Location.SetPosition(Location.Pos + movement)) + UpdateLandblock(); + Location.Rotate(dir); SendUpdatePosition(); } @@ -237,5 +240,11 @@ public void SetFinalPosition() Location.Rotate(dir); SendUpdatePosition(); } + + public void UpdateLandblock() + { + Console.WriteLine("Updating landblock for " + Name); + LandblockManager.RelocateObjectForPhysics(this); + } } } From 3cc12ff732110c41b9d7e35be7c731b0740b3fdd Mon Sep 17 00:00:00 2001 From: gmriggs Date: Tue, 1 May 2018 12:21:43 -0400 Subject: [PATCH 06/14] Fix typo --- Source/ACE.Entity/LandblockId.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/ACE.Entity/LandblockId.cs b/Source/ACE.Entity/LandblockId.cs index c3ed0c272c..7bcf7a25e5 100644 --- a/Source/ACE.Entity/LandblockId.cs +++ b/Source/ACE.Entity/LandblockId.cs @@ -81,7 +81,7 @@ public bool TransitionY(int blockOffset) if (newY < 0 || newY > 254) return false; - Raw = (uint)LandblockX << 24 | (uint)LandblockY << 16; + Raw = (uint)LandblockX << 24 | (uint)newY << 16; return true; } From 96a74f74103783984207c29db0d9a7f5e745b6f3 Mon Sep 17 00:00:00 2001 From: gmriggs Date: Tue, 1 May 2018 12:27:25 -0400 Subject: [PATCH 07/14] Fix typo 2 --- Source/ACE.Entity/Position.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/ACE.Entity/Position.cs b/Source/ACE.Entity/Position.cs index 7ce1172817..5d8e09c37a 100644 --- a/Source/ACE.Entity/Position.cs +++ b/Source/ACE.Entity/Position.cs @@ -173,7 +173,7 @@ public bool SetLandblock() var blockOffset = (int)PositionX / BlockLength - 1; if (LandblockId.TransitionX(blockOffset)) { - PositionX += BlockLength * blockOffset; + PositionX -= BlockLength * blockOffset; changedBlock = true; } else @@ -197,7 +197,7 @@ public bool SetLandblock() var blockOffset = (int)PositionY / BlockLength - 1; if (LandblockId.TransitionY(blockOffset)) { - PositionY += BlockLength * blockOffset; + PositionY -= BlockLength * blockOffset; changedBlock = true; } else From 244b32aceba6bb7c7d8e44c3151e0b037cfaa206 Mon Sep 17 00:00:00 2001 From: gmriggs Date: Tue, 1 May 2018 14:04:04 -0400 Subject: [PATCH 08/14] Adding PVS code to indoor monster wake up --- Source/ACE.Entity/Position.cs | 2 + .../ACE.Server/WorldObjects/Player_Monster.cs | 71 ++++++++++++++----- 2 files changed, 54 insertions(+), 19 deletions(-) diff --git a/Source/ACE.Entity/Position.cs b/Source/ACE.Entity/Position.cs index 5d8e09c37a..c4a04dc774 100644 --- a/Source/ACE.Entity/Position.cs +++ b/Source/ACE.Entity/Position.cs @@ -166,6 +166,8 @@ public Position InFrontOf(double distanceInFront = 3.0f, bool rotate180 = false) /// public bool SetLandblock() { + if (Indoors) return false; + var changedBlock = false; if (PositionX < 0) diff --git a/Source/ACE.Server/WorldObjects/Player_Monster.cs b/Source/ACE.Server/WorldObjects/Player_Monster.cs index a18d06dbd4..c88c88adaf 100644 --- a/Source/ACE.Server/WorldObjects/Player_Monster.cs +++ b/Source/ACE.Server/WorldObjects/Player_Monster.cs @@ -1,8 +1,6 @@ using System; -using System.Collections.Generic; using System.Linq; -using System.Text; -using ACE.Server.Entity; +using ACE.Entity.Enum; using ACE.Entity.Enum.Properties; namespace ACE.Server.WorldObjects @@ -12,16 +10,21 @@ namespace ACE.Server.WorldObjects /// partial class Player { + /// + /// Wakes up any monsters within the applicable range + /// public void CheckMonsters() { - // get all monsters within range - /*var nearbyMonsters = */GetMonstersInRange(); + if (CurrentLandblock.Id.MapScope == MapScope.Outdoors) + GetMonstersInRange(); + else + GetMonstersInPVS(); } /// - /// Returns all monsters within 2D distance of player + /// Sends alerts to monsters within 2D distance for outdoor areas /// - public void GetMonstersInRange(float range = Monster.RadiusAwareness) + private void GetMonstersInRange(float range = Monster.RadiusAwareness) { var distSq = range * range; @@ -35,20 +38,50 @@ public void GetMonstersInRange(float range = Monster.RadiusAwareness) if (this == monster) continue; if (Location.SquaredDistanceTo(monster.Location) < distSq) - { - //Console.WriteLine("Found monster in range! " + monster.Name); - - var attackable = monster.GetProperty(PropertyBool.Attackable) ?? false; - var tolerance = (Tolerance)(monster.GetProperty(PropertyInt.Tolerance) ?? 0); - - if (attackable && monster.MonsterState == State.Idle/* && tolerance == Tolerance.None*/) - { - monster.AttackTarget = this; - monster.WakeUp(); - } - } + AlertMonster(monster); } } } + + /// + /// Sends alerts to monsters within PVS range for indoor areas + /// + private void GetMonstersInPVS(float range = Monster.RadiusAwareness) + { + var distSq = range * range; + + var visibleObjs = Physics.PhysicsObj.ObjMaint.VisibleObjectTable.Values; + + foreach (var obj in visibleObjs) + { + if (PhysicsObj == obj) continue; + + var monster = obj.WeenieObj.WorldObject as Creature; + + if (monster == null) continue; + + if (Location.SquaredDistanceTo(monster.Location) < distSq) + AlertMonster(monster); + } + } + + /// + /// Wakes up a monster if it can be alerted + /// + private bool AlertMonster(Creature monster) + { + var attackable = monster.GetProperty(PropertyBool.Attackable) ?? false; + var tolerance = (Tolerance)(monster.GetProperty(PropertyInt.Tolerance) ?? 0); + + if (attackable && monster.MonsterState == State.Idle/* && tolerance == Tolerance.None*/) + { + //Console.WriteLine("Waking up " + monster.Name); + + monster.AttackTarget = this; + monster.WakeUp(); + return true; + } + return false; + } } } From 9b25b12c71ecbcb82d81042864335fcf36cbddf1 Mon Sep 17 00:00:00 2001 From: gmriggs Date: Tue, 1 May 2018 16:27:44 -0400 Subject: [PATCH 09/14] Some landblock transition updates --- Source/ACE.Entity/LandblockId.cs | 16 +++++++++++----- Source/ACE.Entity/Position.cs | 12 ++++++++---- Source/ACE.Server/Entity/Landblock.cs | 4 ++-- Source/ACE.Server/WorldObjects/Monster.cs | 1 + Source/ACE.Server/WorldObjects/WorldObject.cs | 2 +- 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/Source/ACE.Entity/LandblockId.cs b/Source/ACE.Entity/LandblockId.cs index 7bcf7a25e5..ae84825088 100644 --- a/Source/ACE.Entity/LandblockId.cs +++ b/Source/ACE.Entity/LandblockId.cs @@ -5,7 +5,7 @@ namespace ACE.Entity { public struct LandblockId { - public uint Raw { get; set; } + public uint Raw { get; } public LandblockId(uint raw) { @@ -65,23 +65,29 @@ public bool IsAdjacentTo(LandblockId block) return (Math.Abs(this.LandblockX - block.LandblockX) <= 1 && Math.Abs(this.LandblockY - block.LandblockY) <= 1); } - public bool TransitionX(int blockOffset) + public bool TransitionX(int blockOffset, out LandblockId landblockId) { var newX = LandblockX + blockOffset; if (newX < 0 || newX > 254) + { + landblockId = this; return false; + } - Raw = (uint)newX << 24 | (uint)LandblockY << 16; + landblockId = new LandblockId((uint)newX << 24 | (uint)LandblockY << 16); return true; } - public bool TransitionY(int blockOffset) + public bool TransitionY(int blockOffset, out LandblockId landblockId) { var newY = LandblockY + blockOffset; if (newY < 0 || newY > 254) + { + landblockId = this; return false; + } - Raw = (uint)LandblockX << 24 | (uint)newY << 16; + landblockId = new LandblockId((uint)LandblockX << 24 | (uint)newY << 16); return true; } diff --git a/Source/ACE.Entity/Position.cs b/Source/ACE.Entity/Position.cs index c4a04dc774..4e0b51c282 100644 --- a/Source/ACE.Entity/Position.cs +++ b/Source/ACE.Entity/Position.cs @@ -173,8 +173,9 @@ public bool SetLandblock() if (PositionX < 0) { var blockOffset = (int)PositionX / BlockLength - 1; - if (LandblockId.TransitionX(blockOffset)) + if (LandblockId.TransitionX(blockOffset, out var newBlockId)) { + LandblockId = newBlockId; PositionX -= BlockLength * blockOffset; changedBlock = true; } @@ -185,8 +186,9 @@ public bool SetLandblock() if (PositionX > BlockLength) { var blockOffset = (int)PositionX / BlockLength; - if (LandblockId.TransitionX(blockOffset)) + if (LandblockId.TransitionX(blockOffset, out var newBlockId)) { + LandblockId = newBlockId; PositionX -= BlockLength * blockOffset; changedBlock = true; } @@ -197,8 +199,9 @@ public bool SetLandblock() if (PositionY < 0) { var blockOffset = (int)PositionY / BlockLength - 1; - if (LandblockId.TransitionY(blockOffset)) + if (LandblockId.TransitionY(blockOffset, out var newBlockId)) { + LandblockId = newBlockId; PositionY -= BlockLength * blockOffset; changedBlock = true; } @@ -209,8 +212,9 @@ public bool SetLandblock() if (PositionY > BlockLength) { var blockOffset = (int)PositionY / BlockLength; - if (LandblockId.TransitionY(blockOffset)) + if (LandblockId.TransitionY(blockOffset, out var newBlockId)) { + LandblockId = newBlockId; PositionY -= BlockLength * blockOffset; changedBlock = true; } diff --git a/Source/ACE.Server/Entity/Landblock.cs b/Source/ACE.Server/Entity/Landblock.cs index 36be9ce91a..51eff1abc9 100644 --- a/Source/ACE.Server/Entity/Landblock.cs +++ b/Source/ACE.Server/Entity/Landblock.cs @@ -371,8 +371,8 @@ public ActionChain GetRemoveWorldObjectChain(ObjectGuid objectId, bool adjacency /// /// Should only be called by physics/relocation engines -- not from player /// - /// - /// + /// The object ID to be removed from the current landblock + /// Flag indicates if object is moving to an adjacent landblock public void RemoveWorldObjectForPhysics(ObjectGuid objectId, bool adjacencyMove) { RemoveWorldObjectInternal(objectId, adjacencyMove); diff --git a/Source/ACE.Server/WorldObjects/Monster.cs b/Source/ACE.Server/WorldObjects/Monster.cs index c96985c468..833a7fd01c 100644 --- a/Source/ACE.Server/WorldObjects/Monster.cs +++ b/Source/ACE.Server/WorldObjects/Monster.cs @@ -244,6 +244,7 @@ public void SetFinalPosition() public void UpdateLandblock() { Console.WriteLine("Updating landblock for " + Name); + PreviousLocation = Location; LandblockManager.RelocateObjectForPhysics(this); } } diff --git a/Source/ACE.Server/WorldObjects/WorldObject.cs b/Source/ACE.Server/WorldObjects/WorldObject.cs index 0b78a20a21..e3b5963c6c 100644 --- a/Source/ACE.Server/WorldObjects/WorldObject.cs +++ b/Source/ACE.Server/WorldObjects/WorldObject.cs @@ -305,7 +305,7 @@ private void SetEphemeralValues() public Position RequestedLocation { get; private set; } - public Position PreviousLocation { get; private set; } + public Position PreviousLocation { get; protected set; } /// /// Should only be adjusted by LandblockManager -- default is null From 7da9f29aae7139aa28d04dd8bb844cb5d4875092 Mon Sep 17 00:00:00 2001 From: gmriggs Date: Tue, 1 May 2018 17:51:40 -0400 Subject: [PATCH 10/14] Fixing the cross-landblock inconsistencies w/ correct cell IDs --- Source/ACE.Entity/LandblockId.cs | 4 ++-- Source/ACE.Entity/Position.cs | 23 ++++++++++++++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Source/ACE.Entity/LandblockId.cs b/Source/ACE.Entity/LandblockId.cs index ae84825088..305005622e 100644 --- a/Source/ACE.Entity/LandblockId.cs +++ b/Source/ACE.Entity/LandblockId.cs @@ -74,7 +74,7 @@ public bool TransitionX(int blockOffset, out LandblockId landblockId) return false; } - landblockId = new LandblockId((uint)newX << 24 | (uint)LandblockY << 16); + landblockId = new LandblockId((uint)newX << 24 | (uint)LandblockY << 16 | Raw & 0xFFFF); return true; } @@ -87,7 +87,7 @@ public bool TransitionY(int blockOffset, out LandblockId landblockId) return false; } - landblockId = new LandblockId((uint)LandblockX << 24 | (uint)newY << 16); + landblockId = new LandblockId((uint)LandblockX << 24 | (uint)newY << 16 | Raw & 0xFFFF); return true; } diff --git a/Source/ACE.Entity/Position.cs b/Source/ACE.Entity/Position.cs index 4e0b51c282..967c6f98a2 100644 --- a/Source/ACE.Entity/Position.cs +++ b/Source/ACE.Entity/Position.cs @@ -44,7 +44,10 @@ public bool SetPosition(Vector3 pos) PositionY = pos.Y; PositionZ = pos.Z; - return SetLandblock(); + var blockUpdate = SetLandblock(); + SetLandCell(); + + return blockUpdate; } public Quaternion Rotation @@ -224,6 +227,22 @@ public bool SetLandblock() return changedBlock; } + public bool SetLandCell() + { + var cellX = (uint)PositionX / CellLength; + var cellY = (uint)PositionY / CellLength; + + var cellID = cellX * CellSide + cellY + 1; + + var curCellID = LandblockId.Raw & 0xFFFF; + + if (cellID == curCellID) + return false; + + LandblockId = new LandblockId((uint)((LandblockId.Raw & 0xFFFF0000) | cellID)); + return true; + } + public Position() { } public Position(uint newCell, float newPositionX, float newPositionY, float newPositionZ, float newRotationX, float newRotationY, float newRotationZ, float newRotationW) @@ -521,6 +540,8 @@ public void CalculateObjCell(uint newCell) } public static readonly int BlockLength = 192; + public static readonly int CellSide = 8; + public static readonly int CellLength = 24; public Vector3 ToGlobal() { From 3a23539808b54130b0a01f786213162568d40ff4 Mon Sep 17 00:00:00 2001 From: gmriggs Date: Tue, 1 May 2018 21:06:43 -0400 Subject: [PATCH 11/14] Adding DeltaTime check to avoid ActionChain state --- Source/ACE.Server/WorldObjects/Monster.cs | 9 ++++++++- Source/ACE.Server/WorldObjects/Player_Melee.cs | 2 +- Source/ACE.Server/WorldObjects/Player_Missile.cs | 2 +- Source/ACE.Server/WorldObjects/WorldObject.cs | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Source/ACE.Server/WorldObjects/Monster.cs b/Source/ACE.Server/WorldObjects/Monster.cs index 833a7fd01c..a62f18b015 100644 --- a/Source/ACE.Server/WorldObjects/Monster.cs +++ b/Source/ACE.Server/WorldObjects/Monster.cs @@ -223,6 +223,7 @@ public void Movement() public void UpdatePosition() { var deltaTime = (float)(Timer.CurrentTime - LastMoveTime); + if (deltaTime > 2.0f) return; // ... var dir = Vector3.Normalize(AttackTarget.Location.GlobalPos - Location.GlobalPos); var movement = dir * deltaTime * RunSpeed; if (Location.SetPosition(Location.Pos + movement)) @@ -243,9 +244,15 @@ public void SetFinalPosition() public void UpdateLandblock() { - Console.WriteLine("Updating landblock for " + Name); + //Console.WriteLine("Updating landblock for " + Name); PreviousLocation = Location; LandblockManager.RelocateObjectForPhysics(this); } + + public void OnDeath() + { + IsTurning = false; + IsMoving = false; + } } } diff --git a/Source/ACE.Server/WorldObjects/Player_Melee.cs b/Source/ACE.Server/WorldObjects/Player_Melee.cs index 59ba656c85..8eb76aa4b0 100644 --- a/Source/ACE.Server/WorldObjects/Player_Melee.cs +++ b/Source/ACE.Server/WorldObjects/Player_Melee.cs @@ -47,7 +47,7 @@ public void HandleActionTargetedMeleeAttack(ObjectGuid guid, uint attackHeight, var target = CurrentLandblock.GetObject(guid); if (target == null) { - log.Warn("Unknown target guid " + guid); + log.Warn("Unknown target guid " + guid.Full.ToString("X8")); return; } if (MeleeTarget == null) diff --git a/Source/ACE.Server/WorldObjects/Player_Missile.cs b/Source/ACE.Server/WorldObjects/Player_Missile.cs index b4ff791cd9..a7e4ed9346 100644 --- a/Source/ACE.Server/WorldObjects/Player_Missile.cs +++ b/Source/ACE.Server/WorldObjects/Player_Missile.cs @@ -39,7 +39,7 @@ public void HandleActionTargetedMissileAttack(ObjectGuid guid, uint attackHeight var target = CurrentLandblock.GetObject(guid); if (target == null) { - log.Warn("Unknown target guid " + guid); + log.Warn("Unknown target guid " + guid.Full.ToString("X8")); return; } if (MissileTarget == null) diff --git a/Source/ACE.Server/WorldObjects/WorldObject.cs b/Source/ACE.Server/WorldObjects/WorldObject.cs index e3b5963c6c..f8821e5bc9 100644 --- a/Source/ACE.Server/WorldObjects/WorldObject.cs +++ b/Source/ACE.Server/WorldObjects/WorldObject.cs @@ -733,6 +733,7 @@ public virtual void TakeDamage(WorldObject source, float _amount, bool crit = fa monster.SetFinalPosition(); monster.Health.Current = 0; + monster.OnDeath(); monster.Die(); if (player != null) From c9a54c7b288ab276efddbf7be2cc840882c6e73e Mon Sep 17 00:00:00 2001 From: gmriggs Date: Tue, 1 May 2018 21:43:05 -0400 Subject: [PATCH 12/14] Cleanup --- Source/ACE.Entity/LandblockId.cs | 24 +++---- Source/ACE.Entity/Position.cs | 51 ++++++------- Source/ACE.Server/WorldObjects/Creature.cs | 5 -- Source/ACE.Server/WorldObjects/Monster.cs | 71 ++++++++++--------- .../WorldObjects/WorldObject_Networking.cs | 5 -- 5 files changed, 67 insertions(+), 89 deletions(-) diff --git a/Source/ACE.Entity/LandblockId.cs b/Source/ACE.Entity/LandblockId.cs index 305005622e..0ca685f8e2 100644 --- a/Source/ACE.Entity/LandblockId.cs +++ b/Source/ACE.Entity/LandblockId.cs @@ -65,30 +65,22 @@ public bool IsAdjacentTo(LandblockId block) return (Math.Abs(this.LandblockX - block.LandblockX) <= 1 && Math.Abs(this.LandblockY - block.LandblockY) <= 1); } - public bool TransitionX(int blockOffset, out LandblockId landblockId) + public LandblockId? TransitionX(int blockOffset) { var newX = LandblockX + blockOffset; if (newX < 0 || newX > 254) - { - landblockId = this; - return false; - } - - landblockId = new LandblockId((uint)newX << 24 | (uint)LandblockY << 16 | Raw & 0xFFFF); - return true; + return null; + else + return new LandblockId((uint)newX << 24 | (uint)LandblockY << 16 | Raw & 0xFFFF); } - public bool TransitionY(int blockOffset, out LandblockId landblockId) + public LandblockId? TransitionY(int blockOffset) { var newY = LandblockY + blockOffset; if (newY < 0 || newY > 254) - { - landblockId = this; - return false; - } - - landblockId = new LandblockId((uint)LandblockX << 24 | (uint)newY << 16 | Raw & 0xFFFF); - return true; + return null; + else + return new LandblockId((uint)LandblockX << 24 | (uint)newY << 16 | Raw & 0xFFFF); } public override bool Equals(object obj) diff --git a/Source/ACE.Entity/Position.cs b/Source/ACE.Entity/Position.cs index 967c6f98a2..04b59f25a9 100644 --- a/Source/ACE.Entity/Position.cs +++ b/Source/ACE.Entity/Position.cs @@ -16,10 +16,7 @@ public class Position : ICloneable public LandblockId LandblockId { get => landblockId.Raw != 0 ? landblockId : new LandblockId(Cell); - set - { - landblockId = value; - } + set => landblockId = value; } // TODO: This is just named wrong needs to be fixed. @@ -27,14 +24,16 @@ public LandblockId LandblockId public uint Cell { get; set; } public Vector3 Pos + { + get => new Vector3(PositionX, PositionY, PositionZ); + set => SetPosition(value); + } + + public Vector3 GlobalPos { get { - return new Vector3(PositionX, PositionY, PositionZ); - } - set - { - SetPosition(value); + return ToGlobal(); } } @@ -52,10 +51,7 @@ public bool SetPosition(Vector3 pos) public Quaternion Rotation { - get - { - return new Quaternion(RotationX, RotationY, RotationZ, RotationW); - } + get => new Quaternion(RotationX, RotationY, RotationZ, RotationW); set { RotationW = value.W; @@ -65,14 +61,6 @@ public Quaternion Rotation } } - public Vector3 GlobalPos - { - get - { - return ToGlobal(); - } - } - public void Rotate(Vector3 dir) { Rotation = Quaternion.CreateFromYawPitchRoll(0, 0, (float)Math.Atan2(dir.Y, dir.X)) * Quaternion.CreateFromYawPitchRoll(0, 0, -(float)Math.PI / 2.0f); @@ -176,9 +164,10 @@ public bool SetLandblock() if (PositionX < 0) { var blockOffset = (int)PositionX / BlockLength - 1; - if (LandblockId.TransitionX(blockOffset, out var newBlockId)) + var landblock = LandblockId.TransitionX(blockOffset); + if (landblock != null) { - LandblockId = newBlockId; + LandblockId = landblock.Value; PositionX -= BlockLength * blockOffset; changedBlock = true; } @@ -189,9 +178,10 @@ public bool SetLandblock() if (PositionX > BlockLength) { var blockOffset = (int)PositionX / BlockLength; - if (LandblockId.TransitionX(blockOffset, out var newBlockId)) + var landblock = LandblockId.TransitionX(blockOffset); + if (landblock != null) { - LandblockId = newBlockId; + LandblockId = landblock.Value; PositionX -= BlockLength * blockOffset; changedBlock = true; } @@ -202,9 +192,10 @@ public bool SetLandblock() if (PositionY < 0) { var blockOffset = (int)PositionY / BlockLength - 1; - if (LandblockId.TransitionY(blockOffset, out var newBlockId)) + var landblock = LandblockId.TransitionX(blockOffset); + if (landblock != null) { - LandblockId = newBlockId; + LandblockId = landblock.Value; PositionY -= BlockLength * blockOffset; changedBlock = true; } @@ -215,15 +206,17 @@ public bool SetLandblock() if (PositionY > BlockLength) { var blockOffset = (int)PositionY / BlockLength; - if (LandblockId.TransitionY(blockOffset, out var newBlockId)) + var landblock = LandblockId.TransitionX(blockOffset); + if (landblock != null) { - LandblockId = newBlockId; + LandblockId = landblock.Value; PositionY -= BlockLength * blockOffset; changedBlock = true; } else PositionY = BlockLength; } + return changedBlock; } diff --git a/Source/ACE.Server/WorldObjects/Creature.cs b/Source/ACE.Server/WorldObjects/Creature.cs index e30ddf94fc..23223f6458 100644 --- a/Source/ACE.Server/WorldObjects/Creature.cs +++ b/Source/ACE.Server/WorldObjects/Creature.cs @@ -559,11 +559,6 @@ public override void ActOnUse(Player player) player.SendUseDoneEvent(); } - public override void HeartBeat() - { - base.HeartBeat(); - } - public static readonly float TickInterval = 1.0f; public void QueueNextTick() diff --git a/Source/ACE.Server/WorldObjects/Monster.cs b/Source/ACE.Server/WorldObjects/Monster.cs index a62f18b015..20861d8afd 100644 --- a/Source/ACE.Server/WorldObjects/Monster.cs +++ b/Source/ACE.Server/WorldObjects/Monster.cs @@ -1,22 +1,31 @@ using System; +using System.Numerics; using ACE.Entity.Enum; using ACE.Server.Entity; using ACE.Server.Entity.Actions; +using ACE.Server.Managers; using ACE.Server.Network.Motion; -using System.Numerics; using ACE.Server.Physics; -using ACE.Server.Managers; namespace ACE.Server.WorldObjects { + /// + /// Monster AI functions + /// partial class Creature { + /// + /// The exclusive states the monster can be in + /// public enum State { Idle, Awake }; + /// + /// Determines when a monster will attack + /// [Flags] public enum Tolerance { @@ -35,13 +44,7 @@ public enum Tolerance public bool IsMoving = false; public bool IsTurning = false; - public bool IsDead - { - get - { - return Health.Current <= 0; - } - } + public bool IsDead => Health.Current <= 0; public double LastMoveTime; @@ -51,19 +54,17 @@ public bool IsDead public static readonly float RunSpeed = 2.5f; /// - /// Construct a new monster from a weenie and a guid + /// Called every ~1 second /// - /*public Monster(Weenie weenie, ObjectGuid guid) : base(weenie, guid) + public void DoTick() { - }*/ + Think(); + QueueNextTick(); + } /// - /// Construct a new monster from a Biota + /// Primary dispatch for monster think /// - /*public Monster(Biota biota) : base(biota) - { - }*/ - public void Think() { if (!IsAwake || IsDead) return; @@ -74,15 +75,6 @@ public void Think() Movement(); } - /// - /// Called every ~1 second - /// - public void DoTick() - { - Think(); - QueueNextTick(); - } - /// /// Called when player is in range /// @@ -93,6 +85,9 @@ public void WakeUp() DoAttackStance(); } + /// + /// Switch to attack stance + /// public void DoAttackStance() { // TODO: get attack stance based on weapon type @@ -138,13 +133,6 @@ public void StartMove() { LastMoveTime = Timer.CurrentTime; IsMoving = true; - - /*var time = EstimateMoveTo(); - - var actionChain = new ActionChain(); - actionChain.AddDelaySeconds(time); - actionChain.AddAction(this, () => OnMoveComplete()); - actionChain.EnqueueChain();*/ } /// @@ -212,6 +200,9 @@ public bool IsMeleeRange() return GetDistanceToTarget() <= MaxMeleeRange; } + /// + /// Primary movement handler, determines if target in range + /// public void Movement() { UpdatePosition(); @@ -220,10 +211,13 @@ public void Movement() OnMoveComplete(); } + /// + /// Updates monster position and rotation + /// public void UpdatePosition() { var deltaTime = (float)(Timer.CurrentTime - LastMoveTime); - if (deltaTime > 2.0f) return; // ... + if (deltaTime > 2.0f) return; // FIXME: state persist? var dir = Vector3.Normalize(AttackTarget.Location.GlobalPos - Location.GlobalPos); var movement = dir * deltaTime * RunSpeed; if (Location.SetPosition(Location.Pos + movement)) @@ -233,6 +227,9 @@ public void UpdatePosition() SendUpdatePosition(); } + /// + /// Sets the corpse to the final position + /// public void SetFinalPosition() { var playerDir = AttackTarget.Location.GetCurrentDir(); @@ -242,6 +239,9 @@ public void SetFinalPosition() SendUpdatePosition(); } + /// + /// Called when a monster changes landblocks + /// public void UpdateLandblock() { //Console.WriteLine("Updating landblock for " + Name); @@ -249,6 +249,9 @@ public void UpdateLandblock() LandblockManager.RelocateObjectForPhysics(this); } + /// + /// Cleans up state on monster death + /// public void OnDeath() { IsTurning = false; diff --git a/Source/ACE.Server/WorldObjects/WorldObject_Networking.cs b/Source/ACE.Server/WorldObjects/WorldObject_Networking.cs index 38eeeee9f8..1d2ec05b96 100644 --- a/Source/ACE.Server/WorldObjects/WorldObject_Networking.cs +++ b/Source/ACE.Server/WorldObjects/WorldObject_Networking.cs @@ -1251,11 +1251,6 @@ public void PhysicsUpdatePosition(ACE.Entity.Position newPosition) var dist = (newPosition.Pos - PhysicsObj.Position.Frame.Origin).Length(); if (dist > Physics.PhysicsGlobals.EPSILON) { - /*var dir = newPosition.GetCurrentDir(); - var rads = Math.Atan2(dir.Y, dir.X); - var angle = rads * 57.2958f; - Console.WriteLine("Angle: " + angle);*/ - var curCell = Physics.Common.LScape.get_landcell(Location.Cell); if (curCell != null) { From a4e90361abd2db08328fd9148f5da97d71d72684 Mon Sep 17 00:00:00 2001 From: gmriggs Date: Tue, 1 May 2018 22:11:23 -0400 Subject: [PATCH 13/14] Fixing monster corpses in dungeons --- Source/ACE.Entity/Position.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/ACE.Entity/Position.cs b/Source/ACE.Entity/Position.cs index 04b59f25a9..c0474b0039 100644 --- a/Source/ACE.Entity/Position.cs +++ b/Source/ACE.Entity/Position.cs @@ -222,6 +222,8 @@ public bool SetLandblock() public bool SetLandCell() { + if (Indoors) return false; + var cellX = (uint)PositionX / CellLength; var cellY = (uint)PositionY / CellLength; From 06417781b2d276f5cb5d8833a223e88ade229c5f Mon Sep 17 00:00:00 2001 From: gmriggs Date: Wed, 2 May 2018 01:14:59 -0400 Subject: [PATCH 14/14] Monsters sleep when target exceeds max chase range --- Source/ACE.Server/WorldObjects/Monster.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Source/ACE.Server/WorldObjects/Monster.cs b/Source/ACE.Server/WorldObjects/Monster.cs index 20861d8afd..7d5e742a53 100644 --- a/Source/ACE.Server/WorldObjects/Monster.cs +++ b/Source/ACE.Server/WorldObjects/Monster.cs @@ -191,6 +191,7 @@ public float EstimateMoveTo() } public static readonly float MaxMeleeRange = 1.0f; + public static readonly float MaxChaseRange = 192.0f; /// /// Returns TRUE if monster is within target melee range @@ -209,6 +210,9 @@ public void Movement() LastMoveTime = Timer.CurrentTime; if (IsMeleeRange()) OnMoveComplete(); + + if (GetDistanceToTarget() >= MaxChaseRange) + Sleep(); } /// @@ -257,5 +261,15 @@ public void OnDeath() IsTurning = false; IsMoving = false; } + + /// + /// Returns a monster to idle state + /// + public void Sleep() + { + MonsterState = State.Idle; + IsAwake = false; + IsMoving = false; + } } }