1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-27 09:35:29 +00:00

Fleshed out mob management on server. Added player location message frame.

This commit is contained in:
Tim Sarbin 2018-12-01 02:44:40 -05:00
parent 1fc0eec1be
commit 1c5a0d3361
35 changed files with 461 additions and 349 deletions

View File

@ -27,7 +27,7 @@ namespace OpenDiablo2.Common.UT
2250, 2250,
4125, 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, vitality: herotypeconfig.StartingVitality,
strength: herotypeconfig.StartingStrength, strength: herotypeconfig.StartingStrength,
energy: herotypeconfig.StartingEnergy, energy: herotypeconfig.StartingEnergy,

View File

@ -6,11 +6,13 @@ using System.Threading.Tasks;
namespace OpenDiablo2.Common.Enums namespace OpenDiablo2.Common.Enums
{ {
// TODO: I don't think this needs to live in core...
public enum eMessageFrameType public enum eMessageFrameType
{ {
None = 0x00, None = 0x00,
SetSeed = 0x01, SetSeed = 0x01,
JoinGame = 0x02, JoinGame = 0x02,
LocatePlayers = 0x03,
MAX = 0xFF, // NOTE: MAX = 0xFF, // NOTE:
// You absolutely cannot have a higher ID than this without // You absolutely cannot have a higher ID than this without

View File

@ -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<MobState> FindInRadius(this IEnumerable<MobState> mobs, float centerx, float centery, float radius)
=> mobs.Where(x => x.GetDistance(centerx, centery) <= radius);
}
}

View File

@ -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<PlayerState> Players { get; }
int Seed { get; }
void InitializeNewGame();
int SpawnNewPlayer(int clientHash, string playerName, eHero heroType);
}
}

View File

@ -1,11 +1,10 @@
using System; using System.Drawing;
using System.Drawing;
using OpenDiablo2.Common.Models;
namespace OpenDiablo2.Common.Interfaces namespace OpenDiablo2.Common.Interfaces
{ {
public interface IMapEngine public interface IMapEngine
{ {
int FocusedMobId { get; set; }
PointF CameraLocation { get; set; } PointF CameraLocation { get; set; }
void Update(long ms); void Update(long ms);
void Render(); void Render();

View File

@ -9,6 +9,6 @@ namespace OpenDiablo2.Common.Interfaces
public interface IMessageFrame public interface IMessageFrame
{ {
byte[] Data { get; set; } byte[] Data { get; set; }
void Process(object sender, ISessionEventProvider sessionEventProvider); void Process(int clientHash, ISessionEventProvider sessionEventProvider);
} }
} }

View File

@ -1,18 +1,18 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using OpenDiablo2.Common.Enums;
using System.Text; using OpenDiablo2.Common.Interfaces.MessageBus;
using System.Threading.Tasks;
namespace OpenDiablo2.Common.Interfaces namespace OpenDiablo2.Common.Interfaces
{ {
public delegate void OnSetSeedEvent(object sender, int seed); public delegate void OnSetSeedEvent(int clientHash, int seed);
public delegate void OnJoinGameEvent(object sender, Guid playerId, string playerName); // TODO: Not the final version.. public delegate void OnJoinGameEvent(int clientHash, eHero heroType, string playerName);
public delegate void OnLocatePlayersEvent(int clientHash, IEnumerable<PlayerLocationDetails> playerLocationDetails);
public interface ISessionEventProvider public interface ISessionEventProvider
{ {
OnSetSeedEvent OnSetSeed { get; set; } OnSetSeedEvent OnSetSeed { get; set; }
OnJoinGameEvent OnJoinGame { get; set; } OnJoinGameEvent OnJoinGame { get; set; }
OnLocatePlayersEvent OnLocatePlayers { get; set; }
} }
} }

View File

@ -3,15 +3,18 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using OpenDiablo2.Common.Enums;
namespace OpenDiablo2.Common.Interfaces namespace OpenDiablo2.Common.Interfaces
{ {
public interface ISessionManager : ISessionEventProvider, IDisposable public interface ISessionManager : ISessionEventProvider, IDisposable
{ {
Guid PlayerId { get; }
void Initialize(); void Initialize();
void Stop(); void Stop();
void JoinGame(string playerName, Action<Guid> callback); void JoinGame(string playerName, eHero heroType);
} }
} }

View File

@ -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<byte>();
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
};
}
}

View File

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

View File

@ -1,13 +1,22 @@
using System; using System.Collections.Generic;
using System.Collections.Generic; using OpenDiablo2.Common.Models.Mobs;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenDiablo2.Common.Interfaces.Mobs namespace OpenDiablo2.Common.Interfaces.Mobs
{ {
public interface IMobManager public interface IMobManager
{ {
// TODO: IEnumerable<MobState> Mobs { get; }
IEnumerable<PlayerState> Players { get; }
IEnumerable<EnemyState> 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);
} }
} }

View File

