1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-16 12:35:22 +00:00

Started work on session manager. Fixed mouse rendering logic.

This commit is contained in:
Tim Sarbin 2018-11-29 23:26:51 -05:00
parent 6907d8e507
commit 0a3eb44248
17 changed files with 243 additions and 78 deletions

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenDiablo2.Common.Enums
{
/// <summary>Defines the type of gameplay session we are running.</summary>
public enum eSessionType
{
/// <summary>This session is an offline single player game.</summary>
Local,
/// <summary>This session is a multiplayer game, and this instance is the server.</summary>
Server,
/// <summary>This session is a multiplayer game, and this instance is a client connected to an external server.</summary>
Remote
}
}

View File

@ -6,6 +6,8 @@ namespace OpenDiablo2.Common.Interfaces
{
public interface IRenderWindow : IDisposable
{
IMouseCursor MouseCursor { get; set; }
bool IsRunning { get; }
void Update();
void Clear();
@ -24,7 +26,6 @@ namespace OpenDiablo2.Common.Interfaces
void Draw(ISprite sprite, int frame);
void Draw(ISprite sprite, int xSegments, int ySegments, int offset);
IMouseCursor LoadCursor(ISprite sprite, int frame, Point hotspot);
void SetCursor(IMouseCursor mouseCursor);
void Draw(ILabel label);
MapCellInfo CacheMapCell(MPQDT1Tile mapCell);
void DrawMapCell(MapCellInfo mapCellInfo, int xPixel, int yPixel);

View File

@ -18,7 +18,7 @@ namespace OpenDiablo2.Common.Interfaces
bool ToggleShowCharacterPanel();
bool ShowCharacterPanel { get; set; }
void Initialize(string text, eHero value);
void Initialize(string text, eHero value, eSessionType sessionType);
void Update(long ms);
IEnumerable<MapCellInfo> GetMapCellInfo(int cellX, int cellY, eRenderCellType renderCellType);
void UpdateMapCellInfo(int cellX, int cellY, eRenderCellType renderCellType, IEnumerable<MapCellInfo> mapCellInfo);

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenDiablo2.Common.Interfaces
{
public interface ISessionManager : IDisposable
{
void Initialize();
void Stop();
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenDiablo2.Common.Interfaces
{
public interface ISessionServer : IDisposable
{
}
}

View File

@ -61,11 +61,14 @@
<Compile Include="Enums\eLevelSubType.cs" />
<Compile Include="Enums\eMPQFormatVersion.cs" />
<Compile Include="Enums\eRenderCellType.cs" />
<Compile Include="Enums\eSessionType.cs" />
<Compile Include="Enums\eTextAlign.cs" />
<Compile Include="Enums\eWildBorder.cs" />
<Compile Include="Enums\Mobs\eDamageTypes.cs" />
<Compile Include="Enums\Mobs\eMobFlags.cs" />
<Compile Include="Enums\Mobs\eStatModifierType.cs" />
<Compile Include="Interfaces\ISessionManager.cs" />
<Compile Include="Interfaces\ISessionServer.cs" />
<Compile Include="Interfaces\UI\IButton.cs" />
<Compile Include="Interfaces\UI\IPanelFrame.cs" />
<Compile Include="Interfaces\UI\IInventoryPanel.cs" />
@ -134,6 +137,9 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<Folder Include="Message Frames\Requests\" />
<Folder Include="Message Frames\Responses\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -27,6 +27,7 @@ namespace OpenDiablo2.Core
builder.RegisterType<ResourceManager>().As<IResourceManager>().SingleInstance();
builder.RegisterType<TextDictionary>().As<ITextDictionary>().SingleInstance();
builder.RegisterType<TextBox>().As<ITextBox>().InstancePerDependency();
builder.RegisterType<SessionServer>().As<ISessionServer>().InstancePerLifetimeScope();
}
}
}

View File

@ -17,7 +17,6 @@ namespace OpenDiablo2.Core
private readonly GlobalConfiguration globalConfig;
private readonly IMPQProvider mpqProvider;
private readonly Func<IRenderWindow> getRenderWindow;
private readonly Func<IMouseInfoProvider> getMouseInfoProvider;
private readonly Func<string, IScene> getScene;
private readonly Func<IResourceManager> getResourceManager;
private readonly Func<IGameState> getGameState;
@ -36,7 +35,6 @@ namespace OpenDiablo2.Core
GlobalConfiguration globalConfig,
IMPQProvider mpqProvider,
Func<IRenderWindow> getRenderWindow,
Func<IMouseInfoProvider> getMouseInfoProvider,
Func<string, IScene> getScene,
Func<IResourceManager> getResourceManager,
Func<IGameState> getGameState
@ -45,7 +43,6 @@ namespace OpenDiablo2.Core
this.globalConfig = globalConfig;
this.mpqProvider = mpqProvider;
this.getRenderWindow = getRenderWindow;
this.getMouseInfoProvider = getMouseInfoProvider;
this.getScene = getScene;
this.getResourceManager = getResourceManager;
this.getGameState = getGameState;
@ -81,19 +78,14 @@ namespace OpenDiablo2.Core
public void Run()
{
var renderWindow = getRenderWindow();
var mouseInfoProvider = getMouseInfoProvider();
LoadPalettes();
LoadSoundData();
mouseSprite = renderWindow.LoadSprite(ResourcePaths.CursorDefault, Palettes.Units);
IMouseCursor cursor;
if (globalConfig.MouseMode == eMouseMode.Hardware)
{
cursor = renderWindow.LoadCursor(mouseSprite, 0, new Point(0, 0));
renderWindow.SetCursor(cursor);
}
var cursor = renderWindow.LoadCursor(mouseSprite, 0, new Point(0, 3));
renderWindow.MouseCursor = cursor;
currentScene = getScene("Main Menu");
var lastTicks = renderWindow.GetTicks();
while (getRenderWindow().IsRunning)
@ -132,9 +124,6 @@ namespace OpenDiablo2.Core
renderWindow.Clear();
currentScene.Render();
if (globalConfig.MouseMode == eMouseMode.Software)
renderWindow.Draw(mouseSprite, new Point(mouseInfoProvider.MouseX, mouseInfoProvider.MouseY + 3));
renderWindow.Sync();
}
}

