diff --git a/OpenDiablo2.Common/Attributes/MessageFrameAttribute.cs b/OpenDiablo2.Common/Attributes/MessageFrameAttribute.cs
new file mode 100644
index 00000000..34cac939
--- /dev/null
+++ b/OpenDiablo2.Common/Attributes/MessageFrameAttribute.cs
@@ -0,0 +1,19 @@
+using System;
+using OpenDiablo2.Common.Enums;
+
+namespace OpenDiablo2.Common.Attributes
+{
+ [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
+ public sealed class MessageFrameAttribute : Attribute
+ {
+ public eMessageFrameType FrameType { get; private set; }
+
+ // This is a positional argument
+ public MessageFrameAttribute(eMessageFrameType frameType)
+ {
+ this.FrameType = frameType;
+ }
+
+
+ }
+}
diff --git a/OpenDiablo2.Common/Enums/eMessageFrameType.cs b/OpenDiablo2.Common/Enums/eMessageFrameType.cs
new file mode 100644
index 00000000..ad5556dd
--- /dev/null
+++ b/OpenDiablo2.Common/Enums/eMessageFrameType.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace OpenDiablo2.Common.Enums
+{
+ public enum eMessageFrameType
+ {
+ None = 0x00,
+ SetSeed = 0x01,
+ JoinGame = 0x02,
+
+ MAX = 0xFF, // NOTE:
+ // You absolutely cannot have a higher ID than this without
+ // changing the message header to multi-byte for ALL frame types!!!
+ }
+}
diff --git a/OpenDiablo2.Common/Interfaces/IGameState.cs b/OpenDiablo2.Common/Interfaces/IGameState.cs
index 042d4e70..4a4b5097 100644
--- a/OpenDiablo2.Common/Interfaces/IGameState.cs
+++ b/OpenDiablo2.Common/Interfaces/IGameState.cs
@@ -1,11 +1,12 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Drawing;
using OpenDiablo2.Common.Enums;
using OpenDiablo2.Common.Models;
namespace OpenDiablo2.Common.Interfaces
{
- public interface IGameState
+ public interface IGameState : IDisposable
{
int Act { get; }
int Seed { get; }
diff --git a/OpenDiablo2.Common/Interfaces/ISessionServer.cs b/OpenDiablo2.Common/Interfaces/MessageBus/IMessageFrame.cs
similarity index 53%
rename from OpenDiablo2.Common/Interfaces/ISessionServer.cs
rename to OpenDiablo2.Common/Interfaces/MessageBus/IMessageFrame.cs
index cba01fa6..4ea50c20 100644
--- a/OpenDiablo2.Common/Interfaces/ISessionServer.cs
+++ b/OpenDiablo2.Common/Interfaces/MessageBus/IMessageFrame.cs
@@ -6,7 +6,9 @@ using System.Threading.Tasks;
namespace OpenDiablo2.Common.Interfaces
{
- public interface ISessionServer : IDisposable
+ public interface IMessageFrame
{
+ byte[] Data { get; set; }
+ void Process(object sender, ISessionEventProvider sessionEventProvider);
}
}
diff --git a/OpenDiablo2.Common/Interfaces/MessageBus/ISessionEventProvider.cs b/OpenDiablo2.Common/Interfaces/MessageBus/ISessionEventProvider.cs
new file mode 100644
index 00000000..ea11ee7d
--- /dev/null
+++ b/OpenDiablo2.Common/Interfaces/MessageBus/ISessionEventProvider.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+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 interface ISessionEventProvider
+ {
+
+ OnSetSeedEvent OnSetSeed { get; set; }
+ OnJoinGameEvent OnJoinGame { get; set; }
+ }
+}
diff --git a/OpenDiablo2.Common/Interfaces/ISessionManager.cs b/OpenDiablo2.Common/Interfaces/MessageBus/ISessionManager.cs
similarity index 65%
rename from OpenDiablo2.Common/Interfaces/ISessionManager.cs
rename to OpenDiablo2.Common/Interfaces/MessageBus/ISessionManager.cs
index e4dffb3f..6e832818 100644
--- a/OpenDiablo2.Common/Interfaces/ISessionManager.cs
+++ b/OpenDiablo2.Common/Interfaces/MessageBus/ISessionManager.cs
@@ -6,9 +6,11 @@ using System.Threading.Tasks;
namespace OpenDiablo2.Common.Interfaces
{
- public interface ISessionManager : IDisposable
+
+ public interface ISessionManager : ISessionEventProvider, IDisposable
{
void Initialize();
void Stop();
+ void JoinGame(string playerName);
}
}
diff --git a/OpenDiablo2.Common/Interfaces/MessageBus/ISessionServer.cs b/OpenDiablo2.Common/Interfaces/MessageBus/ISessionServer.cs
new file mode 100644
index 00000000..6025788a
--- /dev/null
+++ b/OpenDiablo2.Common/Interfaces/MessageBus/ISessionServer.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Threading;
+
+namespace OpenDiablo2.Common.Interfaces
+{
+ public interface ISessionServer : IDisposable
+ {
+ AutoResetEvent WaitServerStartEvent { get; set; }
+
+ void Start();
+ void Stop();
+ }
+}
diff --git a/OpenDiablo2.Common/Models/MPQDS1.cs b/OpenDiablo2.Common/Models/MPQDS1.cs
index dae54170..e5dc099d 100644
--- a/OpenDiablo2.Common/Models/MPQDS1.cs
+++ b/OpenDiablo2.Common/Models/MPQDS1.cs
@@ -101,7 +101,6 @@ namespace OpenDiablo2.Common.Models
// TODO: DI magic please
public MPQDS1(Stream stream, LevelPreset level, LevelDetail levelDetail, LevelType levelType, IEngineDataManager engineDataManager, IResourceManager resourceManager)
{
- log.Debug($"Loading {level.Name} (Act {levelDetail.Act})...");
var br = new BinaryReader(stream);
Version = br.ReadInt32();
Width = br.ReadInt32() + 1;
@@ -296,8 +295,6 @@ namespace OpenDiablo2.Common.Models
if (!isMasked || levelType.File[i] == "0")
continue;
- log.Debug($"Loading DT resource {levelType.File[i]}");
-
DT1s[i] = resourceManager.GetMPQDT1("data\\global\\tiles\\" + levelType.File[i].Replace("/", "\\"));
}
diff --git a/OpenDiablo2.Common/Models/Mobs/PlayerState.cs b/OpenDiablo2.Common/Models/Mobs/PlayerState.cs
index 1c6e07e7..bbdbd35b 100644
--- a/OpenDiablo2.Common/Models/Mobs/PlayerState.cs
+++ b/OpenDiablo2.Common/Models/Mobs/PlayerState.cs
@@ -11,6 +11,7 @@ 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;
diff --git a/OpenDiablo2.Common/OpenDiablo2.Common.csproj b/OpenDiablo2.Common/OpenDiablo2.Common.csproj
index d8f8826e..528c3a50 100644
--- a/OpenDiablo2.Common/OpenDiablo2.Common.csproj
+++ b/OpenDiablo2.Common/OpenDiablo2.Common.csproj
@@ -52,8 +52,10 @@
+
+
@@ -67,8 +69,10 @@
-
-
+
+
+
+
@@ -137,9 +141,6 @@
-
-
-
-
+
\ No newline at end of file
diff --git a/OpenDiablo2.Core/AutofacModule.cs b/OpenDiablo2.Core/AutofacModule.cs
index 7bb1497c..52793968 100644
--- a/OpenDiablo2.Core/AutofacModule.cs
+++ b/OpenDiablo2.Core/AutofacModule.cs
@@ -27,7 +27,6 @@ namespace OpenDiablo2.Core
builder.RegisterType().As().SingleInstance();
builder.RegisterType().As().SingleInstance();
builder.RegisterType().As().InstancePerDependency();
- builder.RegisterType().As().InstancePerLifetimeScope();
}
}
}
diff --git a/OpenDiablo2.Core/GameState/GameState.cs b/OpenDiablo2.Core/GameState/GameState.cs
index cc7cdc64..b7b18c98 100644
--- a/OpenDiablo2.Core/GameState/GameState.cs
+++ b/OpenDiablo2.Core/GameState/GameState.cs
@@ -60,14 +60,20 @@ namespace OpenDiablo2.Core.GameState_
sessionManager = getSessionManager(sessionType);
sessionManager.Initialize();
- var random = new Random();
- Seed = random.Next(); // TODO: Seed does not go here ;-(
+ sessionManager.OnSetSeed += OnSetSeedEvent;
- sceneManager.ChangeScene("Game");
mapInfo = new List();
- (new MapGenerator(this)).Generate();
+ sceneManager.ChangeScene("Game");
+
+ sessionManager.JoinGame(characterName); // TODO: we need more attributes...
}
+ private void OnSetSeedEvent(object sender, int seed)
+ {
+ log.Info($"Setting seed to {seed}");
+ this.Seed = seed;
+ (new MapGenerator(this)).Generate();
+ }
public MapInfo LoadSubMap(int levelDefId, Point origin)
{
@@ -391,5 +397,10 @@ namespace OpenDiablo2.Core.GameState_
animationTime += ((float)ms / 1000f);
animationTime -= (float)Math.Truncate(animationTime);
}
+
+ public void Dispose()
+ {
+ sessionManager?.Dispose();
+ }
}
}
diff --git a/OpenDiablo2.Core/OpenDiablo2.Core.csproj b/OpenDiablo2.Core/OpenDiablo2.Core.csproj
index 3bf583db..f8b2fa72 100644
--- a/OpenDiablo2.Core/OpenDiablo2.Core.csproj
+++ b/OpenDiablo2.Core/OpenDiablo2.Core.csproj
@@ -65,7 +65,6 @@
-
diff --git a/OpenDiablo2.Core/SessionServer.cs b/OpenDiablo2.Core/SessionServer.cs
deleted file mode 100644
index 932d8755..00000000
--- a/OpenDiablo2.Core/SessionServer.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using OpenDiablo2.Common.Interfaces;
-
-namespace OpenDiablo2.Core
-{
- public sealed class SessionServer : ISessionServer
- {
-
- public void Dispose()
- {
-
- }
- }
-}
diff --git a/OpenDiablo2.ServiceBus/AutofacModule.cs b/OpenDiablo2.ServiceBus/AutofacModule.cs
index 4123564c..cf214aaf 100644
--- a/OpenDiablo2.ServiceBus/AutofacModule.cs
+++ b/OpenDiablo2.ServiceBus/AutofacModule.cs
@@ -1,5 +1,7 @@
using System;
+using System.Linq;
using Autofac;
+using OpenDiablo2.Common.Attributes;
using OpenDiablo2.Common.Enums;
using OpenDiablo2.Common.Interfaces;
@@ -9,24 +11,38 @@ namespace OpenDiablo2.ServiceBus
{
protected override void Load(ContainerBuilder builder)
{
- builder.RegisterType().AsSelf().InstancePerLifetimeScope();
+ builder.RegisterType().As().InstancePerLifetimeScope();
+ builder.RegisterType().As().InstancePerLifetimeScope();
+
+ var types = ThisAssembly.GetTypes().Where(x => typeof(IMessageFrame).IsAssignableFrom(x) && x.IsClass);
+ foreach (var type in types)
+ {
+ var att = type.GetCustomAttributes(true).First(x => typeof(MessageFrameAttribute).IsAssignableFrom(x.GetType())) as MessageFrameAttribute;
+ builder
+ .RegisterType(type)
+ .Keyed(att.FrameType)
+ .InstancePerDependency();
+ }
+
+ builder.Register>(c =>
+ {
+ var componentContext = c.Resolve();
+ return (frameType) => componentContext.ResolveKeyed(frameType);
+ });
builder.Register>(c =>
{
var componentContext = c.Resolve();
- return (sessionType) =>
- {
- switch (sessionType)
- {
- case eSessionType.Local:
- return componentContext.Resolve();
- case eSessionType.Server:
- case eSessionType.Remote:
- default:
- throw new ApplicationException("Unsupported session type.");
- }
- };
+ return (sessionType) => componentContext.Resolve(new NamedParameter("sessionType", sessionType));
});
+
+ builder.Register>(c =>
+ {
+ var componentContext = c.Resolve();
+ return (sessionType) => componentContext.Resolve(new NamedParameter("sessionType", sessionType));
+ });
+
+
}
}
}
diff --git a/OpenDiablo2.ServiceBus/LocalSessionManager.cs b/OpenDiablo2.ServiceBus/LocalSessionManager.cs
deleted file mode 100644
index f0720116..00000000
--- a/OpenDiablo2.ServiceBus/LocalSessionManager.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using OpenDiablo2.Common.Interfaces;
-
-namespace OpenDiablo2.ServiceBus
-{
- public sealed class LocalSessionManager : ISessionManager
- {
- private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
-
- private readonly ISessionServer sessionServer;
- volatile bool running = false;
-
- public LocalSessionManager(ISessionServer sessionServer)
- {
- this.sessionServer = sessionServer;
- }
-
- public void Initialize()
- {
- log.Info("Initializing a local multiplayer session.");
- running = true;
- Task.Run(() => Listen());
- }
-
- private void Listen()
- {
- log.Info("Local session manager is starting.");
- while (running)
- {
-
- }
-
- log.Info("Local session manager has stopped.");
- }
-
- public void Dispose()
- {
-
- }
-
- public void Stop() => running = false;
- }
-}
diff --git a/OpenDiablo2.ServiceBus/Message Frames/MFJoinGame.cs b/OpenDiablo2.ServiceBus/Message Frames/MFJoinGame.cs
new file mode 100644
index 00000000..6f72d557
--- /dev/null
+++ b/OpenDiablo2.ServiceBus/Message Frames/MFJoinGame.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Linq;
+using System.Text;
+using OpenDiablo2.Common.Attributes;
+using OpenDiablo2.Common.Enums;
+using OpenDiablo2.Common.Interfaces;
+
+namespace OpenDiablo2.ServiceBus.Message_Frames
+{
+ [MessageFrame(eMessageFrameType.JoinGame)]
+ public sealed class MFJoinGame : IMessageFrame
+ {
+ public Guid PlayerId { get; set; }
+ public string PlayerName { get; set; }
+ public byte[] Data
+ {
+ get
+ {
+ return PlayerId.ToByteArray()
+ .Concat(BitConverter.GetBytes((UInt16)PlayerName.Length))
+ .Concat(Encoding.UTF8.GetBytes(PlayerName))
+ .ToArray();
+ }
+
+ set
+ {
+
+ PlayerId = new Guid(value.Take(16).ToArray());
+ var playerNameLen = BitConverter.ToUInt16(value, 16);
+ PlayerName = Encoding.UTF8.GetString(value, 18, value.Length - 18);
+
+ if (PlayerName.Length != playerNameLen)
+ throw new ApplicationException("Invalid player length!");
+ }
+ }
+
+ public MFJoinGame() { }
+ public MFJoinGame(string playerName)
+ {
+ PlayerId = Guid.NewGuid();
+ PlayerName = playerName;
+ }
+
+ public void Process(object sender, ISessionEventProvider sessionEventProvider)
+ {
+ sessionEventProvider.OnJoinGame(sender, PlayerId, PlayerName);
+ }
+ }
+}
diff --git a/OpenDiablo2.ServiceBus/Message Frames/MFSetSeed.cs b/OpenDiablo2.ServiceBus/Message Frames/MFSetSeed.cs
new file mode 100644
index 00000000..eb7901ac
--- /dev/null
+++ b/OpenDiablo2.ServiceBus/Message Frames/MFSetSeed.cs
@@ -0,0 +1,35 @@
+using System;
+using OpenDiablo2.Common.Attributes;
+using OpenDiablo2.Common.Enums;
+using OpenDiablo2.Common.Interfaces;
+
+namespace OpenDiablo2.ServiceBus.Message_Frames
+{
+ [MessageFrame(eMessageFrameType.SetSeed)]
+ public sealed class MFSetSeed : IMessageFrame
+ {
+
+ public byte[] Data
+ {
+ get => BitConverter.GetBytes(Seed);
+ set => BitConverter.ToInt32(value, 0);
+ }
+
+ public Int32 Seed { get; private set; }
+
+ public MFSetSeed()
+ {
+ Seed = (new Random()).Next();
+ }
+
+ public MFSetSeed(int seed)
+ {
+ Seed = seed;
+ }
+
+ public void Process(object sender, ISessionEventProvider sessionEventProvider)
+ {
+ sessionEventProvider.OnSetSeed?.Invoke(sender, Seed);
+ }
+ }
+}
diff --git a/OpenDiablo2.ServiceBus/OpenDiablo2.ServiceBus.csproj b/OpenDiablo2.ServiceBus/OpenDiablo2.ServiceBus.csproj
index b22a6bbc..40c0077f 100644
--- a/OpenDiablo2.ServiceBus/OpenDiablo2.ServiceBus.csproj
+++ b/OpenDiablo2.ServiceBus/OpenDiablo2.ServiceBus.csproj
@@ -56,8 +56,11 @@
-
+
+
+
+
diff --git a/OpenDiablo2.ServiceBus/SessionManager.cs b/OpenDiablo2.ServiceBus/SessionManager.cs
new file mode 100644
index 00000000..5c417149
--- /dev/null
+++ b/OpenDiablo2.ServiceBus/SessionManager.cs
@@ -0,0 +1,129 @@
+using System;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using NetMQ;
+using NetMQ.Sockets;
+using OpenDiablo2.Common.Attributes;
+using OpenDiablo2.Common.Enums;
+using OpenDiablo2.Common.Interfaces;
+using OpenDiablo2.ServiceBus.Message_Frames;
+
+namespace OpenDiablo2.ServiceBus
+{
+ public sealed class SessionManager : ISessionManager
+ {
+ private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+
+ private readonly Func getSessionServer;
+ private readonly eSessionType sessionType;
+ private readonly Func getMessageFrame;
+
+ private RequestSocket requestSocket;
+ private AutoResetEvent resetEvent = new AutoResetEvent(false);
+ private ISessionServer sessionServer;
+ private Guid playerId;
+ private bool running = false;
+
+ public OnSetSeedEvent OnSetSeed { get; set; }
+ public OnJoinGameEvent OnJoinGame { get; set; }
+
+ public SessionManager(eSessionType sessionType, Func getSessionServer, Func getMessageFrame)
+ {
+ this.getSessionServer = getSessionServer;
+ this.sessionType = sessionType;
+ this.getMessageFrame = getMessageFrame;
+ }
+
+ public void Initialize()
+ {
+ if (sessionType == eSessionType.Local || sessionType == eSessionType.Server)
+ {
+ sessionServer = getSessionServer(sessionType);
+ sessionServer.Start();
+ sessionServer.WaitServerStartEvent.WaitOne(); // Wait until the server starts...
+ }
+ else sessionServer = null;
+
+ log.Info("Initializing a local multiplayer session.");
+ Task.Run(() => Listen());
+ }
+
+ private void Listen()
+ {
+ log.Info("Session manager is starting.");
+ requestSocket = new RequestSocket();
+
+ switch (sessionType)
+ {
+ case eSessionType.Local:
+ requestSocket.Connect("inproc://opendiablo2-session");
+ break;
+ case eSessionType.Server:
+ case eSessionType.Remote:
+ 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;
+ requestSocket.Dispose();
+ log.Info("Session manager has stopped.");
+
+ }
+ public void Stop()
+ {
+ if (!running)
+ return;
+
+ resetEvent.Set();
+
+ if (sessionType == eSessionType.Local || sessionType == eSessionType.Server)
+ sessionServer?.Stop();
+
+ }
+
+ public void Dispose()
+ {
+ Stop();
+ }
+
+ public void Send(IMessageFrame messageFrame)
+ {
+ var attr = messageFrame.GetType().GetCustomAttributes(true).First(x => typeof(MessageFrameAttribute).IsAssignableFrom(x.GetType())) as MessageFrameAttribute;
+ requestSocket.SendFrame(new byte[] { (byte)attr.FrameType }.Concat(messageFrame.Data).ToArray());
+ }
+
+ private void ProcessMessageFrame() where T : IMessageFrame, new()
+ {
+ if (!running)
+ throw new ApplicationException("You have made a terrible mistake. Cannot get a message frame if you are not connected.");
+
+ var bytes = requestSocket.ReceiveFrameBytes();
+ var frameType = (eMessageFrameType)bytes[0];
+ var frameData = bytes.Skip(1).ToArray(); // TODO: Can we maybe use pointers? This seems wasteful
+ var messageFrame = getMessageFrame(frameType);
+ if (messageFrame.GetType() != typeof(T))
+ throw new ApplicationException("Recieved unexpected message frame!");
+ messageFrame.Data = frameData;
+ messageFrame.Process(requestSocket, this);
+ }
+
+ public void JoinGame(string playerName)
+ {
+ var mf = new MFJoinGame(playerName);
+ playerId = mf.PlayerId;
+ Send(mf);
+ ProcessMessageFrame();
+ }
+ }
+}
diff --git a/OpenDiablo2.ServiceBus/SessionServer.cs b/OpenDiablo2.ServiceBus/SessionServer.cs
new file mode 100644
index 00000000..c57e2109
--- /dev/null
+++ b/OpenDiablo2.ServiceBus/SessionServer.cs
@@ -0,0 +1,104 @@
+using System;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using NetMQ;
+using NetMQ.Sockets;
+using OpenDiablo2.Common.Attributes;
+using OpenDiablo2.Common.Enums;
+using OpenDiablo2.Common.Interfaces;
+using OpenDiablo2.ServiceBus.Message_Frames;
+
+namespace OpenDiablo2.ServiceBus
+{
+ public sealed class SessionServer : ISessionServer, ISessionEventProvider
+ {
+ private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+
+ private readonly eSessionType sessionType;
+ 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 SessionServer(eSessionType sessionType, Func getMessageFrame)
+ {
+ this.sessionType = sessionType;
+ this.getMessageFrame = getMessageFrame;
+ }
+
+ public void Start()
+ {
+ gameSeed = (new Random()).Next();
+ Task.Run(() => Serve());
+ }
+
+ private void Serve()
+ {
+ log.Info("Session server is starting.");
+ responseSocket = new ResponseSocket();
+
+ switch (sessionType)
+ {
+ case eSessionType.Local:
+ responseSocket.Bind("inproc://opendiablo2-session");
+ break;
+ case eSessionType.Server:
+ case eSessionType.Remote:
+ default:
+ throw new ApplicationException("This session type is currently unsupported.");
+ }
+
+ OnJoinGame += OnJoinGameHandler;
+
+ var proactor = new NetMQProactor(responseSocket, (socket, message) =>
+ {
+ 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;
+ WaitServerStartEvent.Set();
+ resetEvent.WaitOne();
+ proactor.Dispose();
+ running = false;
+ responseSocket.Dispose();
+ log.Info("Session server has stopped.");
+ }
+
+
+ public void Stop()
+ {
+ if (!running)
+ return;
+
+ resetEvent.Set();
+ }
+
+ public void Dispose()
+ {
+ Stop();
+ }
+
+ private void Send(NetMQSocket target, IMessageFrame messageFrame)
+ {
+ 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());
+ }
+
+ private void OnJoinGameHandler(object sender, Guid playerId, string playerName)
+ {
+ // TODO: Try to make this less stupid
+ Send(sender as NetMQSocket, new MFSetSeed(gameSeed));
+ }
+ }
+}
diff --git a/OpenDiablo2/OpenDiablo2.csproj b/OpenDiablo2/OpenDiablo2.csproj
index e6ada74e..09886d24 100644
--- a/OpenDiablo2/OpenDiablo2.csproj
+++ b/OpenDiablo2/OpenDiablo2.csproj
@@ -5,7 +5,7 @@
Debug
AnyCPU
{2B0CF1AC-06DD-4322-AE8B-FF8A8C70A3CD}
- WinExe
+ Exe
OpenDiablo2
OpenDiablo2
v4.6.1
diff --git a/OpenDiablo2/Program.cs b/OpenDiablo2/Program.cs
index 4d9a559c..417f9908 100644
--- a/OpenDiablo2/Program.cs
+++ b/OpenDiablo2/Program.cs
@@ -34,9 +34,20 @@ namespace OpenDiablo2
try
{
#endif
- BuildContainer()
- .Resolve()
- .Run();
+ var container = BuildContainer();
+ try
+ {
+ using (var gameEngine = container.Resolve())
+ {
+ gameEngine.Run();
+ }
+ }
+ finally
+ {
+ container.Dispose();
+ }
+
+
#if !DEBUG
}
catch (Exception ex)
diff --git a/README.md b/README.md
index a9727f7a..86a5ba29 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@ You need to have MonoDevelop installed, as well as any depenencies for that. You
## Command Line Parameters
| Long Name | Description |
| ------------ | ------------------------------------------------------------ |
-| --datapath | (-d) Defines the path where the data files can be found |
+| --datapath | (-p) Defines the path where the data files can be found |
| --hwmouse | Use the hardware mouse instead of software |
| --mousescale | When hardware mouse is enabled, this defines the pixel scale of the mouse. No effect for software mode |
| --fullscreen | (-f) When set, the game launches in full screen mode at 800x600. |