@ -1,9 +1,4 @@
using OpenDiablo2.Common.Enums.Mobs; 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 namespace OpenDiablo2.Common.Models.Mobs
{ {
@ -11,6 +6,8 @@ namespace OpenDiablo2.Common.Models.Mobs
{ {
public int ExperienceGiven { get; protected set; } 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) public EnemyState(string name, int id, int level, int maxhealth, float x, float y, int experiencegiven)
: base(name, id, level, maxhealth, x, y) : base(name, id, level, maxhealth, x, y)
{ {

View File

@ -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<IMobCondition> Conditions = new List<IMobCondition>();
public MobConditionAnd(List<IMobCondition> 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<IMobCondition> Conditions = new List<IMobCondition>();
public MobConditionOr(List<IMobCondition> 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<eMobFlags, bool> Flags = new Dictionary<eMobFlags, bool>();
public MobConditionFlags(Dictionary<eMobFlags, bool> 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
}

View File

@ -1,14 +1,11 @@
using OpenDiablo2.Common.Enums.Mobs; using System;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq; using OpenDiablo2.Common.Enums.Mobs;
using System.Text;
using System.Threading.Tasks;
namespace OpenDiablo2.Common.Models.Mobs namespace OpenDiablo2.Common.Models.Mobs
{ {
public class MobState public class MobState : IComparable
{ {
public readonly string Name; public readonly string Name;
public readonly int Id; public readonly int Id;
@ -26,6 +23,8 @@ namespace OpenDiablo2.Common.Models.Mobs
protected Dictionary<eMobFlags, bool> Flags = new Dictionary<eMobFlags, bool>(); protected Dictionary<eMobFlags, bool> Flags = new Dictionary<eMobFlags, bool>();
public MobState() { }
public MobState(string name, int id, int level, int maxhealth, float x, float y) public MobState(string name, int id, int level, int maxhealth, float x, float y)
{ {
Name = name; Name = name;
@ -163,6 +162,10 @@ namespace OpenDiablo2.Common.Models.Mobs
} }
return false; return false;
} }
#endregion Flags #endregion Flags
public int CompareTo(object obj) => Id - ((MobState)obj).Id;
} }
} }

View File

@ -1,27 +1,23 @@
using OpenDiablo2.Common.Enums; using System;
using OpenDiablo2.Common.Enums;
using OpenDiablo2.Common.Enums.Mobs; using OpenDiablo2.Common.Enums.Mobs;
using OpenDiablo2.Common.Interfaces.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 namespace OpenDiablo2.Common.Models.Mobs
{ {
public class PlayerState : MobState public class PlayerState : MobState
{ {
public Guid Id { get; protected set; }
public eHero HeroType { get; protected set; } public eHero HeroType { get; protected set; }
private IHeroTypeConfig HeroTypeConfig; private IHeroTypeConfig HeroTypeConfig;
private ILevelExperienceConfig ExperienceConfig; private ILevelExperienceConfig ExperienceConfig;
public int ClientHash { get; protected set; }
// Player character stats // Player character stats
protected Stat Vitality; protected Stat Vitality;
protected Stat Strength; protected Stat Strength;
protected Stat Energy; protected Stat Energy;
protected Stat Dexterity; protected Stat Dexterity;
protected Stat DefenseRating; protected Stat DefenseRating;
protected Stat AttackRating; protected Stat AttackRating;
@ -30,11 +26,14 @@ namespace OpenDiablo2.Common.Models.Mobs
public int Experience { get; protected set; } public int Experience { get; protected set; }
public PlayerState(string name, int id, int level, float x, float y, public PlayerState() : base() { }
int vitality, int strength, int energy, int dexterity, int experience, eHero herotype,
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) IHeroTypeConfig heroconfig, ILevelExperienceConfig expconfig)
: base(name, id, level, 0, x, y) : base(name, id, level, 0, x, y)
{ {
this.ClientHash = clientHash;
Stamina = new Stat(0, 0, 0, true); Stamina = new Stat(0, 0, 0, true);
Mana = 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); Energy = new Stat(0, energy, energy, true);
Dexterity = new Stat(0, dexterity, dexterity, 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); DefenseRating = new Stat(0, 0, 0, false);
Experience = experience; // how much total exp do they have Experience = experience; // how much total exp do they have
@ -82,11 +81,11 @@ namespace OpenDiablo2.Common.Models.Mobs
} }
public bool TryLevelUp() public bool TryLevelUp()
{ {
if(Level >= GetMaxLevel()) if (Level >= GetMaxLevel())
{ {
return false; // can't level up anymore return false; // can't level up anymore
} }
if(GetExperienceToLevel() > 0) if (GetExperienceToLevel() > 0)
{ {
return false; // not enough exp return false; // not enough exp
} }

View File

@ -69,10 +69,13 @@
<Compile Include="Enums\Mobs\eDamageTypes.cs" /> <Compile Include="Enums\Mobs\eDamageTypes.cs" />
<Compile Include="Enums\Mobs\eMobFlags.cs" /> <Compile Include="Enums\Mobs\eMobFlags.cs" />
<Compile Include="Enums\Mobs\eStatModifierType.cs" /> <Compile Include="Enums\Mobs\eStatModifierType.cs" />
<Compile Include="Extensions\MobManagerExtensions.cs" />
<Compile Include="Interfaces\IGameServer.cs" />
<Compile Include="Interfaces\MessageBus\ISessionEventProvider.cs" /> <Compile Include="Interfaces\MessageBus\ISessionEventProvider.cs" />
<Compile Include="Interfaces\MessageBus\IMessageFrame.cs" /> <Compile Include="Interfaces\MessageBus\IMessageFrame.cs" />
<Compile Include="Interfaces\MessageBus\ISessionManager.cs" /> <Compile Include="Interfaces\MessageBus\ISessionManager.cs" />
<Compile Include="Interfaces\MessageBus\ISessionServer.cs" /> <Compile Include="Interfaces\MessageBus\ISessionServer.cs" />
<Compile Include="Interfaces\MessageBus\PlayerLocationDetails.cs" />
<Compile Include="Interfaces\UI\IButton.cs" /> <Compile Include="Interfaces\UI\IButton.cs" />
<Compile Include="Interfaces\UI\IPanelFrame.cs" /> <Compile Include="Interfaces\UI\IPanelFrame.cs" />
<Compile Include="Interfaces\UI\IInventoryPanel.cs" /> <Compile Include="Interfaces\UI\IInventoryPanel.cs" />
@ -101,7 +104,6 @@
<Compile Include="Interfaces\Drawing\ITexture.cs" /> <Compile Include="Interfaces\Drawing\ITexture.cs" />
<Compile Include="Interfaces\Mobs\IHeroTypeConfig.cs" /> <Compile Include="Interfaces\Mobs\IHeroTypeConfig.cs" />
<Compile Include="Interfaces\Mobs\ILevelExperienceConfig.cs" /> <Compile Include="Interfaces\Mobs\ILevelExperienceConfig.cs" />
<Compile Include="Interfaces\Mobs\IMobCondition.cs" />
<Compile Include="Interfaces\Mobs\IMobManager.cs" /> <Compile Include="Interfaces\Mobs\IMobManager.cs" />
<Compile Include="Interfaces\Mobs\IStatModifier.cs" /> <Compile Include="Interfaces\Mobs\IStatModifier.cs" />
<Compile Include="Models\BitStream.cs" /> <Compile Include="Models\BitStream.cs" />
@ -114,7 +116,6 @@
<Compile Include="Models\Mobs\EnemyState.cs" /> <Compile Include="Models\Mobs\EnemyState.cs" />
<Compile Include="Models\Mobs\HeroTypeConfig.cs" /> <Compile Include="Models\Mobs\HeroTypeConfig.cs" />
<Compile Include="Models\Mobs\LevelExperienceConfig.cs" /> <Compile Include="Models\Mobs\LevelExperienceConfig.cs" />
<Compile Include="Models\Mobs\MobCondition.cs" />
<Compile Include="Models\Mobs\MobState.cs" /> <Compile Include="Models\Mobs\MobState.cs" />
<Compile Include="Models\Mobs\PlayerState.cs" /> <Compile Include="Models\Mobs\PlayerState.cs" />
<Compile Include="Models\Mobs\Stat.cs" /> <Compile Include="Models\Mobs\Stat.cs" />

View File

@ -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.Enums.Mobs;
using OpenDiablo2.Common.Extensions;
using OpenDiablo2.Common.Models.Mobs; using OpenDiablo2.Common.Models.Mobs;
using OpenDiablo2.Core.GameState_; 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 namespace OpenDiablo2.Core.UT
{ {
@ -19,34 +15,21 @@ namespace OpenDiablo2.Core.UT
{ {
MobManager mobman = new MobManager(); MobManager mobman = new MobManager();
MobState mob1 = new MobState("test1", mobman.GetNextAvailableMobId(), 1, 100, 0, 0); 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); 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.ENEMY);
mob2.AddFlag(eMobFlags.INVULNERABLE); mob2.AddFlag(eMobFlags.INVULNERABLE);
mobman.AddMob(mob1);
mobman.AddMob(mob2); mobman.AddMob(mob2);
MobState mob3 = new MobState("test3", mobman.GetNextAvailableMobId(), 1, 100, 0, 0);
mobman.AddMob(mob3); mobman.AddMob(mob3);
Assert.IsTrue(mobman.FindMobs(new MobConditionFlags( Assert.IsTrue(mobman.Mobs.Count(x => x.HasFlag(eMobFlags.ENEMY)) == 2);
new Dictionary<eMobFlags, bool> { Assert.IsTrue(mobman.Mobs.Count(x => x.HasFlag(eMobFlags.INVULNERABLE)) == 1);
{ eMobFlags.ENEMY, true } Assert.IsTrue(mobman.Mobs.Count(x => x.HasFlag(eMobFlags.PLAYER)) == 0);
})).Count == 2); Assert.IsTrue(mobman.Mobs.Count(x => !x.HasFlag(eMobFlags.PLAYER)) == 3);
Assert.IsTrue(mobman.FindMobs(new MobConditionFlags(
new Dictionary<eMobFlags, bool> {
{ eMobFlags.INVULNERABLE, true }
})).Count == 1);
Assert.IsTrue(mobman.FindMobs(new MobConditionFlags(
new Dictionary<eMobFlags, bool> {
{ eMobFlags.PLAYER, true }
})).Count == 0);
Assert.IsTrue(mobman.FindMobs(new MobConditionFlags(
new Dictionary<eMobFlags, bool> {
{ eMobFlags.PLAYER, false }
})).Count == 3);
} }
[TestMethod] [TestMethod]
@ -54,19 +37,21 @@ namespace OpenDiablo2.Core.UT
{ {
MobManager mobman = new MobManager(); MobManager mobman = new MobManager();
MobState mob1 = new MobState("test1", mobman.GetNextAvailableMobId(), 1, 100, 0, 0); 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); 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.ENEMY);
mob2.AddFlag(eMobFlags.INVULNERABLE); mob2.AddFlag(eMobFlags.INVULNERABLE);
mobman.AddMob(mob1);
mobman.AddMob(mob2); mobman.AddMob(mob2);
MobState mob3 = new MobState("test3", mobman.GetNextAvailableMobId(), 1, 100, 3, 1);
mobman.AddMob(mob3); mobman.AddMob(mob3);
Assert.IsTrue(mobman.FindMobsInRadius(0, 0, 1, null).Count == 1); Assert.IsTrue(mobman.Mobs.FindInRadius(0, 0, 1).Count() == 1);
Assert.IsTrue(mobman.FindMobsInRadius(0, 0, 7, null).Count == 2); Assert.IsTrue(mobman.Mobs.FindInRadius(0, 0, 7).Count() == 2);
Assert.IsTrue(mobman.FindMobsInRadius(0, 0, 20, null).Count == 3); Assert.IsTrue(mobman.Mobs.FindInRadius(0, 0, 20).Count() == 3);
Assert.IsTrue(mobman.FindMobsInRadius(10, 10, 1, null).Count == 1); Assert.IsTrue(mobman.Mobs.FindInRadius(10, 10, 1).Count() == 1);
} }
} }
} }

View File

@ -1,5 +1,6 @@
using Autofac; using Autofac;
using OpenDiablo2.Common.Interfaces; using OpenDiablo2.Common.Interfaces;
using OpenDiablo2.Common.Interfaces.Mobs;
using OpenDiablo2.Core.GameState_; using OpenDiablo2.Core.GameState_;
using OpenDiablo2.Core.Map_Engine; using OpenDiablo2.Core.Map_Engine;
using OpenDiablo2.Core.UI; using OpenDiablo2.Core.UI;
@ -27,6 +28,8 @@ namespace OpenDiablo2.Core
builder.RegisterType<ResourceManager>().As<IResourceManager>().SingleInstance(); builder.RegisterType<ResourceManager>().As<IResourceManager>().SingleInstance();
builder.RegisterType<TextDictionary>().As<ITextDictionary>().SingleInstance(); builder.RegisterType<TextDictionary>().As<ITextDictionary>().SingleInstance();
builder.RegisterType<TextBox>().As<ITextBox>().InstancePerDependency(); builder.RegisterType<TextBox>().As<ITextBox>().InstancePerDependency();
builder.RegisterType<MobManager>().As<IMobManager>().SingleInstance(); // TODO: This needs to have client and server versions...
} }
} }
} }