View File

@ -19,16 +19,12 @@ namespace OpenDiablo2.Core.GameState_
private readonly IEngineDataManager engineDataManager;
private readonly IRenderWindow renderWindow;
private readonly Func<IMapEngine> getMapEngine;
private readonly Func<eSessionType, ISessionManager> getSessionManager;
private float animationTime = 0f;
private List<MapInfo> mapInfo;
private List<MapCellInfo> mapDataLookup = new List<MapCellInfo>();
// TODO: Break this out further so we can support multiple maps---------------------------------------------
//private MPQDS1 _mapDataTemp, _mapDataTemp2;
//private Dictionary<Guid, List<MapCellInfo>> mapDataLookup = new Dictionary<Guid, List<MapCellInfo>>();
//private Dictionary<Guid, List<MapCellInfo>> mapDataLookup2 = new Dictionary<Guid, List<MapCellInfo>>();
// ---------------------------------------------------------------------------------------------------------
private ISessionManager sessionManager;
public int Act { get; private set; }
public string MapName { get; private set; }
@ -45,57 +41,31 @@ namespace OpenDiablo2.Core.GameState_
IPaletteProvider paletteProvider,
IEngineDataManager engineDataManager,
IRenderWindow renderWindow,
Func<IMapEngine> getMapEngine
Func<IMapEngine> getMapEngine,
Func<eSessionType, ISessionManager> getSessionManager
)
{
this.sceneManager = sceneManager;
this.resourceManager = resourceManager;
this.paletteProvider = paletteProvider;
this.getMapEngine = getMapEngine;
this.getSessionManager = getSessionManager;
this.engineDataManager = engineDataManager;
this.renderWindow = renderWindow;
}
public void Initialize(string characterName, eHero hero)
public void Initialize(string characterName, eHero hero, eSessionType sessionType)
{
sessionManager = getSessionManager(sessionType);
sessionManager.Initialize();
var random = new Random();
Seed = random.Next();
Seed = random.Next(); // TODO: Seed does not go here ;-(
sceneManager.ChangeScene("Game");
// Initialize our first village
// TODO: Loading may make this 'fun'..
mapInfo = new List<MapInfo>();
(new MapGenerator(this)).Generate();
// TODO: We need a map generator here...
/*
{
// TODO: TEMP CODE AHEAD!
var transId = nw ? 3 : 2;
var level = engineDataManager.LevelPresets.First(x => x.Def == (int)transId);
var levelDetails = engineDataManager.LevelDetails.First(x => x.Id == level.LevelId);
var levelType = engineDataManager.LevelTypes.First(x => x.Id == levelDetails.LevelType);
// Some maps have variations, so lets pick a random one
var mapNames = new List<string>();
if (level.File1 != "0") mapNames.Add(level.File1);
if (level.File2 != "0") mapNames.Add(level.File2);
if (level.File3 != "0") mapNames.Add(level.File3);
if (level.File4 != "0") mapNames.Add(level.File4);
if (level.File5 != "0") mapNames.Add(level.File5);
if (level.File6 != "0") mapNames.Add(level.File6);
var random = new Random(Seed);
var mapName = "data\\global\\tiles\\" + mapNames[random.Next(mapNames.Count())].Replace("/", "\\");
_mapDataTemp2 = resourceManager.GetMPQDS1(mapName, level, levelDetails, levelType);
}
*/
}

