diff --git a/FFXIVClassic Map Server/Program.cs b/FFXIVClassic Map Server/Program.cs index e4105a8d..fe4d69be 100644 --- a/FFXIVClassic Map Server/Program.cs +++ b/FFXIVClassic Map Server/Program.cs @@ -18,6 +18,7 @@ namespace FFXIVClassic_Map_Server public static Logger Log; public static Server Server; public static Random Random; + public static DateTime Tick; static void Main(string[] args) { @@ -59,7 +60,7 @@ namespace FFXIVClassic_Map_Server { Random = new Random(); Server = new Server(); - + Tick = DateTime.Now; Server.StartServer(); while (startServer) diff --git a/FFXIVClassic Map Server/WorldManager.cs b/FFXIVClassic Map Server/WorldManager.cs index 3d6cd62c..d0bd5f1f 100644 --- a/FFXIVClassic Map Server/WorldManager.cs +++ b/FFXIVClassic Map Server/WorldManager.cs @@ -954,11 +954,12 @@ namespace FFXIVClassic_Map_Server public void ZoneThreadLoop(Object state) { + // todo: spawn new thread for each zone on startup lock (zoneList) { - var tick = DateTime.Now; + Program.Tick = DateTime.Now; foreach (Zone zone in zoneList.Values) - zone.Update(tick); + zone.Update(Program.Tick); } } diff --git a/FFXIVClassic Map Server/actors/Actor.cs b/FFXIVClassic Map Server/actors/Actor.cs index 1ae1023d..68db3c94 100644 --- a/FFXIVClassic Map Server/actors/Actor.cs +++ b/FFXIVClassic Map Server/actors/Actor.cs @@ -160,7 +160,7 @@ namespace FFXIVClassic_Map_Server.Actors var pos = positionUpdates[0]; if (this is Character) - ((Character)this).OnPath(ref pos); + ((Character)this).OnPath(pos); positionX = pos.X; positionY = pos.Y; @@ -642,6 +642,31 @@ namespace FFXIVClassic_Map_Server.Actors return new Vector3(positionX + x, positionY, positionZ + z); } + + public Player GetAsPlayer() + { + return currentSubState == SetActorStatePacket.SUB_STATE_PLAYER && this is Player ? ((Player)this) : null; + } + + public Mob GetAsMob() + { + return currentSubState == SetActorStatePacket.SUB_STATE_MONSTER && this is Mob ? ((Mob)this) : null; + } + + public Npc GetAsNpc() + { + return currentSubState != SetActorStatePacket.SUB_STATE_PLAYER && this is Npc ? ((Npc)this) : null; + } + + public Actor GetAsActor() + { + return this is Actor ? ((Actor)this) : null; + } + + public Character GetAsCharacter() + { + return this is Character ? ((Character)this) : null; + } } } diff --git a/FFXIVClassic Map Server/actors/area/Area.cs b/FFXIVClassic Map Server/actors/area/Area.cs index 7a991e7f..9878526e 100644 --- a/FFXIVClassic Map Server/actors/area/Area.cs +++ b/FFXIVClassic Map Server/actors/area/Area.cs @@ -412,7 +412,7 @@ namespace FFXIVClassic_Map_Server.Actors AddActorToZone(npc); } - public Npc SpawnActor(uint classId, string uniqueId, float x, float y, float z, float rot = 0, ushort state = 0, uint animId = 0) + public Npc SpawnActor(uint classId, string uniqueId, float x, float y, float z, float rot = 0, ushort state = 0, uint animId = 0, bool isMob = true) { ActorClass actorClass = Server.GetWorldManager().GetActorClass(classId); @@ -426,7 +426,12 @@ namespace FFXIVClassic_Map_Server.Actors else zoneId = actorId; - Npc npc = new Npc(mActorList.Count + 1, actorClass, uniqueId, this, x, y, z, rot, state, animId, null); + Npc npc; + + if(isMob) + npc = new Mob(mActorList.Count + 1, actorClass, uniqueId, this, x, y, z, rot, state, animId, null); + else + npc = new Npc(mActorList.Count + 1, actorClass, uniqueId, this, x, y, z, rot, state, animId, null); npc.LoadEventConditions(actorClass.eventConditions); diff --git a/FFXIVClassic Map Server/actors/chara/Character.cs b/FFXIVClassic Map Server/actors/chara/Character.cs index 4924cbdd..1966b67c 100644 --- a/FFXIVClassic Map Server/actors/chara/Character.cs +++ b/FFXIVClassic Map Server/actors/chara/Character.cs @@ -209,7 +209,7 @@ namespace FFXIVClassic_Map_Server.Actors } } - public void OnPath(ref Vector3 point) + public void OnPath(Vector3 point) { if (positionUpdates != null && positionUpdates.Count > 0) { diff --git a/FFXIVClassic Map Server/actors/chara/ai/AIContainer.cs b/FFXIVClassic Map Server/actors/chara/ai/AIContainer.cs index 3c29b443..0fc56836 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/AIContainer.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/AIContainer.cs @@ -8,7 +8,7 @@ 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 +// port of ai code in dsp by kjLotus (https://github.com/DarkstarProject/darkstar/blob/master/src/map/ai) namespace FFXIVClassic_Map_Server.actors.chara.ai { // todo: actually implement stuff @@ -22,6 +22,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai private DateTime prevUpdate; private PathFind pathFind; private TargetFind targetFind; + private ActionQueue actionQueue; public AIContainer(Character actor, Controller controller, PathFind pathFind, TargetFind targetFind) { @@ -32,6 +33,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai this.targetFind = targetFind; latestUpdate = DateTime.Now; prevUpdate = latestUpdate; + actionQueue = new ActionQueue(owner); } public void Update(DateTime tick) @@ -46,36 +48,23 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai } - public DateTime GetLatestUpdate() + public void InterruptStates() { - return latestUpdate; + while (states.Count > 0 && states.Peek().CanInterrupt()) + { + states.Peek().SetInterrupted(true); + states.Peek().Cleanup(); + states.Pop(); + } } - public void Engage(Character target) + public void ClearStates() { - 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) - { - + while (states.Count > 0) + { + states.Peek().Cleanup(); + states.Pop(); + } } public void ChangeController(Controller controller) @@ -100,6 +89,75 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai } } + public DateTime GetLatestUpdate() + { + return latestUpdate; + } + + public bool IsSpawned() + { + // todo: set a flag when finished spawning + return true; + } + + public bool IsEngaged() + { + // todo: check this is legit + return owner.currentMainState == SetActorStatePacket.MAIN_STATE_ACTIVE; + } + + public bool IsDead() + { + return owner.currentMainState == SetActorStatePacket.MAIN_STATE_DEAD || + owner.currentMainState == SetActorStatePacket.MAIN_STATE_DEAD2; + } + + public bool IsRoaming() + { + // todo: check mounted? + return owner.currentMainState == SetActorStatePacket.MAIN_STATE_PASSIVE; + } + + public void Engage(Character target) + { + if (controller != null) + controller.Engage(target); + else + InternalEngage(target); + } + + public void Disengage() + { + if (controller != null) + controller.Disengage(); + else + InternalDisengage(); + } + + public void Cast(Character target, uint spellId) + { + if (controller != null) + controller.Cast(target, spellId); + else + InternalCast(target, spellId); + } + + public void WeaponSkill(Character target, uint weaponSkillId) + { + if (controller != null) + controller.WeaponSkill(target, weaponSkillId); + else + InternalWeaponSkill(target, weaponSkillId); + } + + public void MobSkill(Character target, uint mobSkillId) + { + if (controller != null) + controller.MobSkill(target, mobSkillId); + else + InternalMobSkill(target, mobSkillId); + } + public void InternalEngage(Character target) { diff --git a/FFXIVClassic Map Server/actors/chara/ai/state/AttackState.cs b/FFXIVClassic Map Server/actors/chara/ai/state/AttackState.cs index f8e38efe..ed2c659d 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/state/AttackState.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/state/AttackState.cs @@ -20,7 +20,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state } - public override void Update(ref DateTime time) + public override void Update(DateTime time) { } diff --git a/FFXIVClassic Map Server/actors/chara/ai/state/State.cs b/FFXIVClassic Map Server/actors/chara/ai/state/State.cs index c9f8cf68..d3cde4e3 100644 --- a/FFXIVClassic Map Server/actors/chara/ai/state/State.cs +++ b/FFXIVClassic Map Server/actors/chara/ai/state/State.cs @@ -28,13 +28,15 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state this.interrupt = false; } - public virtual void Update(ref DateTime time) { } + public virtual void Update(DateTime tick) { } public virtual void OnStart() { } public virtual void OnInterrupt() { } public virtual void OnComplete() { } public virtual void TryInterrupt() { } + public virtual void Cleanup() { } + public bool CanInterrupt() { return canInterrupt; @@ -44,5 +46,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state { this.interrupt = interrupt; } + } } diff --git a/FFXIVClassic Map Server/actors/chara/npc/Mob.cs b/FFXIVClassic Map Server/actors/chara/npc/Mob.cs index a24ba397..44642f9a 100644 --- a/FFXIVClassic Map Server/actors/chara/npc/Mob.cs +++ b/FFXIVClassic Map Server/actors/chara/npc/Mob.cs @@ -9,6 +9,7 @@ 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; +using FFXIVClassic_Map_Server.packets.send.actor; namespace FFXIVClassic_Map_Server.Actors { @@ -19,6 +20,7 @@ namespace FFXIVClassic_Map_Server.Actors : 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)); + this.currentSubState = SetActorStatePacket.SUB_STATE_MONSTER; } } }