View File

@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;

View File

@ -4,6 +4,7 @@ using System.Drawing;
using System.Linq; using System.Linq;
using OpenDiablo2.Common.Enums; using OpenDiablo2.Common.Enums;
using OpenDiablo2.Common.Interfaces; using OpenDiablo2.Common.Interfaces;
using OpenDiablo2.Common.Interfaces.MessageBus;
using OpenDiablo2.Common.Models; using OpenDiablo2.Common.Models;
using OpenDiablo2.Core.Map_Engine; using OpenDiablo2.Core.Map_Engine;
@ -21,7 +22,6 @@ namespace OpenDiablo2.Core.GameState_
private readonly Func<IMapEngine> getMapEngine; private readonly Func<IMapEngine> getMapEngine;
private readonly Func<eSessionType, ISessionManager> getSessionManager; private readonly Func<eSessionType, ISessionManager> getSessionManager;
private Guid playerId;
private float animationTime = 0f; private float animationTime = 0f;
private List<MapInfo> mapInfo; private List<MapInfo> mapInfo;
private List<MapCellInfo> mapDataLookup = new List<MapCellInfo>(); private List<MapCellInfo> mapDataLookup = new List<MapCellInfo>();
@ -30,6 +30,7 @@ namespace OpenDiablo2.Core.GameState_
public int Act { get; private set; } public int Act { get; private set; }
public string MapName { get; private set; } public string MapName { get; private set; }
public Palette CurrentPalette => paletteProvider.PaletteTable[$"ACT{Act}"]; public Palette CurrentPalette => paletteProvider.PaletteTable[$"ACT{Act}"];
public IEnumerable<PlayerLocationDetails> PlayerLocationDetails { get; private set; } = new List<PlayerLocationDetails>();
public bool ShowInventoryPanel { get; set; } = false; public bool ShowInventoryPanel { get; set; } = false;
public bool ShowCharacterPanel { get; set; } = false; public bool ShowCharacterPanel { get; set; } = false;
@ -64,19 +65,20 @@ namespace OpenDiablo2.Core.GameState_
sessionManager.Initialize(); sessionManager.Initialize();
sessionManager.OnSetSeed += OnSetSeedEvent; sessionManager.OnSetSeed += OnSetSeedEvent;
sessionManager.OnLocatePlayers += OnLocatePlayers;
mapInfo = new List<MapInfo>(); mapInfo = new List<MapInfo>();
sceneManager.ChangeScene("Game"); sceneManager.ChangeScene("Game");
sessionManager.JoinGame(characterName, (id) => sessionManager.JoinGame(characterName, hero);
{
log.Info("hoo");
playerId = id;
}); // TODO: we need more attributes...
log.Info("woo");
} }
private void OnSetSeedEvent(object sender, int seed) private void OnLocatePlayers(int clientHash, IEnumerable<PlayerLocationDetails> playerLocationDetails)
{
PlayerLocationDetails = playerLocationDetails;
}
private void OnSetSeedEvent(int clientHash, int seed)
{ {
log.Info($"Setting seed to {seed}"); log.Info($"Setting seed to {seed}");
this.Seed = seed; this.Seed = seed;
@ -224,15 +226,7 @@ namespace OpenDiablo2.Core.GameState_
return ShowCharacterPanel; 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)) if (!map.CellInfo.ContainsKey(cellType))
{ {

View File

@ -1,20 +1,21 @@
using OpenDiablo2.Common.Enums; using System;
using System.Collections.Generic;
using OpenDiablo2.Common.Interfaces.Mobs; using OpenDiablo2.Common.Interfaces.Mobs;
using OpenDiablo2.Common.Models.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_ namespace OpenDiablo2.Core.GameState_
{ {
public class MobManager : IMobManager public class MobManager : IMobManager
{ {
private List<MobState> Mobs = new List<MobState>(); // all mobs (including players!) public HashSet<MobState> Mobs { get; private set; } = new HashSet<MobState>(); // all mobs (including players!)
private List<PlayerState> Players = new List<PlayerState>(); public HashSet<PlayerState> Players { get; private set; } = new HashSet<PlayerState>();
private List<EnemyState> Enemies = new List<EnemyState>(); public HashSet<EnemyState> Enemies { get; private set;} = new HashSet<EnemyState>();
private List<int> IdsUsed = new List<int>();
IEnumerable<MobState> IMobManager.Mobs => Mobs;
IEnumerable<PlayerState> IMobManager.Players => Players;
IEnumerable<EnemyState> IMobManager.Enemies => Enemies;
private HashSet<int> IdsUsed = new HashSet<int>();
#region Player Controls #region Player Controls
public void AddPlayer(PlayerState player) public void AddPlayer(PlayerState player)
@ -33,22 +34,9 @@ namespace OpenDiablo2.Core.GameState_
public void AddMob(MobState mob) public void AddMob(MobState mob)
{ {
Mobs.Add(mob); Mobs.Add(mob);
// add id to idsused in order if (IdsUsed.Contains(mob.Id))
int i = 0; throw new ApplicationException("Tried to insert an existing mob id!");
while(i < IdsUsed.Count) IdsUsed.Add(mob.Id);
{
if(IdsUsed[i] > mob.Id)
{
IdsUsed.Insert(i, mob.Id);
break;
}
i++;
}
if(i == IdsUsed.Count)
{
// didn't get added
IdsUsed.Add(mob.Id);
}
} }
public void RemoveMob(MobState mob) public void RemoveMob(MobState mob)
{ {
@ -57,16 +45,11 @@ namespace OpenDiablo2.Core.GameState_
} }
public int GetNextAvailableMobId() public int GetNextAvailableMobId()
{ {
int i = 0; for (var i = 1; i < int.MaxValue; i++)
while(i < IdsUsed.Count) if (!IdsUsed.Contains(i))
{
if(IdsUsed[i] != i)
{
return i; return i;
}
i++; throw new ApplicationException("Ran out of IDs. How did this even happen?!");
}
return IdsUsed.Count;
} }
#endregion Mob Controls #endregion Mob Controls
@ -83,59 +66,5 @@ namespace OpenDiablo2.Core.GameState_
} }
#endregion Enemy Controls #endregion Enemy Controls
#region Searching and Filtering
public List<MobState> FilterMobs(IEnumerable<MobState> mobs, IMobCondition condition)
{
// note: if condition is null, returns full list
List<MobState> filtered = new List<MobState>();
foreach(MobState mob in mobs)
{
if (condition == null || condition.Evaluate(mob))
{
filtered.Add(mob);
}
}
return filtered;
}
public List<MobState> FindMobs(IMobCondition condition)
{
return FilterMobs(Mobs, condition);
}
public List<MobState> FindEnemies(IMobCondition condition)
{
return FilterMobs(Enemies, condition);
}
public List<MobState> FindPlayers(IMobCondition condition)
{
return FilterMobs(Players, condition);
}
public List<MobState> FindInRadius(IEnumerable<MobState> mobs, float centerx, float centery, float radius)
{
List<MobState> filtered = new List<MobState>();
foreach(MobState mob in mobs)
{
if(mob.GetDistance(centerx, centery) <= radius)
{
filtered.Add(mob);
}
}
return filtered;
}
public List<MobState> FindMobsInRadius(float centerx, float centery, float radius, IMobCondition condition)
{
return FilterMobs(FindInRadius(Mobs, centerx, centery, radius), condition);
}
public List<MobState> FindEnemiesInRadius(float centerx, float centery, float radius, IMobCondition condition)
{
return FilterMobs(FindInRadius(Enemies, centerx, centery, radius), condition);
}
public List<MobState> FindPlayersInRadius(float centerx, float centery, float radius, IMobCondition condition)
{
return FilterMobs(FindInRadius(Players, centerx, centery, radius), condition);
}
#endregion Searching and Filtering
} }
} }