View File

@ -65,6 +65,7 @@
<Compile Include="MPQProvider.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ResourceManager.cs" />
<Compile Include="SessionServer.cs" />
<Compile Include="TextDictionary.cs" />
<Compile Include="UI\Button.cs" />
<Compile Include="UI\PanelFrame.cs" />

View File

@ -0,0 +1,18 @@
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()
{
}
}
}

View File

@ -1,10 +1,15 @@
using System;
using System.Drawing;
using OpenDiablo2.Common.Interfaces;
using SDL2;
namespace OpenDiablo2.SDL2_
{
public sealed class SDL2MouseCursor : IMouseCursor
{
public IntPtr Surface { get; set; }
public IntPtr HWSurface { get; set; }
public IntPtr SWTexture { get; set; }
public Size ImageSize { get; set; }
public Point Hotspot { get; set; }
}
}

View File

@ -25,6 +25,19 @@ namespace OpenDiablo2.SDL2_
public OnKeyPressed KeyPressCallback { get; set; }
private IMouseCursor mouseCursor = null;
public IMouseCursor MouseCursor
{
get => mouseCursor;
set
{
if (mouseCursor == value)
return;
SetCursor(value);
}
}
private readonly IMPQProvider mpqProvider;
private readonly IPaletteProvider paletteProvider;
private readonly IResourceManager resourceManager;
@ -96,8 +109,33 @@ namespace OpenDiablo2.SDL2_
}
public void Sync()
public unsafe void Sync()
{
if (globalConfig.MouseMode == eMouseMode.Software)
{
var cursor = mouseCursor as SDL2MouseCursor;
var texture = cursor.SWTexture;
var srcRect = new SDL.SDL_Rect
{
x = 0,
y = 0,
w = cursor.ImageSize.Width,
h = cursor.ImageSize.Height
};
var destRect = new SDL.SDL_Rect
{
x = MouseX - cursor.Hotspot.X,
y = MouseY - cursor.Hotspot.Y,
w = cursor.ImageSize.Width,
h = cursor.ImageSize.Height
};
SDL.SDL_RenderCopy(renderer, texture, ref srcRect, ref destRect);
}
SDL.SDL_RenderPresent(renderer);
}
@ -145,7 +183,8 @@ namespace OpenDiablo2.SDL2_
fullscreen = !fullscreen;
SDL.SDL_SetWindowFullscreen(window, (uint)(fullscreen ? SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN : 0));
}
else*/ if (evt.key.keysym.sym == SDL.SDL_Keycode.SDLK_BACKSPACE && KeyPressCallback != null)
else*/
if (evt.key.keysym.sym == SDL.SDL_Keycode.SDLK_BACKSPACE && KeyPressCallback != null)
KeyPressCallback('\b');
}
else if (evt.type == SDL.SDL_EventType.SDL_TEXTINPUT)
@ -287,8 +326,6 @@ namespace OpenDiablo2.SDL2_
public unsafe MapCellInfo CacheMapCell(MPQDT1Tile mapCell)
{
log.Debug($"Caching map cell {mapCell.Id}");
var minX = mapCell.Blocks.Min(x => x.PositionX);
var minY = mapCell.Blocks.Min(x => x.PositionY);
var maxX = mapCell.Blocks.Max(x => x.PositionX + 32);
@ -379,34 +416,55 @@ namespace OpenDiablo2.SDL2_
public unsafe IMouseCursor LoadCursor(ISprite sprite, int frame, Point hotspot)
{
if (globalConfig.MouseMode != eMouseMode.Hardware)
throw new ApplicationException("Tried to set a hardware cursor, but we are using software cursors!");
if (globalConfig.MouseMode == eMouseMode.Software)
{
sprite.Frame = frame;
var texId = SDL.SDL_CreateTexture(renderer, SDL.SDL_PIXELFORMAT_ARGB8888,
(int)SDL.SDL_TextureAccess.SDL_TEXTUREACCESS_TARGET, sprite.LocalFrameSize.Width, sprite.LocalFrameSize.Height);
SDL.SDL_SetTextureBlendMode(texId, SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
SDL.SDL_SetRenderTarget(renderer, texId);
SDL.SDL_RenderCopy(renderer, (sprite as SDL2Sprite).texture, IntPtr.Zero, IntPtr.Zero);
SDL.SDL_SetRenderTarget(renderer, IntPtr.Zero);
return new SDL2MouseCursor
{
Hotspot = hotspot,
ImageSize = sprite.LocalFrameSize,
SWTexture = texId
};
}
var multiple = globalConfig.HardwareMouseScale;
var spr = sprite as SDL2Sprite;
var surface = SDL.SDL_CreateRGBSurface(0, spr.FrameSize.Width * multiple, spr.FrameSize.Height * multiple, 32, 0xFF0000, 0xFF00, 0xFF, 0xFF000000);
var surface = SDL.SDL_CreateRGBSurface(0, spr.LocalFrameSize.Width * multiple, spr.LocalFrameSize.Height * multiple, 32, 0xFF0000, 0xFF00, 0xFF, 0xFF000000);
var yOffset = (spr.FrameSize.Height - spr.LocalFrameSize.Height);
var XOffset = (spr.FrameSize.Width - spr.LocalFrameSize.Width);
var pixels = (UInt32*)((SDL.SDL_Surface*)surface)->pixels;
for (var y = 0; y < (spr.FrameSize.Height * multiple) - 1; y++)
for (var x = 0; x < (spr.FrameSize.Width * multiple) - 1; x++)
for (var y = 0; y < (spr.LocalFrameSize.Height * multiple) - 1; y++)
for (var x = 0; x < (spr.LocalFrameSize.Width * multiple) - 1; x++)
{
pixels[x + (y * spr.FrameSize.Width * multiple)] = spr.source.Frames[frame].GetColor(x / multiple, y / multiple, sprite.CurrentPalette);
pixels[x + XOffset + ((y + yOffset) * spr.LocalFrameSize.Width * multiple)] = spr.source.Frames[frame].GetColor(x / multiple, y / multiple, sprite.CurrentPalette);
}
var cursor = SDL.SDL_CreateColorCursor(surface, hotspot.X, hotspot.Y);
var cursor = SDL.SDL_CreateColorCursor(surface, hotspot.X * multiple, hotspot.Y * multiple);
if (cursor == IntPtr.Zero)
throw new ApplicationException($"Unable to set the cursor cursor: {SDL.SDL_GetError()}"); // TODO: Is this supported everywhere? May need to still support software cursors.
return new SDL2MouseCursor { Surface = cursor };
return new SDL2MouseCursor { HWSurface = cursor };
}
public void SetCursor(IMouseCursor mouseCursor)
private void SetCursor(IMouseCursor mouseCursor)
{
if (globalConfig.MouseMode != eMouseMode.Hardware)
throw new ApplicationException("Tried to set a hardware cursor, but we are using software cursors!");
this.mouseCursor = mouseCursor;
SDL.SDL_SetCursor((mouseCursor as SDL2MouseCursor).Surface);
if (globalConfig.MouseMode != eMouseMode.Hardware)
return;
SDL.SDL_SetCursor((mouseCursor as SDL2MouseCursor).HWSurface);
}
public uint GetTicks() => SDL.SDL_GetTicks();
}
}

