diff --git a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj index a24629b3..a1c0bde5 100644 --- a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj +++ b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj @@ -85,14 +85,18 @@ + + + + diff --git a/FFXIVClassic Map Server/WorldManager.cs b/FFXIVClassic Map Server/WorldManager.cs index e61e4221..271a22c9 100644 --- a/FFXIVClassic Map Server/WorldManager.cs +++ b/FFXIVClassic Map Server/WorldManager.cs @@ -956,8 +956,8 @@ namespace FFXIVClassic_Map_Server { lock (zoneList) { - foreach (Area area in zoneList.Values) - area.Update(MILIS_LOOPTIME); + foreach (Zone zone in zoneList.Values) + zone.Update(MILIS_LOOPTIME); } } diff --git a/FFXIVClassic Map Server/actors/Actor.cs b/FFXIVClassic Map Server/actors/Actor.cs index 8e642e82..97e8b34e 100644 --- a/FFXIVClassic Map Server/actors/Actor.cs +++ b/FFXIVClassic Map Server/actors/Actor.cs @@ -152,7 +152,7 @@ namespace FFXIVClassic_Map_Server.Actors { updateMs = 150; } - if (diffTime.Milliseconds >= updateMs && hasMoved) + if (hasMoved && diffTime.Milliseconds >= updateMs) { hasMoved = (this.positionUpdates != null && this.positionUpdates.Count > 0); if (hasMoved) diff --git a/FFXIVClassic Map Server/actors/area/Zone.cs b/FFXIVClassic Map Server/actors/area/Zone.cs index cb75cbd2..a45b5fd4 100644 --- a/FFXIVClassic Map Server/actors/area/Zone.cs +++ b/FFXIVClassic Map Server/actors/area/Zone.cs @@ -167,6 +167,7 @@ namespace FFXIVClassic_Map_Server.actors.area { // todo: again, this is retarded but debug stuff var diffTime = DateTime.Now - lastUpdate; + base.Update(deltaTime); // arbitrary cap if (diffTime.Milliseconds >= 33) diff --git a/FFXIVClassic Map Server/actors/chara/Character.cs b/FFXIVClassic Map Server/actors/chara/Character.cs index 92262271..755ab6f4 100644 --- a/FFXIVClassic Map Server/actors/chara/Character.cs +++ b/FFXIVClassic Map Server/actors/chara/Character.cs @@ -228,6 +228,13 @@ namespace FFXIVClassic_Map_Server.Actors // todo: other ai helpers // time elapsed since last ai update + + if (aiContainer != null) + { + this.aiContainer.Update(DateTime.Now); + } + + /* var diffTime = (DateTime.Now - lastAiUpdate); if (this is Player) @@ -386,7 +393,9 @@ namespace FFXIVClassic_Map_Server.Actors lastAiUpdate = DateTime.Now; } } + */ } + } } diff --git a/FFXIVClassic Map Server/actors/chara/ai/AIContainer.cs b/FFXIVClassic Map Server/actors/chara/ai/AIContainer.cs index f0217a6c..f5d0bcf3 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/AIContainer.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/AIContainer.cs @@ -6,27 +6,118 @@ using System.Threading.Tasks; using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.actors.chara.ai.state; using FFXIVClassic_Map_Server.actors.chara.ai.controllers; +using FFXIVClassic_Map_Server.packets.send.actor; // port of ai code in dsp by kjLotus namespace FFXIVClassic_Map_Server.actors.chara.ai { // todo: actually implement stuff + // todo: use spell/ability/ws/mobskill objects instead of looking up ids class AIContainer { private Character owner; private Controller controller; - private List states; + private Stack states; private DateTime latestUpdate; private DateTime prevUpdate; + private PathFind pathFind; + private TargetFind targetFind; - public AIContainer(Actors.Character actor) + public AIContainer(Character actor, Controller controller, PathFind pathFind, TargetFind targetFind) { this.owner = actor; + this.states = new Stack(); + this.controller = controller; + this.pathFind = pathFind; + this.targetFind = targetFind; + latestUpdate = DateTime.Now; + prevUpdate = latestUpdate; + } + + public void Update(DateTime tick) + { + prevUpdate = latestUpdate; + latestUpdate = tick; + + // todo: trigger listeners + + // todo: action queues + + + } + + public void Engage(Character target) + { + if (controller != null) + controller.Engage(target); + else + InternalEngage(target); + } + + public bool IsEngaged() + { + // todo: check this is legit + return owner.currentMainState == SetActorStatePacket.MAIN_STATE_ACTIVE; + } + + public void Disengage() + { + if (controller != null) + controller.Disengage(); + else + InternalDisengage(); + } + + public void Cast(Character target, uint spellId) + { + } public void ChangeController(Controller controller) { this.controller = controller; } + + public bool CanChangeState() + { + return states.Count == 0 || states.First().CanInterrupt(); + } + + public void ChangeState(State state) + { + if (states.Count < 10) + { + states.Push(state); + } + else + { + throw new Exception("shit"); + } + } + + public void InternalEngage(Character target) + { + + } + + public void InternalDisengage() + { + + } + + public void InternalCast(Character target, uint spellId) + { + + } + + public void InternalWeaponSkill(Character target, uint weaponSkillId) + { + + } + + public void InternalMobSkill(Character target, uint mobSkillId) + { + + } } } diff --git a/FFXIVClassic Map Server/actors/chara/ai/ActionQueue.cs b/FFXIVClassic Map Server/actors/chara/ai/ActionQueue.cs new file mode 100644 index 00000000..b69caed8 --- /dev/null +++ b/FFXIVClassic Map Server/actors/chara/ai/ActionQueue.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using FFXIVClassic_Map_Server.Actors; +using MoonSharp; +using MoonSharp.Interpreter; + +namespace FFXIVClassic_Map_Server.actors.chara.ai +{ + class Action + { + public DateTime startTime; + public uint durationMs; + public bool checkState; + // todo: lua function + Script script; + } + class ActionQueue + { + private Character owner; + private Queue actionQueue; + private Queue timerQueue; + + public bool IsEmpty { get { return actionQueue.Count > 0 || timerQueue.Count > 0; } } + + public ActionQueue(Character owner) + { + + } + + public void PushAction(Action action) + { + + } + + public void Update(DateTime tick) + { + + } + + public void HandleAction(Action action) + { + + } + + } +} diff --git a/FFXIVClassic Map Server/actors/chara/ai/PathFind.cs b/FFXIVClassic Map Server/actors/chara/ai/PathFind.cs new file mode 100644 index 00000000..80a6a41c --- /dev/null +++ b/FFXIVClassic Map Server/actors/chara/ai/PathFind.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using FFXIVClassic_Map_Server.Actors; + +namespace FFXIVClassic_Map_Server.actors.chara.ai +{ + class PathFind + { + private Character owner; + + public PathFind(Character owner) + { + this.owner = owner; + } + } +} diff --git a/FFXIVClassic Map Server/actors/chara/ai/TargetFind.cs b/FFXIVClassic Map Server/actors/chara/ai/TargetFind.cs new file mode 100644 index 00000000..7a53177d --- /dev/null +++ b/FFXIVClassic Map Server/actors/chara/ai/TargetFind.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using FFXIVClassic_Map_Server.Actors; + +namespace FFXIVClassic_Map_Server.actors.chara.ai +{ + class TargetFind + { + private Character owner; + + public TargetFind(Character owner) + { + this.owner = owner; + } + } +} diff --git a/FFXIVClassic Map Server/actors/chara/ai/controllers/Controller.cs b/FFXIVClassic Map Server/actors/chara/ai/controllers/Controller.cs index 87bc3391..3f237d9e 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/controllers/Controller.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/controllers/Controller.cs @@ -3,10 +3,67 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using FFXIVClassic_Map_Server.Actors; namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers { - class Controller + abstract class Controller { + protected Character owner; + + protected DateTime lastUpdate; + protected bool canUpdate = true; + protected bool autoAttackEnabled = true; + protected bool castingEnabled = true; + protected bool weaponSkillEnabled = true; + protected PathFind pathFind; + protected TargetFind targetFind; + + public abstract void Update(DateTime tick); + public abstract bool Engage(Character target); + public abstract bool Disengage(); + public abstract void Cast(Character target, uint spellId); + public virtual void WeaponSkill(Character target, uint weaponSkillId) { } + public virtual void MobSkill(Character target, uint mobSkillId) { } + public abstract void Ability(Character target, uint abilityId); + public abstract void RangedAttack(Character target); + public virtual void Spawn() { } + public virtual void Despawn() { } + + + public virtual void ChangeTarget(Character target) + { + owner.aiContainer.InternalEngage(target); + } + + public bool IsAutoAttackEnabled() + { + return autoAttackEnabled; + } + + public void SetAutoAttackEnabled(bool isEnabled) + { + autoAttackEnabled = isEnabled; + } + + public bool IsCastingEnabled() + { + return castingEnabled; + } + + public void SetCastingEnabled(bool isEnabled) + { + castingEnabled = isEnabled; + } + + public bool IsWeaponSkillEnabled() + { + return weaponSkillEnabled; + } + + public void SetWeaponSkillEnabled(bool isEnabled) + { + weaponSkillEnabled = isEnabled; + } } } diff --git a/FFXIVClassic Map Server/actors/chara/ai/controllers/MobController.cs b/FFXIVClassic Map Server/actors/chara/ai/controllers/MobController.cs index c8a1ba6c..b6da397f 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/controllers/MobController.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/controllers/MobController.cs @@ -3,10 +3,59 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using FFXIVClassic_Map_Server.Actors; namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers { class MobController : Controller { + public MobController(Character owner) + { + this.owner = owner; + this.lastUpdate = DateTime.Now; + } + + public override void Update(DateTime tick) + { + + } + + public override bool Engage(Character target) + { + // todo: check distance, last swing time, status effects + return true; + } + + private bool TryEngage(Character target) + { + // todo: + return true; + } + + public override bool Disengage() + { + // todo: + return true; + } + + public override void Cast(Character target, uint spellId) + { + + } + + public override void Ability(Character target, uint abilityId) + { + + } + + public override void RangedAttack(Character target) + { + + } + + public override void MobSkill(Character target, uint mobSkillId) + { + + } } } diff --git a/FFXIVClassic Map Server/actors/chara/ai/controllers/PlayerController.cs b/FFXIVClassic Map Server/actors/chara/ai/controllers/PlayerController.cs index b067dc58..b920c690 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/controllers/PlayerController.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/controllers/PlayerController.cs @@ -3,10 +3,53 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using FFXIVClassic_Map_Server.Actors; namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers { class PlayerController : Controller { + public PlayerController(Character owner) + { + this.owner = owner; + this.lastUpdate = DateTime.Now; + } + + public override void Update(DateTime tick) + { + + } + + public override void ChangeTarget(Character target) + { + base.ChangeTarget(target); + } + + public override bool Engage(Character target) + { + // todo: check distance, last swing time, status effects + return true; + } + + public override bool Disengage() + { + // todo: + return true; + } + + public override void Cast(Character target, uint spellId) + { + + } + + public override void Ability(Character target, uint abilityId) + { + + } + + public override void RangedAttack(Character target) + { + + } } } diff --git a/FFXIVClassic Map Server/actors/chara/npc/Mob.cs b/FFXIVClassic Map Server/actors/chara/npc/Mob.cs new file mode 100644 index 00000000..a24ba397 --- /dev/null +++ b/FFXIVClassic Map Server/actors/chara/npc/Mob.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using FFXIVClassic_Map_Server.Actors; +using FFXIVClassic_Map_Server.actors.chara.npc; +using FFXIVClassic_Map_Server.actors; +using FFXIVClassic_Map_Server.actors.chara; +using FFXIVClassic_Map_Server.actors.chara.ai; +using FFXIVClassic_Map_Server.actors.chara.ai.controllers; + +namespace FFXIVClassic_Map_Server.Actors +{ + class Mob : Npc + { + public Mob(int actorNumber, ActorClass actorClass, string uniqueId, Area spawnedArea, float posX, float posY, float posZ, float rot, + ushort actorState, uint animationId, string customDisplayName) + : base(actorNumber, actorClass, uniqueId, spawnedArea, posX, posY, posZ, rot, actorState, animationId, customDisplayName) + { + this.aiContainer = new AIContainer(this, new MobController(this), new PathFind(this), new TargetFind(this)); + } + } +} diff --git a/FFXIVClassic Map Server/actors/chara/npc/Npc.cs b/FFXIVClassic Map Server/actors/chara/npc/Npc.cs index d7a94eee..94f37af2 100644 --- a/FFXIVClassic Map Server/actors/chara/npc/Npc.cs +++ b/FFXIVClassic Map Server/actors/chara/npc/Npc.cs @@ -17,6 +17,7 @@ using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; +using FFXIVClassic_Map_Server.actors.chara.ai; namespace FFXIVClassic_Map_Server.Actors { @@ -84,8 +85,7 @@ namespace FFXIVClassic_Map_Server.Actors isStatic = true; } } - - GenerateActorName((int)actorNumber); + this.aiContainer = new AIContainer(this, null, new PathFind(this), new TargetFind(this)); } public Npc(int actorNumber, ActorClass actorClass, string uniqueId, Area spawnedArea, float posX, float posY, float posZ, float rot, uint layout, uint instance) diff --git a/FFXIVClassic Map Server/actors/chara/player/Player.cs b/FFXIVClassic Map Server/actors/chara/player/Player.cs index 3e700d63..a63dc7cc 100644 --- a/FFXIVClassic Map Server/actors/chara/player/Player.cs +++ b/FFXIVClassic Map Server/actors/chara/player/Player.cs @@ -18,6 +18,8 @@ using FFXIVClassic_Map_Server.packets.send.actor.inventory; using FFXIVClassic_Map_Server.actors.group; using FFXIVClassic_Map_Server.packets.send.group; using FFXIVClassic_Map_Server.packets.WorldPackets.Send.Group; +using FFXIVClassic_Map_Server.actors.chara.ai; +using FFXIVClassic_Map_Server.actors.chara.ai.controllers; namespace FFXIVClassic_Map_Server.Actors { @@ -247,6 +249,7 @@ namespace FFXIVClassic_Map_Server.Actors Database.LoadPlayerCharacter(this); lastPlayTimeUpdate = Utils.UnixTimeStampUTC(); + this.aiContainer = new AIContainer(this, new PlayerController(this), null, new TargetFind(this)); } public List Create0x132Packets(uint playerActorId)