View File

@ -12,6 +12,8 @@ namespace OpenDiablo2.Core.Map_Engine
private readonly IRenderWindow renderWindow; private readonly IRenderWindow renderWindow;
private readonly IResourceManager resourceManager; private readonly IResourceManager resourceManager;
public int FocusedMobId { get; set; } = -1;
private PointF cameraLocation = new PointF(); private PointF cameraLocation = new PointF();
public PointF CameraLocation public PointF CameraLocation
{ {

View File

@ -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<GameServer>().As<IGameServer>().SingleInstance();
}
}
}

View File

@ -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<PlayerState> 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<int>() { 100 }));
mobManager.AddPlayer(newPlayer);
return newPlayer.Id;
}
public void Dispose()
{
}
}
}

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{C29A84E8-E708-4BE2-9946-202899B68E19}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>OpenDiablo2.GameServer</RootNamespace>
<AssemblyName>OpenDiablo2.GameServer</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Autofac, Version=4.8.1.0, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL">
<HintPath>..\packages\Autofac.4.8.1\lib\net45\Autofac.dll</HintPath>
</Reference>
<Reference Include="log4net, Version=2.0.8.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<HintPath>..\packages\log4net.2.0.8\lib\net45-full\log4net.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="AutofacModule.cs" />
<Compile Include="GameServer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenDiablo2.Common\OpenDiablo2.Common.csproj">
<Project>{b743160e-a0bb-45dc-9998-967a85e50562}</Project>
<Name>OpenDiablo2.Common</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -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")]

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Autofac" version="4.8.1" targetFramework="net461" />
<package id="log4net" version="2.0.8" targetFramework="net461" />
</packages>