View File

@ -228,7 +228,8 @@ namespace OpenDiablo2.Scenes
private void OnOkclicked()
{
gameState.Initialize(characterNameTextBox.Text, selectedHero.Value);
// TODO: Support other session types
gameState.Initialize(characterNameTextBox.Text, selectedHero.Value, eSessionType.Local);
}
private void OnExitClicked()

View File

@ -1,4 +1,7 @@
using Autofac;
using System;
using Autofac;
using OpenDiablo2.Common.Enums;
using OpenDiablo2.Common.Interfaces;
namespace OpenDiablo2.ServiceBus
{
@ -6,7 +9,24 @@ namespace OpenDiablo2.ServiceBus
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<LocalSessionManager>().AsSelf().InstancePerLifetimeScope();
builder.Register<Func<eSessionType, ISessionManager>>(c =>
{
var componentContext = c.Resolve<IComponentContext>();
return (sessionType) =>
{
switch (sessionType)
{
case eSessionType.Local:
return componentContext.Resolve<LocalSessionManager>();
case eSessionType.Server:
case eSessionType.Remote:
default:
throw new ApplicationException("Unsupported session type.");
}
};
});
}
}
}

View File

@ -0,0 +1,47 @@
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;
}
}

View File

@ -56,6 +56,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="AutofacModule.cs" />
<Compile Include="LocalSessionManager.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>