From 1c5a0d3361b589ced9e1d06ea71c293cd5736763 Mon Sep 17 00:00:00 2001 From: Tim Sarbin Date: Sat, 1 Dec 2018 02:44:40 -0500 Subject: [PATCH] Fleshed out mob management on server. Added player location message frame. --- OpenDiablo2.Common.UT/UT_PlayerState.cs | 2 +- OpenDiablo2.Common/Enums/eMessageFrameType.cs | 2 + .../Extensions/MobManagerExtensions.cs | 12 ++ OpenDiablo2.Common/Interfaces/IGameServer.cs | 16 +++ OpenDiablo2.Common/Interfaces/IMapEngine.cs | 5 +- .../Interfaces/MessageBus/IMessageFrame.cs | 2 +- .../MessageBus/ISessionEventProvider.cs | 12 +- .../Interfaces/MessageBus/ISessionManager.cs | 5 +- .../MessageBus/PlayerLocationDetails.cs | 44 +++++++ .../Interfaces/Mobs/IMobCondition.cs | 14 --- .../Interfaces/Mobs/IMobManager.cs | 21 +++- OpenDiablo2.Common/Models/Mobs/EnemyState.cs | 7 +- .../Models/Mobs/MobCondition.cs | 97 ---------------- OpenDiablo2.Common/Models/Mobs/MobState.cs | 15 ++- OpenDiablo2.Common/Models/Mobs/PlayerState.cs | 25 ++-- OpenDiablo2.Common/OpenDiablo2.Common.csproj | 5 +- OpenDiablo2.Core.UT/UT_MobManager.cs | 57 ++++------ OpenDiablo2.Core/AutofacModule.cs | 3 + OpenDiablo2.Core/GameEngine.cs | 1 - OpenDiablo2.Core/GameState/GameState.cs | 28 ++--- OpenDiablo2.Core/GameState/MobManager.cs | 107 +++--------------- OpenDiablo2.Core/Map Engine/MapEngine.cs | 2 + OpenDiablo2.GameServer/AutofacModule.cs | 18 +++ OpenDiablo2.GameServer/GameServer.cs | 43 +++++++ .../OpenDiablo2.GameServer.csproj | 65 +++++++++++ .../Properties/AssemblyInfo.cs | 36 ++++++ OpenDiablo2.GameServer/packages.config | 5 + .../Message Frames/{ => Client}/MFJoinGame.cs | 22 ++-- .../Message Frames/Server/MFLocatePlayers.cs | 49 ++++++++ .../Message Frames/{ => Server}/MFSetSeed.cs | 10 +- .../OpenDiablo2.ServiceBus.csproj | 7 +- OpenDiablo2.ServiceBus/SessionManager.cs | 29 ++--- OpenDiablo2.ServiceBus/SessionServer.cs | 32 ++++-- OpenDiablo2.sln | 6 + OpenDiablo2/OpenDiablo2.csproj | 6 +- 35 files changed, 461 insertions(+), 349 deletions(-) create mode 100644 OpenDiablo2.Common/Extensions/MobManagerExtensions.cs create mode 100644 OpenDiablo2.Common/Interfaces/IGameServer.cs create mode 100644 OpenDiablo2.Common/Interfaces/MessageBus/PlayerLocationDetails.cs delete mode 100644 OpenDiablo2.Common/Interfaces/Mobs/IMobCondition.cs delete mode 100644 OpenDiablo2.Common/Models/Mobs/MobCondition.cs create mode 100644 OpenDiablo2.GameServer/AutofacModule.cs create mode 100644 OpenDiablo2.GameServer/GameServer.cs create mode 100644 OpenDiablo2.GameServer/OpenDiablo2.GameServer.csproj create mode 100644 OpenDiablo2.GameServer/Properties/AssemblyInfo.cs create mode 100644 OpenDiablo2.GameServer/packages.config rename OpenDiablo2.ServiceBus/Message Frames/{ => Client}/MFJoinGame.cs (63%) create mode 100644 OpenDiablo2.ServiceBus/Message Frames/Server/MFLocatePlayers.cs rename OpenDiablo2.ServiceBus/Message Frames/{ => Server}/MFSetSeed.cs (68%) diff --git a/OpenDiablo2.Common.UT/UT_PlayerState.cs b/OpenDiablo2.Common.UT/UT_PlayerState.cs index 02c6ba5a..73501165 100644 --- a/OpenDiablo2.Common.UT/UT_PlayerState.cs +++ b/OpenDiablo2.Common.UT/UT_PlayerState.cs @@ -27,7 +27,7 @@ namespace OpenDiablo2.Common.UT 2250, 4125, }); - PlayerState ps = new PlayerState("player1", id: 1, level: 1, x: 0, y: 0, + PlayerState ps = new PlayerState(0, "player1", id: 1, level: 1, x: 0, y: 0, vitality: herotypeconfig.StartingVitality, strength: herotypeconfig.StartingStrength, energy: herotypeconfig.StartingEnergy, diff --git a/OpenDiablo2.Common/Enums/eMessageFrameType.cs b/OpenDiablo2.Common/Enums/eMessageFrameType.cs index ad5556dd..165c8f46 100644 --- a/OpenDiablo2.Common/Enums/eMessageFrameType.cs +++ b/OpenDiablo2.Common/Enums/eMessageFrameType.cs @@ -6,11 +6,13 @@ using System.Threading.Tasks; namespace OpenDiablo2.Common.Enums { + // TODO: I don't think this needs to live in core... public enum eMessageFrameType { None = 0x00, SetSeed = 0x01, JoinGame = 0x02, + LocatePlayers = 0x03, MAX = 0xFF, // NOTE: // You absolutely cannot have a higher ID than this without diff --git a/OpenDiablo2.Common/Extensions/MobManagerExtensions.cs b/OpenDiablo2.Common/Extensions/MobManagerExtensions.cs new file mode 100644 index 00000000..eb6f8644 --- /dev/null +++ b/OpenDiablo2.Common/Extensions/MobManagerExtensions.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using System.Linq; +using OpenDiablo2.Common.Models.Mobs; + +namespace OpenDiablo2.Common.Extensions +{ + public static class MobManagerExtensions + { + public static IEnumerable FindInRadius(this IEnumerable mobs, float centerx, float centery, float radius) + => mobs.Where(x => x.GetDistance(centerx, centery) <= radius); + } +} diff --git a/OpenDiablo2.Common/Interfaces/IGameServer.cs b/OpenDiablo2.Common/Interfaces/IGameServer.cs new file mode 100644 index 00000000..050d004a --- /dev/null +++ b/OpenDiablo2.Common/Interfaces/IGameServer.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using OpenDiablo2.Common.Enums; +using OpenDiablo2.Common.Models.Mobs; + +namespace OpenDiablo2.Common.Interfaces +{ + public interface IGameServer : IDisposable + { + IEnumerable Players { get; } + int Seed { get; } + + void InitializeNewGame(); + int SpawnNewPlayer(int clientHash, string playerName, eHero heroType); + } +} diff --git a/OpenDiablo2.Common/Interfaces/IMapEngine.cs b/OpenDiablo2.Common/Interfaces/IMapEngine.cs index d8ccf182..228d23d7 100644 --- a/OpenDiablo2.Common/Interfaces/IMapEngine.cs +++ b/OpenDiablo2.Common/Interfaces/IMapEngine.cs @@ -1,11 +1,10 @@ -using System; -using System.Drawing; -using OpenDiablo2.Common.Models; +using System.Drawing; namespace OpenDiablo2.Common.Interfaces { public interface IMapEngine { + int FocusedMobId { get; set; } PointF CameraLocation { get; set; } void Update(long ms); void Render(); diff --git a/OpenDiablo2.Common/Interfaces/MessageBus/IMessageFrame.cs b/OpenDiablo2.Common/Interfaces/MessageBus/IMessageFrame.cs index 4ea50c20..1f5318c6 100644 --- a/OpenDiablo2.Common/Interfaces/MessageBus/IMessageFrame.cs +++ b/OpenDiablo2.Common/Interfaces/MessageBus/IMessageFrame.cs @@ -9,6 +9,6 @@ namespace OpenDiablo2.Common.Interfaces public interface IMessageFrame { byte[] Data { get; set; } - void Process(object sender, ISessionEventProvider sessionEventProvider); + void Process(int clientHash, ISessionEventProvider sessionEventProvider); } } diff --git a/OpenDiablo2.Common/Interfaces/MessageBus/ISessionEventProvider.cs b/OpenDiablo2.Common/Interfaces/MessageBus/ISessionEventProvider.cs index ea11ee7d..5e249420 100644 --- a/OpenDiablo2.Common/Interfaces/MessageBus/ISessionEventProvider.cs +++ b/OpenDiablo2.Common/Interfaces/MessageBus/ISessionEventProvider.cs @@ -1,18 +1,18 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using OpenDiablo2.Common.Enums; +using OpenDiablo2.Common.Interfaces.MessageBus; namespace OpenDiablo2.Common.Interfaces { - public delegate void OnSetSeedEvent(object sender, int seed); - public delegate void OnJoinGameEvent(object sender, Guid playerId, string playerName); // TODO: Not the final version.. + public delegate void OnSetSeedEvent(int clientHash, int seed); + public delegate void OnJoinGameEvent(int clientHash, eHero heroType, string playerName); + public delegate void OnLocatePlayersEvent(int clientHash, IEnumerable playerLocationDetails); public interface ISessionEventProvider { - OnSetSeedEvent OnSetSeed { get; set; } OnJoinGameEvent OnJoinGame { get; set; } + OnLocatePlayersEvent OnLocatePlayers { get; set; } } } diff --git a/OpenDiablo2.Common/Interfaces/MessageBus/ISessionManager.cs b/OpenDiablo2.Common/Interfaces/MessageBus/ISessionManager.cs index aa3c33a8..9d0dfc02 100644 --- a/OpenDiablo2.Common/Interfaces/MessageBus/ISessionManager.cs +++ b/OpenDiablo2.Common/Interfaces/MessageBus/ISessionManager.cs @@ -3,15 +3,18 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using OpenDiablo2.Common.Enums; namespace OpenDiablo2.Common.Interfaces { public interface ISessionManager : ISessionEventProvider, IDisposable { + Guid PlayerId { get; } + void Initialize(); void Stop(); - void JoinGame(string playerName, Action callback); + void JoinGame(string playerName, eHero heroType); } } diff --git a/OpenDiablo2.Common/Interfaces/MessageBus/PlayerLocationDetails.cs b/OpenDiablo2.Common/Interfaces/MessageBus/PlayerLocationDetails.cs new file mode 100644 index 00000000..b9d524a2 --- /dev/null +++ b/OpenDiablo2.Common/Interfaces/MessageBus/PlayerLocationDetails.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using OpenDiablo2.Common.Models.Mobs; + +namespace OpenDiablo2.Common.Interfaces.MessageBus +{ + public sealed class PlayerLocationDetails + { + public int PlayerId { get; set; } + public float PlayerX { get; set; } + public float PlayerY { get; set; } + // TODO: They may not be on the same 'anchor map'... + + public byte[] GetBytes() + { + var result = new List(); + result.AddRange(BitConverter.GetBytes(PlayerId)); + result.AddRange(BitConverter.GetBytes(PlayerX)); + result.AddRange(BitConverter.GetBytes(PlayerY)); + return result.ToArray(); + } + + public static PlayerLocationDetails FromBytes(byte[] data, int offset = 0) + => new PlayerLocationDetails + { + PlayerId = BitConverter.ToInt32(data, offset + 0), + PlayerX = BitConverter.ToSingle(data, offset + 4), + PlayerY = BitConverter.ToSingle(data, offset + 8) + }; + + public static int SizeInBytes => 12; + } + + public static class PlayerLocationDetailsExtensions + { + public static PlayerLocationDetails ToPlayerLocationDetails(this PlayerState source) + => new PlayerLocationDetails + { + PlayerId = source.Id, + PlayerX = source.GetPosition().X, + PlayerY = source.GetPosition().Y + }; + } +} diff --git a/OpenDiablo2.Common/Interfaces/Mobs/IMobCondition.cs b/OpenDiablo2.Common/Interfaces/Mobs/IMobCondition.cs deleted file mode 100644 index 5266ef48..00000000 --- a/OpenDiablo2.Common/Interfaces/Mobs/IMobCondition.cs +++ /dev/null @@ -1,14 +0,0 @@ -using OpenDiablo2.Common.Models.Mobs; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OpenDiablo2.Common.Interfaces.Mobs -{ - public interface IMobCondition - { - bool Evaluate(MobState mob); - } -} diff --git a/OpenDiablo2.Common/Interfaces/Mobs/IMobManager.cs b/OpenDiablo2.Common/Interfaces/Mobs/IMobManager.cs index 21122bbd..f509bd72 100644 --- a/OpenDiablo2.Common/Interfaces/Mobs/IMobManager.cs +++ b/OpenDiablo2.Common/Interfaces/Mobs/IMobManager.cs @@ -1,13 +1,22 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; +using OpenDiablo2.Common.Models.Mobs; namespace OpenDiablo2.Common.Interfaces.Mobs { public interface IMobManager { - // TODO: + IEnumerable Mobs { get; } + IEnumerable Players { get; } + IEnumerable Enemies { get; } + + void AddPlayer(PlayerState player); + void RemovePlayer(PlayerState player); + + void AddMob(MobState mob); + void RemoveMob(MobState mob); + int GetNextAvailableMobId(); + + void AddEnemy(EnemyState enemy); + void RemoveEnemy(EnemyState enemy); } } diff --git a/OpenDiablo2.Common/Models/Mobs/EnemyState.cs b/OpenDiablo2.Common/Models/Mobs/EnemyState.cs index 96210943..96445f88 100644 --- a/OpenDiablo2.Common/Models/Mobs/EnemyState.cs +++ b/OpenDiablo2.Common/Models/Mobs/EnemyState.cs @@ -1,9 +1,4 @@ using OpenDiablo2.Common.Enums.Mobs; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace OpenDiablo2.Common.Models.Mobs { @@ -11,6 +6,8 @@ namespace OpenDiablo2.Common.Models.Mobs { public int ExperienceGiven { get; protected set; } + public EnemyState() : base() { } + public EnemyState(string name, int id, int level, int maxhealth, float x, float y, int experiencegiven) : base(name, id, level, maxhealth, x, y) { diff --git a/OpenDiablo2.Common/Models/Mobs/MobCondition.cs b/OpenDiablo2.Common/Models/Mobs/MobCondition.cs deleted file mode 100644 index aa4437d1..00000000 --- a/OpenDiablo2.Common/Models/Mobs/MobCondition.cs +++ /dev/null @@ -1,97 +0,0 @@ -using OpenDiablo2.Common.Enums.Mobs; -using OpenDiablo2.Common.Interfaces.Mobs; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OpenDiablo2.Common.Models.Mobs -{ - public class MobConditionAnd : IMobCondition - { - public List Conditions = new List(); - - public MobConditionAnd(List conditions) - { - Conditions = conditions; - } - - public bool Evaluate(MobState mob) - { - foreach(IMobCondition condition in Conditions) - { - if (!condition.Evaluate(mob)) - { - return false; - } - } - return true; - } - } - - public class MobConditionOr : IMobCondition - { - public List Conditions = new List(); - - public MobConditionOr(List conditions) - { - Conditions = conditions; - } - - public bool Evaluate(MobState mob) - { - foreach (IMobCondition condition in Conditions) - { - if (condition.Evaluate(mob)) - { - return true; - } - } - return false; - } - } - - public class MobConditionNot : IMobCondition - { - public IMobCondition Condition = null; - - public MobConditionNot(IMobCondition condition) - { - Condition = condition; - } - - public bool Evaluate(MobState mob) - { - if(Condition == null) - { - return false; - } - return !Condition.Evaluate(mob); - } - } - - public class MobConditionFlags : IMobCondition - { - public Dictionary Flags = new Dictionary(); - - public MobConditionFlags(Dictionary flags) - { - Flags = flags; - } - - public bool Evaluate(MobState mob) - { - foreach(eMobFlags flag in Flags.Keys) - { - if(Flags[flag] != mob.HasFlag(flag)) - { - return false; - } - } - return true; - } - } - - // TODO: implement more of these -} diff --git a/OpenDiablo2.Common/Models/Mobs/MobState.cs b/OpenDiablo2.Common/Models/Mobs/MobState.cs index f4cd3ce7..523a7c05 100644 --- a/OpenDiablo2.Common/Models/Mobs/MobState.cs +++ b/OpenDiablo2.Common/Models/Mobs/MobState.cs @@ -1,14 +1,11 @@ -using OpenDiablo2.Common.Enums.Mobs; -using System; +using System; using System.Collections.Generic; using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using OpenDiablo2.Common.Enums.Mobs; namespace OpenDiablo2.Common.Models.Mobs { - public class MobState + public class MobState : IComparable { public readonly string Name; public readonly int Id; @@ -26,6 +23,8 @@ namespace OpenDiablo2.Common.Models.Mobs protected Dictionary Flags = new Dictionary(); + public MobState() { } + public MobState(string name, int id, int level, int maxhealth, float x, float y) { Name = name; @@ -163,6 +162,10 @@ namespace OpenDiablo2.Common.Models.Mobs } return false; } + #endregion Flags + + + public int CompareTo(object obj) => Id - ((MobState)obj).Id; } } diff --git a/OpenDiablo2.Common/Models/Mobs/PlayerState.cs b/OpenDiablo2.Common/Models/Mobs/PlayerState.cs index bbdbd35b..a41e3fa6 100644 --- a/OpenDiablo2.Common/Models/Mobs/PlayerState.cs +++ b/OpenDiablo2.Common/Models/Mobs/PlayerState.cs @@ -1,27 +1,23 @@ -using OpenDiablo2.Common.Enums; +using System; +using OpenDiablo2.Common.Enums; using OpenDiablo2.Common.Enums.Mobs; using OpenDiablo2.Common.Interfaces.Mobs; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace OpenDiablo2.Common.Models.Mobs { public class PlayerState : MobState { - public Guid Id { get; protected set; } public eHero HeroType { get; protected set; } private IHeroTypeConfig HeroTypeConfig; private ILevelExperienceConfig ExperienceConfig; + public int ClientHash { get; protected set; } // Player character stats protected Stat Vitality; protected Stat Strength; protected Stat Energy; protected Stat Dexterity; - + protected Stat DefenseRating; protected Stat AttackRating; @@ -30,11 +26,14 @@ namespace OpenDiablo2.Common.Models.Mobs public int Experience { get; protected set; } - public PlayerState(string name, int id, int level, float x, float y, - int vitality, int strength, int energy, int dexterity, int experience, eHero herotype, + public PlayerState() : base() { } + + public PlayerState(int clientHash, string name, int id, int level, float x, float y, + int vitality, int strength, int energy, int dexterity, int experience, eHero herotype, IHeroTypeConfig heroconfig, ILevelExperienceConfig expconfig) : base(name, id, level, 0, x, y) { + this.ClientHash = clientHash; Stamina = new Stat(0, 0, 0, true); Mana = new Stat(0, 0, 0, true); @@ -43,7 +42,7 @@ namespace OpenDiablo2.Common.Models.Mobs Energy = new Stat(0, energy, energy, true); Dexterity = new Stat(0, dexterity, dexterity, true); - AttackRating = new Stat(0, 0, 0, false); + AttackRating = new Stat(0, 0, 0, false); DefenseRating = new Stat(0, 0, 0, false); Experience = experience; // how much total exp do they have @@ -82,11 +81,11 @@ namespace OpenDiablo2.Common.Models.Mobs } public bool TryLevelUp() { - if(Level >= GetMaxLevel()) + if (Level >= GetMaxLevel()) { return false; // can't level up anymore } - if(GetExperienceToLevel() > 0) + if (GetExperienceToLevel() > 0) { return false; // not enough exp } diff --git a/OpenDiablo2.Common/OpenDiablo2.Common.csproj b/OpenDiablo2.Common/OpenDiablo2.Common.csproj index 528c3a50..39c9fe7c 100644 --- a/OpenDiablo2.Common/OpenDiablo2.Common.csproj +++ b/OpenDiablo2.Common/OpenDiablo2.Common.csproj @@ -69,10 +69,13 @@ + + + @@ -101,7 +104,6 @@ - @@ -114,7 +116,6 @@ - diff --git a/OpenDiablo2.Core.UT/UT_MobManager.cs b/OpenDiablo2.Core.UT/UT_MobManager.cs index 1b4108c5..72fa6f12 100644 --- a/OpenDiablo2.Core.UT/UT_MobManager.cs +++ b/OpenDiablo2.Core.UT/UT_MobManager.cs @@ -1,13 +1,9 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; using OpenDiablo2.Common.Enums.Mobs; +using OpenDiablo2.Common.Extensions; using OpenDiablo2.Common.Models.Mobs; using OpenDiablo2.Core.GameState_; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace OpenDiablo2.Core.UT { @@ -19,34 +15,21 @@ namespace OpenDiablo2.Core.UT { MobManager mobman = new MobManager(); MobState mob1 = new MobState("test1", mobman.GetNextAvailableMobId(), 1, 100, 0, 0); - MobState mob2 = new MobState("test2", mobman.GetNextAvailableMobId(), 1, 100, 0, 0); - MobState mob3 = new MobState("test3", mobman.GetNextAvailableMobId(), 1, 100, 0, 0); mob1.AddFlag(eMobFlags.ENEMY); + mobman.AddMob(mob1); + + MobState mob2 = new MobState("test2", mobman.GetNextAvailableMobId(), 1, 100, 0, 0); mob2.AddFlag(eMobFlags.ENEMY); mob2.AddFlag(eMobFlags.INVULNERABLE); - mobman.AddMob(mob1); mobman.AddMob(mob2); + + MobState mob3 = new MobState("test3", mobman.GetNextAvailableMobId(), 1, 100, 0, 0); mobman.AddMob(mob3); - Assert.IsTrue(mobman.FindMobs(new MobConditionFlags( - new Dictionary { - { eMobFlags.ENEMY, true } - })).Count == 2); - - Assert.IsTrue(mobman.FindMobs(new MobConditionFlags( - new Dictionary { - { eMobFlags.INVULNERABLE, true } - })).Count == 1); - - Assert.IsTrue(mobman.FindMobs(new MobConditionFlags( - new Dictionary { - { eMobFlags.PLAYER, true } - })).Count == 0); - - Assert.IsTrue(mobman.FindMobs(new MobConditionFlags( - new Dictionary { - { eMobFlags.PLAYER, false } - })).Count == 3); + Assert.IsTrue(mobman.Mobs.Count(x => x.HasFlag(eMobFlags.ENEMY)) == 2); + Assert.IsTrue(mobman.Mobs.Count(x => x.HasFlag(eMobFlags.INVULNERABLE)) == 1); + Assert.IsTrue(mobman.Mobs.Count(x => x.HasFlag(eMobFlags.PLAYER)) == 0); + Assert.IsTrue(mobman.Mobs.Count(x => !x.HasFlag(eMobFlags.PLAYER)) == 3); } [TestMethod] @@ -54,19 +37,21 @@ namespace OpenDiablo2.Core.UT { MobManager mobman = new MobManager(); MobState mob1 = new MobState("test1", mobman.GetNextAvailableMobId(), 1, 100, 0, 0); - MobState mob2 = new MobState("test2", mobman.GetNextAvailableMobId(), 1, 100, 10, 10); - MobState mob3 = new MobState("test3", mobman.GetNextAvailableMobId(), 1, 100, 3, 1); mob1.AddFlag(eMobFlags.ENEMY); + mobman.AddMob(mob1); + + MobState mob2 = new MobState("test2", mobman.GetNextAvailableMobId(), 1, 100, 10, 10); mob2.AddFlag(eMobFlags.ENEMY); mob2.AddFlag(eMobFlags.INVULNERABLE); - mobman.AddMob(mob1); mobman.AddMob(mob2); + + MobState mob3 = new MobState("test3", mobman.GetNextAvailableMobId(), 1, 100, 3, 1); mobman.AddMob(mob3); - Assert.IsTrue(mobman.FindMobsInRadius(0, 0, 1, null).Count == 1); - Assert.IsTrue(mobman.FindMobsInRadius(0, 0, 7, null).Count == 2); - Assert.IsTrue(mobman.FindMobsInRadius(0, 0, 20, null).Count == 3); - Assert.IsTrue(mobman.FindMobsInRadius(10, 10, 1, null).Count == 1); + Assert.IsTrue(mobman.Mobs.FindInRadius(0, 0, 1).Count() == 1); + Assert.IsTrue(mobman.Mobs.FindInRadius(0, 0, 7).Count() == 2); + Assert.IsTrue(mobman.Mobs.FindInRadius(0, 0, 20).Count() == 3); + Assert.IsTrue(mobman.Mobs.FindInRadius(10, 10, 1).Count() == 1); } } } diff --git a/OpenDiablo2.Core/AutofacModule.cs b/OpenDiablo2.Core/AutofacModule.cs index 52793968..3c4889aa 100644 --- a/OpenDiablo2.Core/AutofacModule.cs +++ b/OpenDiablo2.Core/AutofacModule.cs @@ -1,5 +1,6 @@ using Autofac; using OpenDiablo2.Common.Interfaces; +using OpenDiablo2.Common.Interfaces.Mobs; using OpenDiablo2.Core.GameState_; using OpenDiablo2.Core.Map_Engine; using OpenDiablo2.Core.UI; @@ -27,6 +28,8 @@ namespace OpenDiablo2.Core builder.RegisterType().As().SingleInstance(); builder.RegisterType().As().SingleInstance(); builder.RegisterType().As().InstancePerDependency(); + + builder.RegisterType().As().SingleInstance(); // TODO: This needs to have client and server versions... } } } diff --git a/OpenDiablo2.Core/GameEngine.cs b/OpenDiablo2.Core/GameEngine.cs index 93fb4dc7..78da0e95 100644 --- a/OpenDiablo2.Core/GameEngine.cs +++ b/OpenDiablo2.Core/GameEngine.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Drawing; using System.Linq; using System.Threading; diff --git a/OpenDiablo2.Core/GameState/GameState.cs b/OpenDiablo2.Core/GameState/GameState.cs index 68570d27..f85fe7db 100644 --- a/OpenDiablo2.Core/GameState/GameState.cs +++ b/OpenDiablo2.Core/GameState/GameState.cs @@ -4,6 +4,7 @@ using System.Drawing; using System.Linq; using OpenDiablo2.Common.Enums; using OpenDiablo2.Common.Interfaces; +using OpenDiablo2.Common.Interfaces.MessageBus; using OpenDiablo2.Common.Models; using OpenDiablo2.Core.Map_Engine; @@ -21,7 +22,6 @@ namespace OpenDiablo2.Core.GameState_ private readonly Func getMapEngine; private readonly Func getSessionManager; - private Guid playerId; private float animationTime = 0f; private List mapInfo; private List mapDataLookup = new List(); @@ -30,6 +30,7 @@ namespace OpenDiablo2.Core.GameState_ public int Act { get; private set; } public string MapName { get; private set; } public Palette CurrentPalette => paletteProvider.PaletteTable[$"ACT{Act}"]; + public IEnumerable PlayerLocationDetails { get; private set; } = new List(); public bool ShowInventoryPanel { get; set; } = false; public bool ShowCharacterPanel { get; set; } = false; @@ -64,19 +65,20 @@ namespace OpenDiablo2.Core.GameState_ sessionManager.Initialize(); sessionManager.OnSetSeed += OnSetSeedEvent; + sessionManager.OnLocatePlayers += OnLocatePlayers; mapInfo = new List(); sceneManager.ChangeScene("Game"); - sessionManager.JoinGame(characterName, (id) => - { - log.Info("hoo"); - playerId = id; - }); // TODO: we need more attributes... - log.Info("woo"); + sessionManager.JoinGame(characterName, hero); } - private void OnSetSeedEvent(object sender, int seed) + private void OnLocatePlayers(int clientHash, IEnumerable playerLocationDetails) + { + PlayerLocationDetails = playerLocationDetails; + } + + private void OnSetSeedEvent(int clientHash, int seed) { log.Info($"Setting seed to {seed}"); this.Seed = seed; @@ -224,15 +226,7 @@ namespace OpenDiablo2.Core.GameState_ return ShowCharacterPanel; } - - private MapCellInfo GetMapCellInfo( - MapInfo map, - int cellX, - int cellY, - MPQDS1TileProps props, - eRenderCellType cellType, - MPQDS1WallOrientationTileProps wallOrientations = null - ) + private MapCellInfo GetMapCellInfo(MapInfo map, int cellX, int cellY, MPQDS1TileProps props, eRenderCellType cellType, MPQDS1WallOrientationTileProps wallOrientations = null) { if (!map.CellInfo.ContainsKey(cellType)) { diff --git a/OpenDiablo2.Core/GameState/MobManager.cs b/OpenDiablo2.Core/GameState/MobManager.cs index 1665033c..5e6bb28a 100644 --- a/OpenDiablo2.Core/GameState/MobManager.cs +++ b/OpenDiablo2.Core/GameState/MobManager.cs @@ -1,20 +1,21 @@ -using OpenDiablo2.Common.Enums; +using System; +using System.Collections.Generic; using OpenDiablo2.Common.Interfaces.Mobs; using OpenDiablo2.Common.Models.Mobs; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace OpenDiablo2.Core.GameState_ { public class MobManager : IMobManager { - private List Mobs = new List(); // all mobs (including players!) - private List Players = new List(); - private List Enemies = new List(); - private List IdsUsed = new List(); + public HashSet Mobs { get; private set; } = new HashSet(); // all mobs (including players!) + public HashSet Players { get; private set; } = new HashSet(); + public HashSet Enemies { get; private set;} = new HashSet(); + + IEnumerable IMobManager.Mobs => Mobs; + IEnumerable IMobManager.Players => Players; + IEnumerable IMobManager.Enemies => Enemies; + + private HashSet IdsUsed = new HashSet(); #region Player Controls public void AddPlayer(PlayerState player) @@ -33,22 +34,9 @@ namespace OpenDiablo2.Core.GameState_ public void AddMob(MobState mob) { Mobs.Add(mob); - // add id to idsused in order - int i = 0; - while(i < IdsUsed.Count) - { - if(IdsUsed[i] > mob.Id) - { - IdsUsed.Insert(i, mob.Id); - break; - } - i++; - } - if(i == IdsUsed.Count) - { - // didn't get added - IdsUsed.Add(mob.Id); - } + if (IdsUsed.Contains(mob.Id)) + throw new ApplicationException("Tried to insert an existing mob id!"); + IdsUsed.Add(mob.Id); } public void RemoveMob(MobState mob) { @@ -57,16 +45,11 @@ namespace OpenDiablo2.Core.GameState_ } public int GetNextAvailableMobId() { - int i = 0; - while(i < IdsUsed.Count) - { - if(IdsUsed[i] != i) - { + for (var i = 1; i < int.MaxValue; i++) + if (!IdsUsed.Contains(i)) return i; - } - i++; - } - return IdsUsed.Count; + + throw new ApplicationException("Ran out of IDs. How did this even happen?!"); } #endregion Mob Controls @@ -83,59 +66,5 @@ namespace OpenDiablo2.Core.GameState_ } #endregion Enemy Controls - #region Searching and Filtering - public List FilterMobs(IEnumerable mobs, IMobCondition condition) - { - // note: if condition is null, returns full list - List filtered = new List(); - foreach(MobState mob in mobs) - { - if (condition == null || condition.Evaluate(mob)) - { - filtered.Add(mob); - } - } - return filtered; - } - - public List FindMobs(IMobCondition condition) - { - return FilterMobs(Mobs, condition); - } - public List FindEnemies(IMobCondition condition) - { - return FilterMobs(Enemies, condition); - } - public List FindPlayers(IMobCondition condition) - { - return FilterMobs(Players, condition); - } - - public List FindInRadius(IEnumerable mobs, float centerx, float centery, float radius) - { - List filtered = new List(); - foreach(MobState mob in mobs) - { - if(mob.GetDistance(centerx, centery) <= radius) - { - filtered.Add(mob); - } - } - return filtered; - } - - public List FindMobsInRadius(float centerx, float centery, float radius, IMobCondition condition) - { - return FilterMobs(FindInRadius(Mobs, centerx, centery, radius), condition); - } - public List FindEnemiesInRadius(float centerx, float centery, float radius, IMobCondition condition) - { - return FilterMobs(FindInRadius(Enemies, centerx, centery, radius), condition); - } - public List FindPlayersInRadius(float centerx, float centery, float radius, IMobCondition condition) - { - return FilterMobs(FindInRadius(Players, centerx, centery, radius), condition); - } - #endregion Searching and Filtering } } diff --git a/OpenDiablo2.Core/Map Engine/MapEngine.cs b/OpenDiablo2.Core/Map Engine/MapEngine.cs index d7443f72..5bb31153 100644 --- a/OpenDiablo2.Core/Map Engine/MapEngine.cs +++ b/OpenDiablo2.Core/Map Engine/MapEngine.cs @@ -12,6 +12,8 @@ namespace OpenDiablo2.Core.Map_Engine private readonly IRenderWindow renderWindow; private readonly IResourceManager resourceManager; + public int FocusedMobId { get; set; } = -1; + private PointF cameraLocation = new PointF(); public PointF CameraLocation { diff --git a/OpenDiablo2.GameServer/AutofacModule.cs b/OpenDiablo2.GameServer/AutofacModule.cs new file mode 100644 index 00000000..3565be8e --- /dev/null +++ b/OpenDiablo2.GameServer/AutofacModule.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Autofac; +using OpenDiablo2.Common.Interfaces; + +namespace OpenDiablo2.GameServer_ +{ + public sealed class AutofacModule : Module + { + protected override void Load(ContainerBuilder builder) + { + builder.RegisterType().As().SingleInstance(); + } + } +} diff --git a/OpenDiablo2.GameServer/GameServer.cs b/OpenDiablo2.GameServer/GameServer.cs new file mode 100644 index 00000000..64071e04 --- /dev/null +++ b/OpenDiablo2.GameServer/GameServer.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using OpenDiablo2.Common.Enums; +using OpenDiablo2.Common.Interfaces; +using OpenDiablo2.Common.Interfaces.Mobs; +using OpenDiablo2.Common.Models.Mobs; + +namespace OpenDiablo2.GameServer_ +{ + public sealed class GameServer : IGameServer + { + private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + private readonly IMobManager mobManager; + + public int Seed { get; private set; } + public IEnumerable Players => mobManager.Players; + + public GameServer(IMobManager mobManager) + { + this.mobManager = mobManager; + } + + public void InitializeNewGame() + { + log.Info("Initializing a new game"); + Seed = (new Random()).Next(); + } + + public int SpawnNewPlayer(int clientHash, string playerName, eHero heroType) + { + var newPlayer = new PlayerState(clientHash, playerName, mobManager.GetNextAvailableMobId(), 1, 20.0f, 20.0f, 10, 10, 10, 10, 0, heroType, + new HeroTypeConfig(10, 10, 10, 50, 50, 50, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1), new LevelExperienceConfig(new List() { 100 })); + + mobManager.AddPlayer(newPlayer); + return newPlayer.Id; + } + + public void Dispose() + { + } + } +} diff --git a/OpenDiablo2.GameServer/OpenDiablo2.GameServer.csproj b/OpenDiablo2.GameServer/OpenDiablo2.GameServer.csproj new file mode 100644 index 00000000..6973a36d --- /dev/null +++ b/OpenDiablo2.GameServer/OpenDiablo2.GameServer.csproj @@ -0,0 +1,65 @@ + + + + + Debug + AnyCPU + {C29A84E8-E708-4BE2-9946-202899B68E19} + Library + Properties + OpenDiablo2.GameServer + OpenDiablo2.GameServer + v4.6.1 + 512 + true + + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + prompt + MinimumRecommendedRules.ruleset + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + + + + ..\packages\Autofac.4.8.1\lib\net45\Autofac.dll + + + ..\packages\log4net.2.0.8\lib\net45-full\log4net.dll + + + + + + + + + + + + + + + + + + + + + {b743160e-a0bb-45dc-9998-967a85e50562} + OpenDiablo2.Common + + + + \ No newline at end of file diff --git a/OpenDiablo2.GameServer/Properties/AssemblyInfo.cs b/OpenDiablo2.GameServer/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..74d819f3 --- /dev/null +++ b/OpenDiablo2.GameServer/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenDiablo2.GameServer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("OpenDiablo2.GameServer")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c29a84e8-e708-4be2-9946-202899b68e19")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenDiablo2.GameServer/packages.config b/OpenDiablo2.GameServer/packages.config new file mode 100644 index 00000000..6764f843 --- /dev/null +++ b/OpenDiablo2.GameServer/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/OpenDiablo2.ServiceBus/Message Frames/MFJoinGame.cs b/OpenDiablo2.ServiceBus/Message Frames/Client/MFJoinGame.cs similarity index 63% rename from OpenDiablo2.ServiceBus/Message Frames/MFJoinGame.cs rename to OpenDiablo2.ServiceBus/Message Frames/Client/MFJoinGame.cs index 6f72d557..9cb4afbe 100644 --- a/OpenDiablo2.ServiceBus/Message Frames/MFJoinGame.cs +++ b/OpenDiablo2.ServiceBus/Message Frames/Client/MFJoinGame.cs @@ -5,18 +5,19 @@ using OpenDiablo2.Common.Attributes; using OpenDiablo2.Common.Enums; using OpenDiablo2.Common.Interfaces; -namespace OpenDiablo2.ServiceBus.Message_Frames +namespace OpenDiablo2.ServiceBus.Message_Frames.Client { [MessageFrame(eMessageFrameType.JoinGame)] public sealed class MFJoinGame : IMessageFrame { - public Guid PlayerId { get; set; } public string PlayerName { get; set; } + public eHero HeroType { get; set; } + public byte[] Data { get { - return PlayerId.ToByteArray() + return new byte[] { (byte)HeroType } .Concat(BitConverter.GetBytes((UInt16)PlayerName.Length)) .Concat(Encoding.UTF8.GetBytes(PlayerName)) .ToArray(); @@ -24,10 +25,9 @@ namespace OpenDiablo2.ServiceBus.Message_Frames set { - - PlayerId = new Guid(value.Take(16).ToArray()); - var playerNameLen = BitConverter.ToUInt16(value, 16); - PlayerName = Encoding.UTF8.GetString(value, 18, value.Length - 18); + HeroType = (eHero)value[0]; + var playerNameLen = BitConverter.ToUInt16(value, 1); + PlayerName = Encoding.UTF8.GetString(value, 3, value.Length - 3); if (PlayerName.Length != playerNameLen) throw new ApplicationException("Invalid player length!"); @@ -35,15 +35,15 @@ namespace OpenDiablo2.ServiceBus.Message_Frames } public MFJoinGame() { } - public MFJoinGame(string playerName) + public MFJoinGame(string playerName, eHero heroType) { - PlayerId = Guid.NewGuid(); PlayerName = playerName; + HeroType = heroType; } - public void Process(object sender, ISessionEventProvider sessionEventProvider) + public void Process(int clientHash, ISessionEventProvider sessionEventProvider) { - sessionEventProvider.OnJoinGame(sender, PlayerId, PlayerName); + sessionEventProvider.OnJoinGame(clientHash, HeroType, PlayerName); } } } diff --git a/OpenDiablo2.ServiceBus/Message Frames/Server/MFLocatePlayers.cs b/OpenDiablo2.ServiceBus/Message Frames/Server/MFLocatePlayers.cs new file mode 100644 index 00000000..2ce5a312 --- /dev/null +++ b/OpenDiablo2.ServiceBus/Message Frames/Server/MFLocatePlayers.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using OpenDiablo2.Common.Attributes; +using OpenDiablo2.Common.Enums; +using OpenDiablo2.Common.Interfaces; +using OpenDiablo2.Common.Interfaces.MessageBus; + +namespace OpenDiablo2.ServiceBus.Message_Frames.Server +{ + [MessageFrame(eMessageFrameType.LocatePlayers)] + public sealed class MFLocatePlayers : IMessageFrame + { + public IEnumerable LocationDetails { get; set; } + + public byte[] Data + { + get + { + var result = new List(); + result.AddRange(BitConverter.GetBytes((UInt16)LocationDetails.Count())); + result.AddRange(LocationDetails.SelectMany(x => x.GetBytes())); + return result.ToArray(); + } + + set + { + var count = BitConverter.ToUInt16(value, 0); + var result = new List(); + + for(var i = 0; i < count; i++) + { + result.Add(PlayerLocationDetails.FromBytes(value, 2 + (i * PlayerLocationDetails.SizeInBytes))); + } + + LocationDetails = result; + } + } + + public MFLocatePlayers() { } + public MFLocatePlayers(IEnumerable locationDetails) + { + this.LocationDetails = locationDetails; + } + + public void Process(int clientHash, ISessionEventProvider sessionEventProvider) + => sessionEventProvider.OnLocatePlayers(clientHash, LocationDetails); + } +} diff --git a/OpenDiablo2.ServiceBus/Message Frames/MFSetSeed.cs b/OpenDiablo2.ServiceBus/Message Frames/Server/MFSetSeed.cs similarity index 68% rename from OpenDiablo2.ServiceBus/Message Frames/MFSetSeed.cs rename to OpenDiablo2.ServiceBus/Message Frames/Server/MFSetSeed.cs index eb7901ac..0fd5b0f2 100644 --- a/OpenDiablo2.ServiceBus/Message Frames/MFSetSeed.cs +++ b/OpenDiablo2.ServiceBus/Message Frames/Server/MFSetSeed.cs @@ -3,7 +3,7 @@ using OpenDiablo2.Common.Attributes; using OpenDiablo2.Common.Enums; using OpenDiablo2.Common.Interfaces; -namespace OpenDiablo2.ServiceBus.Message_Frames +namespace OpenDiablo2.ServiceBus.Message_Frames.Server { [MessageFrame(eMessageFrameType.SetSeed)] public sealed class MFSetSeed : IMessageFrame @@ -19,7 +19,6 @@ namespace OpenDiablo2.ServiceBus.Message_Frames public MFSetSeed() { - Seed = (new Random()).Next(); } public MFSetSeed(int seed) @@ -27,9 +26,8 @@ namespace OpenDiablo2.ServiceBus.Message_Frames Seed = seed; } - public void Process(object sender, ISessionEventProvider sessionEventProvider) - { - sessionEventProvider.OnSetSeed?.Invoke(sender, Seed); - } + public void Process(int clientHash, ISessionEventProvider sessionEventProvider) + => sessionEventProvider.OnSetSeed?.Invoke(clientHash, Seed); + } } diff --git a/OpenDiablo2.ServiceBus/OpenDiablo2.ServiceBus.csproj b/OpenDiablo2.ServiceBus/OpenDiablo2.ServiceBus.csproj index 40c0077f..1081ff3c 100644 --- a/OpenDiablo2.ServiceBus/OpenDiablo2.ServiceBus.csproj +++ b/OpenDiablo2.ServiceBus/OpenDiablo2.ServiceBus.csproj @@ -21,6 +21,7 @@ x64 prompt MinimumRecommendedRules.ruleset + false bin\x64\Release\ @@ -30,6 +31,7 @@ x64 prompt MinimumRecommendedRules.ruleset + false @@ -56,8 +58,9 @@ - - + + + diff --git a/OpenDiablo2.ServiceBus/SessionManager.cs b/OpenDiablo2.ServiceBus/SessionManager.cs index e9798f50..960e9efb 100644 --- a/OpenDiablo2.ServiceBus/SessionManager.cs +++ b/OpenDiablo2.ServiceBus/SessionManager.cs @@ -7,7 +7,8 @@ using NetMQ.Sockets; using OpenDiablo2.Common.Attributes; using OpenDiablo2.Common.Enums; using OpenDiablo2.Common.Interfaces; -using OpenDiablo2.ServiceBus.Message_Frames; +using OpenDiablo2.ServiceBus.Message_Frames.Client; +using OpenDiablo2.ServiceBus.Message_Frames.Server; namespace OpenDiablo2.ServiceBus { @@ -23,11 +24,12 @@ namespace OpenDiablo2.ServiceBus private RequestSocket requestSocket; private AutoResetEvent resetEvent = new AutoResetEvent(false); private ISessionServer sessionServer; - private Guid playerId; + public Guid PlayerId { get; private set; } private bool running = false; public OnSetSeedEvent OnSetSeed { get; set; } public OnJoinGameEvent OnJoinGame { get; set; } + public OnLocatePlayersEvent OnLocatePlayers { get; set; } public SessionManager( eSessionType sessionType, @@ -71,15 +73,7 @@ namespace OpenDiablo2.ServiceBus default: throw new ApplicationException("This session type is currently unsupported."); } - - - //var bytes = message.First().ToByteArray(); - //var frameType = (eMessageFrameType)bytes[0]; - //var frameData = bytes.Skip(1).ToArray(); // TODO: Can we maybe use pointers? This seems wasteful - //var messageFrame = getMessageFrame(frameType); - //messageFrame.Data = frameData; - //messageFrame.Process(socket, this); - + running = true; resetEvent.WaitOne(); running = false; @@ -124,22 +118,17 @@ namespace OpenDiablo2.ServiceBus messageFrame.Data = frameData; lock (getGameState().ThreadLocker) { - messageFrame.Process(requestSocket, this); + messageFrame.Process(requestSocket.GetHashCode(), this); } } - public void JoinGame(string playerName, Action callback) + public void JoinGame(string playerName, eHero heroType) { Task.Run(() => { - var mf = new MFJoinGame(playerName); - playerId = mf.PlayerId; - Send(mf); + Send(new MFJoinGame(playerName, heroType)); ProcessMessageFrame(); - lock (getGameState().ThreadLocker) - { - callback(playerId); - } + ProcessMessageFrame(); }); } } diff --git a/OpenDiablo2.ServiceBus/SessionServer.cs b/OpenDiablo2.ServiceBus/SessionServer.cs index c57e2109..c603de56 100644 --- a/OpenDiablo2.ServiceBus/SessionServer.cs +++ b/OpenDiablo2.ServiceBus/SessionServer.cs @@ -7,7 +7,8 @@ using NetMQ.Sockets; using OpenDiablo2.Common.Attributes; using OpenDiablo2.Common.Enums; using OpenDiablo2.Common.Interfaces; -using OpenDiablo2.ServiceBus.Message_Frames; +using OpenDiablo2.Common.Interfaces.MessageBus; +using OpenDiablo2.ServiceBus.Message_Frames.Server; namespace OpenDiablo2.ServiceBus { @@ -16,26 +17,34 @@ namespace OpenDiablo2.ServiceBus private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private readonly eSessionType sessionType; + private readonly IGameServer gameServer; private readonly Func getMessageFrame; + private AutoResetEvent resetEvent = new AutoResetEvent(false); public AutoResetEvent WaitServerStartEvent { get; set; } = new AutoResetEvent(false); - - private int gameSeed; private bool running = false; private ResponseSocket responseSocket; public OnSetSeedEvent OnSetSeed { get; set; } public OnJoinGameEvent OnJoinGame { get; set; } + public OnLocatePlayersEvent OnLocatePlayers { get; set; } - public SessionServer(eSessionType sessionType, Func getMessageFrame) + public SessionServer( + eSessionType sessionType, + IGameServer gameServer, + Func getMessageFrame + ) { this.sessionType = sessionType; this.getMessageFrame = getMessageFrame; + this.gameServer = gameServer; } public void Start() { - gameSeed = (new Random()).Next(); + // TODO: Loading existing games... + gameServer.InitializeNewGame(); + Task.Run(() => Serve()); } @@ -64,7 +73,7 @@ namespace OpenDiablo2.ServiceBus var frameData = bytes.Skip(1).ToArray(); // TODO: Can we maybe use pointers? This seems wasteful var messageFrame = getMessageFrame(frameType); messageFrame.Data = frameData; - messageFrame.Process(socket, this); + messageFrame.Process(socket.GetHashCode(), this); }); running = true; WaitServerStartEvent.Set(); @@ -89,16 +98,17 @@ namespace OpenDiablo2.ServiceBus Stop(); } - private void Send(NetMQSocket target, IMessageFrame messageFrame) + private void Send(IMessageFrame messageFrame, bool more = false) { var attr = messageFrame.GetType().GetCustomAttributes(true).First(x => typeof(MessageFrameAttribute).IsAssignableFrom(x.GetType())) as MessageFrameAttribute; - responseSocket.SendFrame(new byte[] { (byte)attr.FrameType }.Concat(messageFrame.Data).ToArray()); + responseSocket.SendFrame(new byte[] { (byte)attr.FrameType }.Concat(messageFrame.Data).ToArray(), more); } - private void OnJoinGameHandler(object sender, Guid playerId, string playerName) + private void OnJoinGameHandler(int clientHash, eHero heroType, string playerName) { - // TODO: Try to make this less stupid - Send(sender as NetMQSocket, new MFSetSeed(gameSeed)); + gameServer.SpawnNewPlayer(clientHash, playerName, heroType); + Send(new MFSetSeed(gameServer.Seed), true); + Send(new MFLocatePlayers(gameServer.Players.Select(x => x.ToPlayerLocationDetails()))); } } } diff --git a/OpenDiablo2.sln b/OpenDiablo2.sln index d240598c..b8cc6238 100644 --- a/OpenDiablo2.sln +++ b/OpenDiablo2.sln @@ -25,6 +25,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{1FAD6E2F EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenDiablo2.ServiceBus", "OpenDiablo2.ServiceBus\OpenDiablo2.ServiceBus.csproj", "{D3F0F44F-2AB4-4342-A684-53193032A621}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenDiablo2.GameServer", "OpenDiablo2.GameServer\OpenDiablo2.GameServer.csproj", "{C29A84E8-E708-4BE2-9946-202899B68E19}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -67,6 +69,10 @@ Global {D3F0F44F-2AB4-4342-A684-53193032A621}.Debug|x64.Build.0 = Debug|x64 {D3F0F44F-2AB4-4342-A684-53193032A621}.Release|x64.ActiveCfg = Release|x64 {D3F0F44F-2AB4-4342-A684-53193032A621}.Release|x64.Build.0 = Release|x64 + {C29A84E8-E708-4BE2-9946-202899B68E19}.Debug|x64.ActiveCfg = Debug|x64 + {C29A84E8-E708-4BE2-9946-202899B68E19}.Debug|x64.Build.0 = Debug|x64 + {C29A84E8-E708-4BE2-9946-202899B68E19}.Release|x64.ActiveCfg = Release|x64 + {C29A84E8-E708-4BE2-9946-202899B68E19}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/OpenDiablo2/OpenDiablo2.csproj b/OpenDiablo2/OpenDiablo2.csproj index 09886d24..1ea685e4 100644 --- a/OpenDiablo2/OpenDiablo2.csproj +++ b/OpenDiablo2/OpenDiablo2.csproj @@ -5,7 +5,7 @@ Debug AnyCPU {2B0CF1AC-06DD-4322-AE8B-FF8A8C70A3CD} - Exe + WinExe OpenDiablo2 OpenDiablo2 v4.6.1 @@ -99,6 +99,10 @@ {8fc6bf7d-835a-47c1-a6b2-125495fa0900} OpenDiablo2.Core + + {c29a84e8-e708-4be2-9946-202899b68e19} + OpenDiablo2.GameServer + {05224fe7-293f-4184-b1d6-89f5171b60e0} OpenDiablo2.Scenes