View File

@ -5,18 +5,19 @@ using OpenDiablo2.Common.Attributes;
using OpenDiablo2.Common.Enums; using OpenDiablo2.Common.Enums;
using OpenDiablo2.Common.Interfaces; using OpenDiablo2.Common.Interfaces;
namespace OpenDiablo2.ServiceBus.Message_Frames namespace OpenDiablo2.ServiceBus.Message_Frames.Client
{ {
[MessageFrame(eMessageFrameType.JoinGame)] [MessageFrame(eMessageFrameType.JoinGame)]
public sealed class MFJoinGame : IMessageFrame public sealed class MFJoinGame : IMessageFrame
{ {
public Guid PlayerId { get; set; }
public string PlayerName { get; set; } public string PlayerName { get; set; }
public eHero HeroType { get; set; }
public byte[] Data public byte[] Data
{ {
get get
{ {
return PlayerId.ToByteArray() return new byte[] { (byte)HeroType }
.Concat(BitConverter.GetBytes((UInt16)PlayerName.Length)) .Concat(BitConverter.GetBytes((UInt16)PlayerName.Length))
.Concat(Encoding.UTF8.GetBytes(PlayerName)) .Concat(Encoding.UTF8.GetBytes(PlayerName))
.ToArray(); .ToArray();
@ -24,10 +25,9 @@ namespace OpenDiablo2.ServiceBus.Message_Frames
set set
{ {
HeroType = (eHero)value[0];
PlayerId = new Guid(value.Take(16).ToArray()); var playerNameLen = BitConverter.ToUInt16(value, 1);
var playerNameLen = BitConverter.ToUInt16(value, 16); PlayerName = Encoding.UTF8.GetString(value, 3, value.Length - 3);
PlayerName = Encoding.UTF8.GetString(value, 18, value.Length - 18);
if (PlayerName.Length != playerNameLen) if (PlayerName.Length != playerNameLen)
throw new ApplicationException("Invalid player length!"); throw new ApplicationException("Invalid player length!");
@ -35,15 +35,15 @@ namespace OpenDiablo2.ServiceBus.Message_Frames
} }
public MFJoinGame() { } public MFJoinGame() { }
public MFJoinGame(string playerName) public MFJoinGame(string playerName, eHero heroType)
{ {
PlayerId = Guid.NewGuid();
PlayerName = playerName; 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);
} }
} }
} }

View File

@ -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<PlayerLocationDetails> LocationDetails { get; set; }
public byte[] Data
{
get
{
var result = new List<byte>();
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<PlayerLocationDetails>();
for(var i = 0; i < count; i++)
{
result.Add(PlayerLocationDetails.FromBytes(value, 2 + (i * PlayerLocationDetails.SizeInBytes)));
}
LocationDetails = result;
}
}
public MFLocatePlayers() { }
public MFLocatePlayers(IEnumerable<PlayerLocationDetails> locationDetails)
{
this.LocationDetails = locationDetails;
}
public void Process(int clientHash, ISessionEventProvider sessionEventProvider)
=> sessionEventProvider.OnLocatePlayers(clientHash, LocationDetails);
}
}

View File

@ -3,7 +3,7 @@ using OpenDiablo2.Common.Attributes;
using OpenDiablo2.Common.Enums; using OpenDiablo2.Common.Enums;
using OpenDiablo2.Common.Interfaces; using OpenDiablo2.Common.Interfaces;
namespace OpenDiablo2.ServiceBus.Message_Frames namespace OpenDiablo2.ServiceBus.Message_Frames.Server
{ {
[MessageFrame(eMessageFrameType.SetSeed)] [MessageFrame(eMessageFrameType.SetSeed)]
public sealed class MFSetSeed : IMessageFrame public sealed class MFSetSeed : IMessageFrame
@ -19,7 +19,6 @@ namespace OpenDiablo2.ServiceBus.Message_Frames
public MFSetSeed() public MFSetSeed()
{ {
Seed = (new Random()).Next();
} }
public MFSetSeed(int seed) public MFSetSeed(int seed)
@ -27,9 +26,8 @@ namespace OpenDiablo2.ServiceBus.Message_Frames
Seed = seed; Seed = seed;
} }
public void Process(object sender, ISessionEventProvider sessionEventProvider) public void Process(int clientHash, ISessionEventProvider sessionEventProvider)
{ => sessionEventProvider.OnSetSeed?.Invoke(clientHash, Seed);
sessionEventProvider.OnSetSeed?.Invoke(sender, Seed);
}
} }
} }

View File

@ -21,6 +21,7 @@
<PlatformTarget>x64</PlatformTarget> <PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath> <OutputPath>bin\x64\Release\</OutputPath>
@ -30,6 +31,7 @@
<PlatformTarget>x64</PlatformTarget> <PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="AsyncIO, Version=0.1.61.0, Culture=neutral, PublicKeyToken=44a94435bd6f33f8, processorArchitecture=MSIL"> <Reference Include="AsyncIO, Version=0.1.61.0, Culture=neutral, PublicKeyToken=44a94435bd6f33f8, processorArchitecture=MSIL">
@ -56,8 +58,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="AutofacModule.cs" /> <Compile Include="AutofacModule.cs" />
<Compile Include="Message Frames\MFJoinGame.cs" /> <Compile Include="Message Frames\Client\MFJoinGame.cs" />
<Compile Include="Message Frames\MFSetSeed.cs" /> <Compile Include="Message Frames\Server\MFLocatePlayers.cs" />
<Compile Include="Message Frames\Server\MFSetSeed.cs" />
<Compile Include="SessionManager.cs" /> <Compile Include="SessionManager.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SessionServer.cs" /> <Compile Include="SessionServer.cs" />

View File

@ -7,7 +7,8 @@ using NetMQ.Sockets;
using OpenDiablo2.Common.Attributes; using OpenDiablo2.Common.Attributes;
using OpenDiablo2.Common.Enums; using OpenDiablo2.Common.Enums;
using OpenDiablo2.Common.Interfaces; using OpenDiablo2.Common.Interfaces;
using OpenDiablo2.ServiceBus.Message_Frames; using OpenDiablo2.ServiceBus.Message_Frames.Client;
using OpenDiablo2.ServiceBus.Message_Frames.Server;
namespace OpenDiablo2.ServiceBus namespace OpenDiablo2.ServiceBus
{ {
@ -23,11 +24,12 @@ namespace OpenDiablo2.ServiceBus
private RequestSocket requestSocket; private RequestSocket requestSocket;
private AutoResetEvent resetEvent = new AutoResetEvent(false); private AutoResetEvent resetEvent = new AutoResetEvent(false);
private ISessionServer sessionServer; private ISessionServer sessionServer;
private Guid playerId; public Guid PlayerId { get; private set; }
private bool running = false; private bool running = false;
public OnSetSeedEvent OnSetSeed { get; set; } public OnSetSeedEvent OnSetSeed { get; set; }
public OnJoinGameEvent OnJoinGame { get; set; } public OnJoinGameEvent OnJoinGame { get; set; }
public OnLocatePlayersEvent OnLocatePlayers { get; set; }
public SessionManager( public SessionManager(
eSessionType sessionType, eSessionType sessionType,
@ -71,15 +73,7 @@ namespace OpenDiablo2.ServiceBus
default: default:
throw new ApplicationException("This session type is currently unsupported."); 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; running = true;
resetEvent.WaitOne(); resetEvent.WaitOne();
running = false; running = false;
@ -124,22 +118,17 @@ namespace OpenDiablo2.ServiceBus
messageFrame.Data = frameData; messageFrame.Data = frameData;
lock (getGameState().ThreadLocker) lock (getGameState().ThreadLocker)
{ {
messageFrame.Process(requestSocket, this); messageFrame.Process(requestSocket.GetHashCode(), this);
} }
} }
public void JoinGame(string playerName, Action<Guid> callback) public void JoinGame(string playerName, eHero heroType)
{ {
Task.Run(() => Task.Run(() =>
{ {
var mf = new MFJoinGame(playerName); Send(new MFJoinGame(playerName, heroType));
playerId = mf.PlayerId;
Send(mf);
ProcessMessageFrame<MFSetSeed>(); ProcessMessageFrame<MFSetSeed>();
lock (getGameState().ThreadLocker) ProcessMessageFrame<MFLocatePlayers>();
{
callback(playerId);
}
}); });
} }
} }

View File

@ -7,7 +7,8 @@ using NetMQ.Sockets;
using OpenDiablo2.Common.Attributes; using OpenDiablo2.Common.Attributes;
using OpenDiablo2.Common.Enums; using OpenDiablo2.Common.Enums;
using OpenDiablo2.Common.Interfaces; using OpenDiablo2.Common.Interfaces;
using OpenDiablo2.ServiceBus.Message_Frames; using OpenDiablo2.Common.Interfaces.MessageBus;
using OpenDiablo2.ServiceBus.Message_Frames.Server;
namespace OpenDiablo2.ServiceBus 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 static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private readonly eSessionType sessionType; private readonly eSessionType sessionType;
private readonly IGameServer gameServer;
private readonly Func<eMessageFrameType, IMessageFrame> getMessageFrame; private readonly Func<eMessageFrameType, IMessageFrame> getMessageFrame;
private AutoResetEvent resetEvent = new AutoResetEvent(false); private AutoResetEvent resetEvent = new AutoResetEvent(false);
public AutoResetEvent WaitServerStartEvent { get; set; } = new AutoResetEvent(false); public AutoResetEvent WaitServerStartEvent { get; set; } = new AutoResetEvent(false);
private int gameSeed;
private bool running = false; private bool running = false;
private ResponseSocket responseSocket; private ResponseSocket responseSocket;
public OnSetSeedEvent OnSetSeed { get; set; } public OnSetSeedEvent OnSetSeed { get; set; }
public OnJoinGameEvent OnJoinGame { get; set; } public OnJoinGameEvent OnJoinGame { get; set; }
public OnLocatePlayersEvent OnLocatePlayers { get; set; }
public SessionServer(eSessionType sessionType, Func<eMessageFrameType, IMessageFrame> getMessageFrame) public SessionServer(
eSessionType sessionType,
IGameServer gameServer,
Func<eMessageFrameType, IMessageFrame> getMessageFrame
)
{ {
this.sessionType = sessionType; this.sessionType = sessionType;
this.getMessageFrame = getMessageFrame; this.getMessageFrame = getMessageFrame;
this.gameServer = gameServer;
} }
public void Start() public void Start()
{ {
gameSeed = (new Random()).Next(); // TODO: Loading existing games...
gameServer.InitializeNewGame();
Task.Run(() => Serve()); 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 frameData = bytes.Skip(1).ToArray(); // TODO: Can we maybe use pointers? This seems wasteful
var messageFrame = getMessageFrame(frameType); var messageFrame = getMessageFrame(frameType);
messageFrame.Data = frameData; messageFrame.Data = frameData;
messageFrame.Process(socket, this); messageFrame.Process(socket.GetHashCode(), this);
}); });
running = true; running = true;
WaitServerStartEvent.Set(); WaitServerStartEvent.Set();
@ -89,16 +98,17 @@ namespace OpenDiablo2.ServiceBus
Stop(); 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; 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 gameServer.SpawnNewPlayer(clientHash, playerName, heroType);
Send(sender as NetMQSocket, new MFSetSeed(gameSeed)); Send(new MFSetSeed(gameServer.Seed), true);
Send(new MFLocatePlayers(gameServer.Players.Select(x => x.ToPlayerLocationDetails())));
} }
} }
} }

View File

@ -25,6 +25,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{1FAD6E2F
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenDiablo2.ServiceBus", "OpenDiablo2.ServiceBus\OpenDiablo2.ServiceBus.csproj", "{D3F0F44F-2AB4-4342-A684-53193032A621}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenDiablo2.ServiceBus", "OpenDiablo2.ServiceBus\OpenDiablo2.ServiceBus.csproj", "{D3F0F44F-2AB4-4342-A684-53193032A621}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenDiablo2.GameServer", "OpenDiablo2.GameServer\OpenDiablo2.GameServer.csproj", "{C29A84E8-E708-4BE2-9946-202899B68E19}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64 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}.Debug|x64.Build.0 = Debug|x64
{D3F0F44F-2AB4-4342-A684-53193032A621}.Release|x64.ActiveCfg = Release|x64 {D3F0F44F-2AB4-4342-A684-53193032A621}.Release|x64.ActiveCfg = Release|x64
{D3F0F44F-2AB4-4342-A684-53193032A621}.Release|x64.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -5,7 +5,7 @@
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{2B0CF1AC-06DD-4322-AE8B-FF8A8C70A3CD}</ProjectGuid> <ProjectGuid>{2B0CF1AC-06DD-4322-AE8B-FF8A8C70A3CD}</ProjectGuid>
<OutputType>Exe</OutputType> <OutputType>WinExe</OutputType>
<RootNamespace>OpenDiablo2</RootNamespace> <RootNamespace>OpenDiablo2</RootNamespace>
<AssemblyName>OpenDiablo2</AssemblyName> <AssemblyName>OpenDiablo2</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
@ -99,6 +99,10 @@
<Project>{8fc6bf7d-835a-47c1-a6b2-125495fa0900}</Project> <Project>{8fc6bf7d-835a-47c1-a6b2-125495fa0900}</Project>
<Name>OpenDiablo2.Core</Name> <Name>OpenDiablo2.Core</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\OpenDiablo2.GameServer\OpenDiablo2.GameServer.csproj">
<Project>{c29a84e8-e708-4be2-9946-202899b68e19}</Project>
<Name>OpenDiablo2.GameServer</Name>
</ProjectReference>
<ProjectReference Include="..\OpenDiablo2.Scenes\OpenDiablo2.Scenes.csproj"> <ProjectReference Include="..\OpenDiablo2.Scenes\OpenDiablo2.Scenes.csproj">
<Project>{05224fe7-293f-4184-b1d6-89f5171b60e0}</Project> <Project>{05224fe7-293f-4184-b1d6-89f5171b60e0}</Project>
<Name>OpenDiablo2.Scenes</Name> <Name>OpenDiablo2.Scenes</Name>