diff --git a/EOLib.Graphics/NativeGraphicsManager.cs b/EOLib.Graphics/NativeGraphicsManager.cs index c5881fb8d..d9e9b1939 100644 --- a/EOLib.Graphics/NativeGraphicsManager.cs +++ b/EOLib.Graphics/NativeGraphicsManager.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; +using System.IO; using AutomaticTypeMapper; using Microsoft.Xna.Framework.Graphics; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Drawing.Processing; using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; namespace EOLib.Graphics @@ -45,12 +47,21 @@ public Texture2D TextureFromResource(GFXTypes file, int resourceVal, bool transp } } - using (var mem = new System.IO.MemoryStream()) + using (var i = BitmapFromResource(file, resourceVal, transparent)) { - using (var i = BitmapFromResource(file, resourceVal, transparent)) - ((Image)i).Save(mem, new PngEncoder()); - - ret = Texture2D.FromStream(_graphicsDeviceProvider.GraphicsDevice, mem); + if (!i.DangerousTryGetSinglePixelMemory(out var mem)) + { + using (var ms = new MemoryStream()) + { + i.SaveAsPng(ms); + ret = Texture2D.FromStream(_graphicsDeviceProvider.GraphicsDevice, ms); + } + } + else + { + ret = new Texture2D(_graphicsDeviceProvider.GraphicsDevice, i.Width, i.Height); + ret.SetData(mem.ToArray()); + } } lock (__cachelock__) @@ -61,9 +72,9 @@ public Texture2D TextureFromResource(GFXTypes file, int resourceVal, bool transp return ret; } - private IImage BitmapFromResource(GFXTypes file, int resourceVal, bool transparent) + private Image BitmapFromResource(GFXTypes file, int resourceVal, bool transparent) { - var ret = (Image)_gfxLoader.LoadGFX(file, resourceVal); + var ret = (Image)_gfxLoader.LoadGFX(file, resourceVal); if (transparent) { diff --git a/EOLib/Domain/Character/Character.cs b/EOLib/Domain/Character/Character.cs index 2ac580cc4..b954d907a 100644 --- a/EOLib/Domain/Character/Character.cs +++ b/EOLib/Domain/Character/Character.cs @@ -28,6 +28,12 @@ public class Character : ICharacter public bool NoWall { get; private set; } + public Character() + { + RenderProperties = new CharacterRenderProperties(); + Stats = new CharacterStats(); + } + public ICharacter WithID(int id) { var character = MakeCopy(this); diff --git a/EndlessClient/Content/ContentProvider.cs b/EndlessClient/Content/ContentProvider.cs new file mode 100644 index 000000000..7994ee752 --- /dev/null +++ b/EndlessClient/Content/ContentProvider.cs @@ -0,0 +1,94 @@ +using AutomaticTypeMapper; +using EOLib; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using System.Collections.Generic; + +namespace EndlessClient.Content +{ + public interface IContentProvider + { + IReadOnlyDictionary Textures { get; } + + IReadOnlyDictionary Fonts { get; } + + void SetContentManager(ContentManager content); + + void Load(); + } + + [AutoMappedType(IsSingleton = true)] + public class ContentProvider : IContentProvider + { + private readonly Dictionary _textures; + private readonly Dictionary _fonts; + + private ContentManager _content; + + public const string Cursor = "cursor"; + + public const string TBBack = "tbBack"; + public const string TBLeft = "tbLeft"; + public const string TBRight = "tbRight"; + + public const string ChatTL = @"ChatBubble\TL"; + public const string ChatTM = @"ChatBubble\TM"; + public const string ChatTR = @"ChatBubble\TR"; + public const string ChatML = @"ChatBubble\ML"; + public const string ChatMM = @"ChatBubble\MM"; + public const string ChatMR = @"ChatBubble\MR"; + public const string ChatRL = @"ChatBubble\RL"; + public const string ChatRM = @"ChatBubble\RM"; + public const string ChatRR = @"ChatBubble\RR"; + public const string ChatNUB = @"ChatBubble\NUB"; + + public IReadOnlyDictionary Textures => _textures; + + public IReadOnlyDictionary Fonts => _fonts; + + public ContentProvider() + { + _textures = new Dictionary(); + _fonts = new Dictionary(); + } + + public void SetContentManager(ContentManager content) + { + _content = content; + } + + public void Load() + { + RefreshTextures(); + RefreshFonts(); + } + + private void RefreshTextures() + { + if (_content == null) + return; + + _textures[Cursor] = _content.Load(Cursor); + + _textures[TBBack] = _content.Load(TBBack); + _textures[TBLeft] = _content.Load(TBLeft); + _textures[TBRight] = _content.Load(TBRight); + + _textures[ChatTL] = _content.Load(ChatTL); + _textures[ChatTM] = _content.Load(ChatTM); + _textures[ChatTR] = _content.Load(ChatTR); + _textures[ChatML] = _content.Load(ChatML); + _textures[ChatMM] = _content.Load(ChatMM); + _textures[ChatMR] = _content.Load(ChatMR); + _textures[ChatRL] = _content.Load(ChatRL); + _textures[ChatRM] = _content.Load(ChatRM); + _textures[ChatRR] = _content.Load(ChatRR); + _textures[ChatNUB] = _content.Load(ChatNUB); + } + + private void RefreshFonts() + { + _fonts[Constants.FontSize08] = _content.Load(Constants.FontSize08); + } + } +} diff --git a/EndlessClient/Content/IContentManagerRepository.cs b/EndlessClient/Content/IContentManagerRepository.cs deleted file mode 100644 index b2ea957eb..000000000 --- a/EndlessClient/Content/IContentManagerRepository.cs +++ /dev/null @@ -1,22 +0,0 @@ -using AutomaticTypeMapper; -using Microsoft.Xna.Framework.Content; - -namespace EndlessClient.Content -{ - public interface IContentManagerRepository - { - ContentManager Content { get; set; } - } - - public interface IContentManagerProvider - { - ContentManager Content { get; } - } - - [MappedType(BaseType = typeof(IContentManagerProvider), IsSingleton = true)] - [MappedType(BaseType = typeof(IContentManagerRepository), IsSingleton = true)] - public class ContentManagerRepository : IContentManagerRepository, IContentManagerProvider - { - public ContentManager Content { get; set; } - } -} diff --git a/EndlessClient/ControlSets/BackButtonControlSet.cs b/EndlessClient/ControlSets/BackButtonControlSet.cs index aab1a1a96..01dbdb4e3 100644 --- a/EndlessClient/ControlSets/BackButtonControlSet.cs +++ b/EndlessClient/ControlSets/BackButtonControlSet.cs @@ -1,8 +1,8 @@ using System; +using EndlessClient.Content; using EndlessClient.Controllers; using EOLib.Graphics; using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using XNAControls; @@ -21,9 +21,9 @@ protected BackButtonControlSet(IMainButtonController mainButtonController) _mainButtonController = mainButtonController; } - public override void InitializeResources(INativeGraphicsManager gfxManager, ContentManager xnaContentManager) + public override void InitializeResources(INativeGraphicsManager gfxManager, IContentProvider contentProvider) { - base.InitializeResources(gfxManager, xnaContentManager); + base.InitializeResources(gfxManager, contentProvider); _backButtonTexture = gfxManager.TextureFromResource(GFXTypes.PreLoginUI, 24, true); } diff --git a/EndlessClient/ControlSets/BaseControlSet.cs b/EndlessClient/ControlSets/BaseControlSet.cs index 3259aba02..f8efc399e 100644 --- a/EndlessClient/ControlSets/BaseControlSet.cs +++ b/EndlessClient/ControlSets/BaseControlSet.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using EndlessClient.Content; using EndlessClient.GameExecution; using EOLib.Graphics; using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using XNAControls; @@ -43,7 +43,7 @@ protected BaseControlSet() } public virtual void InitializeResources(INativeGraphicsManager gfxManager, - ContentManager xnaContentManager) + IContentProvider contentProvider) { if (_resourcesInitialized) throw new InvalidOperationException("Error initializing resources: resources have already been initialized"); @@ -52,10 +52,10 @@ public virtual void InitializeResources(INativeGraphicsManager gfxManager, _secondaryButtonTexture = gfxManager.TextureFromResource(GFXTypes.PreLoginUI, 14, true); _smallButtonSheet = gfxManager.TextureFromResource(GFXTypes.PreLoginUI, 15, true); - _textBoxBackground = xnaContentManager.Load("tbBack"); - _textBoxLeft = xnaContentManager.Load("tbLeft"); - _textBoxRight = xnaContentManager.Load("tbRight"); - _textBoxCursor = xnaContentManager.Load("cursor"); + _textBoxBackground = contentProvider.Textures[ContentProvider.TBBack]; + _textBoxLeft = contentProvider.Textures[ContentProvider.TBLeft]; + _textBoxRight = contentProvider.Textures[ContentProvider.TBRight]; + _textBoxCursor = contentProvider.Textures[ContentProvider.Cursor]; _backgroundImages = new Texture2D[7]; for (int i = 0; i < _backgroundImages.Length; ++i) diff --git a/EndlessClient/ControlSets/ControlSetFactory.cs b/EndlessClient/ControlSets/ControlSetFactory.cs index 08812c294..2e8a87d6b 100644 --- a/EndlessClient/ControlSets/ControlSetFactory.cs +++ b/EndlessClient/ControlSets/ControlSetFactory.cs @@ -8,6 +8,7 @@ using EndlessClient.Input; using EndlessClient.UIControls; using EOLib.Config; +using EOLib.Domain.Login; using EOLib.Graphics; namespace EndlessClient.ControlSets @@ -18,10 +19,11 @@ public class ControlSetFactory : IControlSetFactory private readonly INativeGraphicsManager _nativeGraphicsManager; private readonly IEOMessageBoxFactory _messageBoxFactory; private readonly IHudControlsFactory _hudControlsFactory; - private readonly IContentManagerProvider _contentManagerProvider; + private readonly IContentProvider _contentProvider; private readonly IKeyboardDispatcherProvider _keyboardDispatcherProvider; private readonly IConfigurationProvider _configProvider; private readonly ICharacterInfoPanelFactory _characterInfoPanelFactory; + private readonly ICharacterSelectorProvider _characterSelectorProvider; private IMainButtonController _mainButtonController; private IAccountController _accountController; private ILoginController _loginController; @@ -30,18 +32,20 @@ public class ControlSetFactory : IControlSetFactory public ControlSetFactory(INativeGraphicsManager nativeGraphicsManager, IEOMessageBoxFactory messageBoxFactory, IHudControlsFactory hudControlsFactory, - IContentManagerProvider contentManagerProvider, + IContentProvider contentProvider, IKeyboardDispatcherProvider keyboardDispatcherProvider, IConfigurationProvider configProvider, - ICharacterInfoPanelFactory characterInfoPanelFactory) + ICharacterInfoPanelFactory characterInfoPanelFactory, + ICharacterSelectorProvider characterSelectorProvider) { _nativeGraphicsManager = nativeGraphicsManager; _messageBoxFactory = messageBoxFactory; _hudControlsFactory = hudControlsFactory; - _contentManagerProvider = contentManagerProvider; + _contentProvider = contentProvider; _keyboardDispatcherProvider = keyboardDispatcherProvider; _configProvider = configProvider; _characterInfoPanelFactory = characterInfoPanelFactory; + _characterSelectorProvider = characterSelectorProvider; } public IControlSet CreateControlsForState(GameStates newState, IControlSet currentControlSet) @@ -51,7 +55,7 @@ public IControlSet CreateControlsForState(GameStates newState, IControlSet curre throw new InvalidOperationException("Missing controllers - the Unity container was initialized incorrectly"); var controlSet = GetSetBasedOnState(newState); - controlSet.InitializeResources(_nativeGraphicsManager, _contentManagerProvider.Content); + controlSet.InitializeResources(_nativeGraphicsManager, _contentProvider); controlSet.InitializeControls(currentControlSet); return controlSet; } @@ -89,6 +93,7 @@ private IControlSet GetSetBasedOnState(GameStates newState) _keyboardDispatcherProvider.Dispatcher, _mainButtonController, _characterInfoPanelFactory, + _characterSelectorProvider, _characterManagementController, _accountController); case GameStates.PlayingTheGame: diff --git a/EndlessClient/ControlSets/CreateAccountControlSet.cs b/EndlessClient/ControlSets/CreateAccountControlSet.cs index 2fbfaa4a2..e87eb133a 100644 --- a/EndlessClient/ControlSets/CreateAccountControlSet.cs +++ b/EndlessClient/ControlSets/CreateAccountControlSet.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using EndlessClient.Content; using EndlessClient.Controllers; using EndlessClient.GameExecution; using EndlessClient.Input; @@ -7,7 +8,6 @@ using EOLib.Domain.Account; using EOLib.Graphics; using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using XNAControls; @@ -41,9 +41,9 @@ public CreateAccountControlSet(KeyboardDispatcher dispatcher, _accountController = accountController; } - public override void InitializeResources(INativeGraphicsManager gfxManager, ContentManager xnaContentManager) + public override void InitializeResources(INativeGraphicsManager gfxManager, IContentProvider contentProvider) { - base.InitializeResources(gfxManager, xnaContentManager); + base.InitializeResources(gfxManager, contentProvider); _labelsTexture = gfxManager.TextureFromResource(GFXTypes.PreLoginUI, 12, true); } diff --git a/EndlessClient/ControlSets/EmptyControlSet.cs b/EndlessClient/ControlSets/EmptyControlSet.cs index 07f70c38a..2318b7edb 100644 --- a/EndlessClient/ControlSets/EmptyControlSet.cs +++ b/EndlessClient/ControlSets/EmptyControlSet.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using System.Linq; +using EndlessClient.Content; using EndlessClient.GameExecution; using EOLib.Graphics; using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Content; using XNAControls; namespace EndlessClient.ControlSets @@ -19,7 +19,7 @@ public class EmptyControlSet : IControlSet public IReadOnlyList XNAControlComponents => AllComponents.OfType().ToList(); - public void InitializeResources(INativeGraphicsManager gfxManager, ContentManager xnaContentManager) + public void InitializeResources(INativeGraphicsManager gfxManager, IContentProvider contentProvider) { } diff --git a/EndlessClient/ControlSets/IControlSet.cs b/EndlessClient/ControlSets/IControlSet.cs index 4a64fead4..59e344c63 100644 --- a/EndlessClient/ControlSets/IControlSet.cs +++ b/EndlessClient/ControlSets/IControlSet.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; +using EndlessClient.Content; using EndlessClient.GameExecution; using EOLib.Graphics; using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Content; using XNAControls; namespace EndlessClient.ControlSets @@ -29,8 +29,8 @@ public interface IControlSet : IDisposable /// Initialize the required resources for the control set from the resource dependencies. Should be called before InitializeControls() /// /// An initialized native graphics manager - /// The ContentManager for the game - void InitializeResources(INativeGraphicsManager gfxManager, ContentManager xnaContentManager); + /// The ContentProvider for the game + void InitializeResources(INativeGraphicsManager gfxManager, IContentProvider contentProvider); /// /// Create the controls for this IControlSet based on an existing set of controls diff --git a/EndlessClient/ControlSets/InitialControlSet.cs b/EndlessClient/ControlSets/InitialControlSet.cs index a4b230a42..af79295cd 100644 --- a/EndlessClient/ControlSets/InitialControlSet.cs +++ b/EndlessClient/ControlSets/InitialControlSet.cs @@ -1,4 +1,5 @@ using System; +using EndlessClient.Content; using EndlessClient.Controllers; using EndlessClient.GameExecution; using EOLib; @@ -38,9 +39,9 @@ public InitialControlSet(IConfigurationProvider configProvider, _randomGen = new Random(); } - public override void InitializeResources(INativeGraphicsManager gfxManager, ContentManager xnaContentManager) + public override void InitializeResources(INativeGraphicsManager gfxManager, IContentProvider contentProvider) { - base.InitializeResources(gfxManager, xnaContentManager); + base.InitializeResources(gfxManager, contentProvider); for (int i = 0; i < _personSet1.Length; ++i) _personSet1[i] = gfxManager.TextureFromResource(GFXTypes.PreLoginUI, 41 + i, true); diff --git a/EndlessClient/ControlSets/IntermediateControlSet.cs b/EndlessClient/ControlSets/IntermediateControlSet.cs index a7ac163a6..1c5fe6ea2 100644 --- a/EndlessClient/ControlSets/IntermediateControlSet.cs +++ b/EndlessClient/ControlSets/IntermediateControlSet.cs @@ -1,9 +1,9 @@ using System; +using EndlessClient.Content; using EndlessClient.Controllers; using EndlessClient.GameExecution; using EOLib.Graphics; using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using XNAControls; @@ -27,9 +27,9 @@ protected IntermediateControlSet(KeyboardDispatcher dispatcher, _randomGen = new Random(); } - public override void InitializeResources(INativeGraphicsManager gfxManager, ContentManager xnaContentManager) + public override void InitializeResources(INativeGraphicsManager gfxManager, IContentProvider contentProvider) { - base.InitializeResources(gfxManager, xnaContentManager); + base.InitializeResources(gfxManager, contentProvider); for (int i = 0; i < _personSet2.Length; ++i) _personSet2[i] = gfxManager.TextureFromResource(GFXTypes.PreLoginUI, 61 + i, true); diff --git a/EndlessClient/ControlSets/LoggedInControlSet.cs b/EndlessClient/ControlSets/LoggedInControlSet.cs index da285ad6d..0fefcadf4 100644 --- a/EndlessClient/ControlSets/LoggedInControlSet.cs +++ b/EndlessClient/ControlSets/LoggedInControlSet.cs @@ -4,6 +4,7 @@ using EndlessClient.Controllers; using EndlessClient.GameExecution; using EndlessClient.UIControls; +using EOLib.Domain.Login; using Microsoft.Xna.Framework; using XNAControls; @@ -12,6 +13,7 @@ namespace EndlessClient.ControlSets public class LoggedInControlSet : IntermediateControlSet { private readonly ICharacterInfoPanelFactory _characterInfoPanelFactory; + private readonly ICharacterSelectorProvider _characterSelectorProvider; private readonly ICharacterManagementController _characterManagementController; private readonly IAccountController _accountController; private readonly List _characterInfoPanels; @@ -25,11 +27,13 @@ public class LoggedInControlSet : IntermediateControlSet public LoggedInControlSet(KeyboardDispatcher dispatcher, IMainButtonController mainButtonController, ICharacterInfoPanelFactory characterInfoPanelFactory, + ICharacterSelectorProvider characterSelectorProvider, ICharacterManagementController characterManagementController, IAccountController accountController) : base(dispatcher, mainButtonController) { _characterInfoPanelFactory = characterInfoPanelFactory; + _characterSelectorProvider = characterSelectorProvider; _characterManagementController = characterManagementController; _accountController = accountController; _characterInfoPanels = new List(); @@ -40,7 +44,7 @@ protected override void InitializeControlsHelper(IControlSet currentControlSet) base.InitializeControlsHelper(currentControlSet); _changePasswordButton = GetControl(currentControlSet, GameControlIdentifier.ChangePasswordButton, GetPasswordButton); - _characterInfoPanels.AddRange(_characterInfoPanelFactory.CreatePanels()); + _characterInfoPanels.AddRange(_characterInfoPanelFactory.CreatePanels(_characterSelectorProvider.Characters)); _allComponents.Add(_changePasswordButton); _allComponents.AddRange(_characterInfoPanels); diff --git a/EndlessClient/ControlSets/LoginPromptControlSet.cs b/EndlessClient/ControlSets/LoginPromptControlSet.cs index 21241da8d..3c9e4efb9 100644 --- a/EndlessClient/ControlSets/LoginPromptControlSet.cs +++ b/EndlessClient/ControlSets/LoginPromptControlSet.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Threading; +using EndlessClient.Content; using EndlessClient.Controllers; using EndlessClient.GameExecution; using EndlessClient.Input; @@ -44,9 +45,9 @@ public LoginPromptControlSet(KeyboardDispatcher dispatcher, _loginController = loginController; } - public override void InitializeResources(INativeGraphicsManager gfxManager, ContentManager xnaContentManager) + public override void InitializeResources(INativeGraphicsManager gfxManager, IContentProvider contentProvider) { - base.InitializeResources(gfxManager, xnaContentManager); + base.InitializeResources(gfxManager, contentProvider); _loginBackgroundTexture = gfxManager.TextureFromResource(GFXTypes.PreLoginUI, 2); } diff --git a/EndlessClient/Dialogs/ChangePasswordDialog.cs b/EndlessClient/Dialogs/ChangePasswordDialog.cs index 984cd896b..7ca699875 100644 --- a/EndlessClient/Dialogs/ChangePasswordDialog.cs +++ b/EndlessClient/Dialogs/ChangePasswordDialog.cs @@ -35,7 +35,7 @@ public class ChangePasswordDialog : BaseEODialog public ChangePasswordDialog(INativeGraphicsManager nativeGraphicsManager, IGameStateProvider gameStateProvider, - IContentManagerProvider contentManagerProvider, + IContentProvider contentProvider, IEOMessageBoxFactory eoMessageBoxFactory, IKeyboardDispatcherProvider keyboardDispatcherProvider, IPlayerInfoProvider playerInfoProvider, @@ -48,7 +48,7 @@ public ChangePasswordDialog(INativeGraphicsManager nativeGraphicsManager, BackgroundTexture = nativeGraphicsManager.TextureFromResource(GFXTypes.PreLoginUI, 21); - var cursorTexture = contentManagerProvider.Content.Load("Cursor"); + var cursorTexture = contentProvider.Textures[ContentProvider.Cursor]; _inputBoxes = new IXNATextBox[4]; for (int i = 0; i < _inputBoxes.Length; ++i) diff --git a/EndlessClient/Dialogs/CreateCharacterDialog.cs b/EndlessClient/Dialogs/CreateCharacterDialog.cs index 98548a89c..eb78b117e 100644 --- a/EndlessClient/Dialogs/CreateCharacterDialog.cs +++ b/EndlessClient/Dialogs/CreateCharacterDialog.cs @@ -1,4 +1,5 @@ using System; +using EndlessClient.Content; using EndlessClient.Dialogs.Factories; using EndlessClient.Dialogs.Services; using EndlessClient.GameExecution; @@ -9,7 +10,6 @@ using EOLib.Graphics; using EOLib.Localization; using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using XNAControls; @@ -41,7 +41,7 @@ public CreateCharacterDialog( INativeGraphicsManager nativeGraphicsManager, IGameStateProvider gameStateProvider, ICharacterRendererFactory rendererFactory, - ContentManager contentManager, + IContentProvider contentProvider, KeyboardDispatcher dispatcher, IEOMessageBoxFactory messageBoxFactory, IEODialogButtonService eoDialogButtonService) @@ -52,7 +52,7 @@ public CreateCharacterDialog( _charCreateSheet = nativeGraphicsManager.TextureFromResource(GFXTypes.PreLoginUI, 22); - var cursorTexture = contentManager.Load("cursor"); + var cursorTexture = contentProvider.Textures[ContentProvider.Cursor]; _inputBox = new XNATextBox(new Rectangle(80, 57, 138, 19), Constants.FontSize08, caretTexture: cursorTexture) { LeftPadding = 5, diff --git a/EndlessClient/Dialogs/Factories/ChangePasswordDialogFactory.cs b/EndlessClient/Dialogs/Factories/ChangePasswordDialogFactory.cs index 8ef219613..1720446f5 100644 --- a/EndlessClient/Dialogs/Factories/ChangePasswordDialogFactory.cs +++ b/EndlessClient/Dialogs/Factories/ChangePasswordDialogFactory.cs @@ -13,7 +13,7 @@ public class ChangePasswordDialogFactory : IChangePasswordDialogFactory { private readonly INativeGraphicsManager _nativeGraphicsManager; private readonly IGameStateProvider _gameStateProvider; - private readonly IContentManagerProvider _contentManagerProvider; + private readonly IContentProvider _contentProvider; private readonly IEOMessageBoxFactory _eoMessageBoxFactory; private readonly IKeyboardDispatcherProvider _keyboardDispatcherProvider; private readonly IPlayerInfoProvider _playerInfoProvider; @@ -21,7 +21,7 @@ public class ChangePasswordDialogFactory : IChangePasswordDialogFactory public ChangePasswordDialogFactory(INativeGraphicsManager nativeGraphicsManager, IGameStateProvider gameStateProvider, - IContentManagerProvider contentManagerProvider, + IContentProvider contentProvider, IEOMessageBoxFactory eoMessageBoxFactory, IKeyboardDispatcherProvider keyboardDispatcherProvider, IPlayerInfoProvider playerInfoProvider, @@ -29,7 +29,7 @@ public ChangePasswordDialogFactory(INativeGraphicsManager nativeGraphicsManager, { _nativeGraphicsManager = nativeGraphicsManager; _gameStateProvider = gameStateProvider; - _contentManagerProvider = contentManagerProvider; + _contentProvider = contentProvider; _eoMessageBoxFactory = eoMessageBoxFactory; _keyboardDispatcherProvider = keyboardDispatcherProvider; _playerInfoProvider = playerInfoProvider; @@ -40,7 +40,7 @@ public ChangePasswordDialog BuildChangePasswordDialog() { return new ChangePasswordDialog(_nativeGraphicsManager, _gameStateProvider, - _contentManagerProvider, + _contentProvider, _eoMessageBoxFactory, _keyboardDispatcherProvider, _playerInfoProvider, diff --git a/EndlessClient/Dialogs/Factories/CreateAccountWarningDialogFactory.cs b/EndlessClient/Dialogs/Factories/CreateAccountWarningDialogFactory.cs index ec6afd21b..291f845d0 100644 --- a/EndlessClient/Dialogs/Factories/CreateAccountWarningDialogFactory.cs +++ b/EndlessClient/Dialogs/Factories/CreateAccountWarningDialogFactory.cs @@ -1,4 +1,5 @@ using AutomaticTypeMapper; +using EndlessClient.Content; using EndlessClient.Dialogs.Services; using EndlessClient.GameExecution; using EOLib.Graphics; @@ -10,15 +11,18 @@ namespace EndlessClient.Dialogs.Factories public class CreateAccountWarningDialogFactory : ICreateAccountWarningDialogFactory { private readonly INativeGraphicsManager _nativeGraphicsManager; + private readonly IContentProvider _contentProvider; private readonly IGameStateProvider _gameStateProvider; private readonly IEODialogButtonService _eoDialogButtonService; public CreateAccountWarningDialogFactory( INativeGraphicsManager nativeGraphicsManager, + IContentProvider contentProvider, IGameStateProvider gameStateProvider, IEODialogButtonService eoDialogButtonService) { _nativeGraphicsManager = nativeGraphicsManager; + _contentProvider = contentProvider; _gameStateProvider = gameStateProvider; _eoDialogButtonService = eoDialogButtonService; } @@ -27,6 +31,7 @@ public IXNADialog ShowCreateAccountWarningDialog(string warningMessage) { return new ScrollingMessageDialog( _nativeGraphicsManager, + _contentProvider, _gameStateProvider, _eoDialogButtonService) { diff --git a/EndlessClient/Dialogs/Factories/CreateCharacterDialogFactory.cs b/EndlessClient/Dialogs/Factories/CreateCharacterDialogFactory.cs index a4b8c355a..a6a7b108a 100644 --- a/EndlessClient/Dialogs/Factories/CreateCharacterDialogFactory.cs +++ b/EndlessClient/Dialogs/Factories/CreateCharacterDialogFactory.cs @@ -14,7 +14,7 @@ public class CreateCharacterDialogFactory : ICreateCharacterDialogFactory private readonly INativeGraphicsManager _nativeGraphicsManager; private readonly IGameStateProvider _gameStateProvider; private readonly ICharacterRendererFactory _characterRendererFactory; - private readonly IContentManagerProvider _contentManagerProvider; + private readonly IContentProvider _contentProvider; private readonly IKeyboardDispatcherProvider _keyboardDispatcherProvider; private readonly IEOMessageBoxFactory _eoMessageBoxFactory; private readonly IEODialogButtonService _dialogButtonService; @@ -22,7 +22,7 @@ public class CreateCharacterDialogFactory : ICreateCharacterDialogFactory public CreateCharacterDialogFactory(INativeGraphicsManager nativeGraphicsManager, IGameStateProvider gameStateProvider, ICharacterRendererFactory characterRendererFactory, - IContentManagerProvider contentManagerProvider, + IContentProvider contentProvider, IKeyboardDispatcherProvider keyboardDispatcherProvider, IEOMessageBoxFactory eoMessageBoxFactory, IEODialogButtonService dialogButtonService) @@ -30,7 +30,7 @@ public CreateCharacterDialogFactory(INativeGraphicsManager nativeGraphicsManager _nativeGraphicsManager = nativeGraphicsManager; _gameStateProvider = gameStateProvider; _characterRendererFactory = characterRendererFactory; - _contentManagerProvider = contentManagerProvider; + _contentProvider = contentProvider; _keyboardDispatcherProvider = keyboardDispatcherProvider; _eoMessageBoxFactory = eoMessageBoxFactory; _dialogButtonService = dialogButtonService; @@ -41,7 +41,7 @@ public CreateCharacterDialog BuildCreateCharacterDialog() return new CreateCharacterDialog(_nativeGraphicsManager, _gameStateProvider, _characterRendererFactory, - _contentManagerProvider.Content, + _contentProvider, _keyboardDispatcherProvider.Dispatcher, _eoMessageBoxFactory, _dialogButtonService); diff --git a/EndlessClient/Dialogs/Factories/TextInputDialogFactory.cs b/EndlessClient/Dialogs/Factories/TextInputDialogFactory.cs index ba48ca80f..fb619c806 100644 --- a/EndlessClient/Dialogs/Factories/TextInputDialogFactory.cs +++ b/EndlessClient/Dialogs/Factories/TextInputDialogFactory.cs @@ -14,19 +14,19 @@ public class TextInputDialogFactory : ITextInputDialogFactory private readonly INativeGraphicsManager _nativeGraphicsManager; private readonly IEODialogButtonService _eoDialogButtonService; private readonly IKeyboardDispatcherRepository _keyboardDispatcherRepository; - private readonly IContentManagerProvider _contentManagerProvider; + private readonly IContentProvider _contentProvider; public TextInputDialogFactory(IGameStateProvider gameStateProvider, INativeGraphicsManager nativeGraphicsManager, IEODialogButtonService eoDialogButtonService, IKeyboardDispatcherRepository keyboardDispatcherRepository, - IContentManagerProvider contentManagerProvider) + IContentProvider contentProvider) { _gameStateProvider = gameStateProvider; _nativeGraphicsManager = nativeGraphicsManager; _eoDialogButtonService = eoDialogButtonService; _keyboardDispatcherRepository = keyboardDispatcherRepository; - _contentManagerProvider = contentManagerProvider; + _contentProvider = contentProvider; } public TextInputDialog Create(string prompt, int maxInputChars = 12) @@ -35,7 +35,7 @@ public TextInputDialog Create(string prompt, int maxInputChars = 12) _nativeGraphicsManager, _eoDialogButtonService, _keyboardDispatcherRepository, - _contentManagerProvider, + _contentProvider, prompt, maxInputChars); } diff --git a/EndlessClient/Dialogs/ScrollingMessageDialog.cs b/EndlessClient/Dialogs/ScrollingMessageDialog.cs index e8235c874..e77349389 100644 --- a/EndlessClient/Dialogs/ScrollingMessageDialog.cs +++ b/EndlessClient/Dialogs/ScrollingMessageDialog.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using EndlessClient.Content; using EndlessClient.Dialogs.Services; using EndlessClient.GameExecution; using EndlessClient.UIControls; @@ -52,11 +53,12 @@ public string MessageText } public ScrollingMessageDialog(INativeGraphicsManager nativeGraphicsManager, + IContentProvider contentProvider, IGameStateProvider gameStateProvider, IEODialogButtonService eoDialogButtonService) : base(gameStateProvider) { - _font = Game.Content.Load(Constants.FontSize08); + _font = contentProvider.Fonts[Constants.FontSize08]; _textSplitter = new TextSplitter("", _font) { LineLength = 275 }; BackgroundTexture = nativeGraphicsManager.TextureFromResource(GFXTypes.PreLoginUI, 40); diff --git a/EndlessClient/Dialogs/TextInputDialog.cs b/EndlessClient/Dialogs/TextInputDialog.cs index 2df523e22..a3380f0a7 100644 --- a/EndlessClient/Dialogs/TextInputDialog.cs +++ b/EndlessClient/Dialogs/TextInputDialog.cs @@ -23,7 +23,7 @@ public TextInputDialog(IGameStateProvider gameStateProvider, INativeGraphicsManager nativeGraphicsManager, IEODialogButtonService eoDialogButtonService, IKeyboardDispatcherRepository keyboardDispatcherRepository, - IContentManagerProvider contentManagerProvider, + IContentProvider contentProvider, string prompt, int maxInputChars = 12) : base(gameStateProvider) @@ -44,7 +44,7 @@ public TextInputDialog(IGameStateProvider gameStateProvider, lblPrompt.Initialize(); lblPrompt.SetParentControl(this); - _inputBox = new XNATextBox(new Rectangle(37, 74, 192, 19), Constants.FontSize08, caretTexture: contentManagerProvider.Content.Load("cursor")) + _inputBox = new XNATextBox(new Rectangle(37, 74, 192, 19), Constants.FontSize08, caretTexture: contentProvider.Textures[ContentProvider.Cursor]) { MaxChars = maxInputChars, LeftPadding = 4, diff --git a/EndlessClient/GameExecution/EndlessGame.cs b/EndlessClient/GameExecution/EndlessGame.cs index 9c5d348ac..85921c70d 100644 --- a/EndlessClient/GameExecution/EndlessGame.cs +++ b/EndlessClient/GameExecution/EndlessGame.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Linq; using System.Runtime.InteropServices; using AutomaticTypeMapper; using EndlessClient.Content; @@ -6,6 +7,8 @@ using EndlessClient.Rendering; using EndlessClient.Rendering.Chat; using EndlessClient.Test; +using EndlessClient.UIControls; +using EOLib.Domain.Character; using EOLib.Graphics; using EOLib.IO; using EOLib.IO.Actions; @@ -20,6 +23,7 @@ namespace EndlessClient.GameExecution public class EndlessGame : Game, IEndlessGame { private readonly IClientWindowSizeProvider _windowSizeProvider; + private readonly IContentProvider _contentProvider; private readonly IGraphicsDeviceRepository _graphicsDeviceRepository; private readonly IControlSetRepository _controlSetRepository; private readonly IControlSetFactory _controlSetFactory; @@ -28,11 +32,13 @@ public class EndlessGame : Game, IEndlessGame private readonly ILoggerProvider _loggerProvider; private readonly IChatBubbleTextureProvider _chatBubbleTextureProvider; private readonly IShaderRepository _shaderRepository; + private readonly ICharacterInfoPanelFactory _characterInfoPanelFactory; private GraphicsDeviceManager _graphicsDeviceManager; private KeyboardState _previousKeyState; public EndlessGame(IClientWindowSizeProvider windowSizeProvider, + IContentProvider contentProvider, IGraphicsDeviceRepository graphicsDeviceRepository, IControlSetRepository controlSetRepository, IControlSetFactory controlSetFactory, @@ -40,9 +46,11 @@ public EndlessGame(IClientWindowSizeProvider windowSizeProvider, IPubFileLoadActions pubFileLoadActions, ILoggerProvider loggerProvider, IChatBubbleTextureProvider chatBubbleTextureProvider, - IShaderRepository shaderRepository) + IShaderRepository shaderRepository, + ICharacterInfoPanelFactory characterInfoPanelFactory) { _windowSizeProvider = windowSizeProvider; + _contentProvider = contentProvider; _graphicsDeviceRepository = graphicsDeviceRepository; _controlSetRepository = controlSetRepository; _controlSetFactory = controlSetFactory; @@ -51,6 +59,7 @@ public EndlessGame(IClientWindowSizeProvider windowSizeProvider, _loggerProvider = loggerProvider; _chatBubbleTextureProvider = chatBubbleTextureProvider; _shaderRepository = shaderRepository; + _characterInfoPanelFactory = characterInfoPanelFactory; _graphicsDeviceManager = new GraphicsDeviceManager(this); @@ -70,12 +79,12 @@ protected override void Initialize() _graphicsDeviceManager.PreferredBackBufferWidth = _windowSizeProvider.Width; _graphicsDeviceManager.PreferredBackBufferHeight = _windowSizeProvider.Height; _graphicsDeviceManager.ApplyChanges(); - - SetUpInitialControlSet(); } protected override void LoadContent() { + _contentProvider.Load(); + //todo: all the things that should load stuff as part of game's load/initialize should be broken into a pattern _chatBubbleTextureProvider.LoadContent(); @@ -94,6 +103,16 @@ protected override void LoadContent() _shaderRepository.Shaders[ShaderRepository.HairClip] = new Effect(GraphicsDevice, shaderBytes); } + // for some reason initializing these and then killing them speeds up transition from Login -> LoggedIn state + // TODO: figure out why this happens???? + foreach (var panel in _characterInfoPanelFactory.CreatePanels(Enumerable.Repeat(new Character(), 3))) + { + panel.Initialize(); + panel.Dispose(); + } + + SetUpInitialControlSet(); + base.LoadContent(); } diff --git a/EndlessClient/GameExecution/GameStateActions.cs b/EndlessClient/GameExecution/GameStateActions.cs index 92f438bc6..c8b6d299e 100644 --- a/EndlessClient/GameExecution/GameStateActions.cs +++ b/EndlessClient/GameExecution/GameStateActions.cs @@ -70,8 +70,7 @@ private void RemoveOldComponents(IControlSet currentSet, IControlSet nextSet) var componentsToRemove = FindUnusedComponents(currentSet, nextSet); var disposableComponents = componentsToRemove .Where(x => !(x is PacketHandlerGameComponent)) - .OfType() - .ToList(); + .OfType(); foreach (var component in disposableComponents) component.Dispose(); diff --git a/EndlessClient/HUD/Controls/HudControlsFactory.cs b/EndlessClient/HUD/Controls/HudControlsFactory.cs index c2ab539dc..b22523fcd 100644 --- a/EndlessClient/HUD/Controls/HudControlsFactory.cs +++ b/EndlessClient/HUD/Controls/HudControlsFactory.cs @@ -44,7 +44,7 @@ public class HudControlsFactory : IHudControlsFactory private readonly IUserInputRepository _userInputRepository; private readonly IStatusLabelSetter _statusLabelSetter; private readonly IStatusLabelTextProvider _statusLabelTextProvider; - private readonly IContentManagerProvider _contentManagerProvider; + private readonly IContentProvider _contentProvider; private readonly IHudControlProvider _hudControlProvider; private readonly ICurrentMapProvider _currentMapProvider; private readonly IChatModeCalculator _chatModeCalculator; @@ -68,7 +68,7 @@ public HudControlsFactory(IHudButtonController hudButtonController, IUserInputRepository userInputRepository, IStatusLabelSetter statusLabelSetter, IStatusLabelTextProvider statusLabelTextProvider, - IContentManagerProvider contentManagerProvider, + IContentProvider contentProvider, IHudControlProvider hudControlProvider, ICurrentMapProvider currentMapProvider, IChatModeCalculator chatModeCalculator, @@ -91,7 +91,7 @@ public HudControlsFactory(IHudButtonController hudButtonController, _userInputRepository = userInputRepository; _statusLabelSetter = statusLabelSetter; _statusLabelTextProvider = statusLabelTextProvider; - _contentManagerProvider = contentManagerProvider; + _contentProvider = contentProvider; _hudControlProvider = hudControlProvider; _currentMapProvider = currentMapProvider; _chatModeCalculator = chatModeCalculator; @@ -336,7 +336,7 @@ private ChatModePictureBox CreateChatModePictureBox() private ChatTextBox CreateChatTextBox() { - var chatTextBox = new ChatTextBox(_contentManagerProvider) + var chatTextBox = new ChatTextBox(_contentProvider) { Text = "", Selected = true, diff --git a/EndlessClient/HUD/Panels/HudPanelFactory.cs b/EndlessClient/HUD/Panels/HudPanelFactory.cs index cf2408a76..07755e770 100644 --- a/EndlessClient/HUD/Panels/HudPanelFactory.cs +++ b/EndlessClient/HUD/Panels/HudPanelFactory.cs @@ -20,7 +20,7 @@ public class HudPanelFactory : IHudPanelFactory private const int HUD_CONTROL_LAYER = 130; private readonly INativeGraphicsManager _nativeGraphicsManager; - private readonly IContentManagerProvider _contentManagerProvider; + private readonly IContentProvider _contentProvider; private readonly IHudControlProvider _hudControlProvider; private readonly INewsProvider _newsProvider; private readonly IChatProvider _chatProvider; @@ -32,7 +32,7 @@ public class HudPanelFactory : IHudPanelFactory private readonly IFriendIgnoreListService _friendIgnoreListService; public HudPanelFactory(INativeGraphicsManager nativeGraphicsManager, - IContentManagerProvider contentManagerProvider, + IContentProvider contentProvider, IHudControlProvider hudControlProvider, INewsProvider newsProvider, IChatProvider chatProvider, @@ -44,7 +44,7 @@ public HudPanelFactory(INativeGraphicsManager nativeGraphicsManager, IFriendIgnoreListService friendIgnoreListService) { _nativeGraphicsManager = nativeGraphicsManager; - _contentManagerProvider = contentManagerProvider; + _contentProvider = contentProvider; _hudControlProvider = hudControlProvider; _newsProvider = newsProvider; _chatProvider = chatProvider; @@ -58,7 +58,7 @@ public HudPanelFactory(INativeGraphicsManager nativeGraphicsManager, public NewsPanel CreateNewsPanel() { - var chatFont = _contentManagerProvider.Content.Load(Constants.FontSize08); + var chatFont = _contentProvider.Fonts[Constants.FontSize08]; return new NewsPanel(_nativeGraphicsManager, new ChatRenderableGenerator(_friendIgnoreListService, chatFont), @@ -83,7 +83,7 @@ public PassiveSpellsPanel CreatePassiveSpellsPanel() public ChatPanel CreateChatPanel() { - var chatFont = _contentManagerProvider.Content.Load(Constants.FontSize08); + var chatFont = _contentProvider.Fonts[Constants.FontSize08]; return new ChatPanel(_nativeGraphicsManager, new ChatRenderableGenerator(_friendIgnoreListService, chatFont), @@ -104,7 +104,7 @@ public StatsPanel CreateStatsPanel() public OnlineListPanel CreateOnlineListPanel() { - var chatFont = _contentManagerProvider.Content.Load(Constants.FontSize08); + var chatFont = _contentProvider.Fonts[Constants.FontSize08]; return new OnlineListPanel(_nativeGraphicsManager, _hudControlProvider, _friendIgnoreListService, chatFont) { DrawOrder = HUD_CONTROL_LAYER }; } diff --git a/EndlessClient/Initialization/EndlessClientInitializer.cs b/EndlessClient/Initialization/EndlessClientInitializer.cs index b7682b095..d56dac75e 100644 --- a/EndlessClient/Initialization/EndlessClientInitializer.cs +++ b/EndlessClient/Initialization/EndlessClientInitializer.cs @@ -18,7 +18,7 @@ public class EndlessClientInitializer : IGameInitializer { private readonly IEndlessGame _game; private readonly IEndlessGameRepository _endlessGameRepository; - private readonly IContentManagerRepository _contentManagerRepository; + private readonly IContentProvider _contentProvider; private readonly IKeyboardDispatcherRepository _keyboardDispatcherRepository; private readonly PacketHandlerGameComponent _packetHandlerGameComponent; @@ -33,7 +33,7 @@ public class EndlessClientInitializer : IGameInitializer public EndlessClientInitializer(IEndlessGame game, IEndlessGameRepository endlessGameRepository, - IContentManagerRepository contentManagerRepository, + IContentProvider contentProvider, IKeyboardDispatcherRepository keyboardDispatcherRepository, PacketHandlerGameComponent packetHandlerGameComponent, @@ -49,7 +49,7 @@ public EndlessClientInitializer(IEndlessGame game, { _game = game; _endlessGameRepository = endlessGameRepository; - _contentManagerRepository = contentManagerRepository; + _contentProvider = contentProvider; _keyboardDispatcherRepository = keyboardDispatcherRepository; _packetHandlerGameComponent = packetHandlerGameComponent; _mainButtonController = mainButtonController; @@ -69,8 +69,8 @@ public void Initialize() _game.Components.Add(_packetHandlerGameComponent); _endlessGameRepository.Game = _game; - _contentManagerRepository.Content = _game.Content; - _contentManagerRepository.Content.RootDirectory = "ContentPipeline"; + _game.Content.RootDirectory = "ContentPipeline"; + _contentProvider.SetContentManager(_game.Content); _keyboardDispatcherRepository.Dispatcher = new KeyboardDispatcher(_game.Window); diff --git a/EndlessClient/Rendering/Character/CharacterRenderer.cs b/EndlessClient/Rendering/Character/CharacterRenderer.cs index 02db0c3ba..8a866cb48 100644 --- a/EndlessClient/Rendering/Character/CharacterRenderer.cs +++ b/EndlessClient/Rendering/Character/CharacterRenderer.cs @@ -117,26 +117,31 @@ public override void Initialize() _charRenderTarget = _renderTargetFactory.CreateRenderTarget(); _sb = new SpriteBatch(Game.GraphicsDevice); - _nameLabel = new BlinkingLabel(Constants.FontSize08pt5) + if (_gameStateProvider.CurrentState == GameStates.PlayingTheGame) { - Visible = _gameStateProvider.CurrentState == GameStates.PlayingTheGame, - TextWidth = 89, - TextAlign = LabelAlignment.MiddleCenter, - ForeColor = Color.White, - AutoSize = true, - Text = _character?.Name ?? string.Empty, - DrawOrder = 30, - KeepInClientWindowBounds = false, - }; - _nameLabel.Initialize(); - - if (!_nameLabel.Game.Components.Contains(_nameLabel)) - _nameLabel.Game.Components.Add(_nameLabel); + _nameLabel = new BlinkingLabel(Constants.FontSize08pt5) + { + Visible = true, + TextWidth = 89, + TextAlign = LabelAlignment.MiddleCenter, + ForeColor = Color.White, + AutoSize = true, + Text = _character?.Name ?? string.Empty, + DrawOrder = 30, + KeepInClientWindowBounds = false, + }; + _nameLabel.Initialize(); + + if (!_nameLabel.Game.Components.Contains(_nameLabel)) + _nameLabel.Game.Components.Add(_nameLabel); + + _nameLabel.DrawPosition = GetNameLabelPosition(); + + _healthBarRenderer = _healthBarRendererFactory.CreateHealthBarRenderer(this); + } - _nameLabel.DrawPosition = GetNameLabelPosition(); _previousMouseState = _currentMouseState = Mouse.GetState(); - _healthBarRenderer = _healthBarRendererFactory.CreateHealthBarRenderer(this); base.Initialize(); } @@ -184,9 +189,9 @@ public override void Update(GameTime gameTime) { _mapInteractionController.RightClick(new MapCellState { Character = Option.Some(Character) }); } - } - _healthBarRenderer.Update(gameTime); + _healthBarRenderer.Update(gameTime); + } _previousMouseState = _currentMouseState; @@ -239,7 +244,8 @@ public void DrawToSpriteBatch(SpriteBatch spriteBatch) spriteBatch.Draw(_charRenderTarget, new Vector2(0, GetSteppingStoneOffset(Character.RenderProperties)), GetAlphaColor()); _effectRenderer.DrawInFrontOfTarget(spriteBatch); - _healthBarRenderer.DrawToSpriteBatch(spriteBatch); + if (_gameStateProvider.CurrentState == GameStates.PlayingTheGame) + _healthBarRenderer.DrawToSpriteBatch(spriteBatch); } #endregion @@ -328,6 +334,9 @@ private int GetMainCharacterOffsetY() private void UpdateNameLabel(GameTime gameTime) { + if (_gameStateProvider.CurrentState != GameStates.PlayingTheGame) + return; + if (_healthBarRenderer.Visible) { _nameLabel.Visible = false; @@ -473,10 +482,10 @@ protected override void Dispose(bool disposing) if (disposing) { _outline?.Dispose(); - _nameLabel.Dispose(); + _nameLabel?.Dispose(); - _sb.Dispose(); - _charRenderTarget.Dispose(); + _sb?.Dispose(); + _charRenderTarget?.Dispose(); } base.Dispose(disposing); diff --git a/EndlessClient/Rendering/Chat/ChatBubbleTextureProvider.cs b/EndlessClient/Rendering/Chat/ChatBubbleTextureProvider.cs index 9dbde7109..903921620 100644 --- a/EndlessClient/Rendering/Chat/ChatBubbleTextureProvider.cs +++ b/EndlessClient/Rendering/Chat/ChatBubbleTextureProvider.cs @@ -9,33 +9,31 @@ namespace EndlessClient.Rendering.Chat [MappedType(BaseType = typeof(IChatBubbleTextureProvider), IsSingleton = true)] public class ChatBubbleTextureProvider : IChatBubbleTextureProvider { - private readonly IContentManagerProvider _contentManagerProvider; + private readonly IContentProvider _contentProvider; private readonly Dictionary _chatBubbleTextures; public IReadOnlyDictionary ChatBubbleTextures => _chatBubbleTextures; - public ChatBubbleTextureProvider(IContentManagerProvider contentManagerProvider) + public ChatBubbleTextureProvider(IContentProvider contentProvider) { - _contentManagerProvider = contentManagerProvider; + _contentProvider = contentProvider; _chatBubbleTextures = new Dictionary(); } public void LoadContent() { - _chatBubbleTextures.Add(ChatBubbleTexture.TopLeft, Content.Load("ChatBubble\\TL")); - _chatBubbleTextures.Add(ChatBubbleTexture.TopMiddle, Content.Load("ChatBubble\\TM")); - _chatBubbleTextures.Add(ChatBubbleTexture.TopRight, Content.Load("ChatBubble\\TR")); - _chatBubbleTextures.Add(ChatBubbleTexture.MiddleLeft, Content.Load("ChatBubble\\ML")); - _chatBubbleTextures.Add(ChatBubbleTexture.MiddleMiddle, Content.Load("ChatBubble\\MM")); - _chatBubbleTextures.Add(ChatBubbleTexture.MiddleRight, Content.Load("ChatBubble\\MR")); + _chatBubbleTextures.Add(ChatBubbleTexture.TopLeft, _contentProvider.Textures[ContentProvider.ChatTL]); + _chatBubbleTextures.Add(ChatBubbleTexture.TopMiddle, _contentProvider.Textures[ContentProvider.ChatTM]); + _chatBubbleTextures.Add(ChatBubbleTexture.TopRight, _contentProvider.Textures[ContentProvider.ChatTR]); + _chatBubbleTextures.Add(ChatBubbleTexture.MiddleLeft, _contentProvider.Textures[ContentProvider.ChatML]); + _chatBubbleTextures.Add(ChatBubbleTexture.MiddleMiddle, _contentProvider.Textures[ContentProvider.ChatMM]); + _chatBubbleTextures.Add(ChatBubbleTexture.MiddleRight, _contentProvider.Textures[ContentProvider.ChatMR]); //todo: change the first 'R' to a 'B' (for bottom) - _chatBubbleTextures.Add(ChatBubbleTexture.BottomLeft, Content.Load("ChatBubble\\RL")); - _chatBubbleTextures.Add(ChatBubbleTexture.BottomMiddle, Content.Load("ChatBubble\\RM")); - _chatBubbleTextures.Add(ChatBubbleTexture.BottomRight, Content.Load("ChatBubble\\RR")); - _chatBubbleTextures.Add(ChatBubbleTexture.Nubbin, Content.Load("ChatBubble\\NUB")); + _chatBubbleTextures.Add(ChatBubbleTexture.BottomLeft, _contentProvider.Textures[ContentProvider.ChatRL]); + _chatBubbleTextures.Add(ChatBubbleTexture.BottomMiddle, _contentProvider.Textures[ContentProvider.ChatRM]); + _chatBubbleTextures.Add(ChatBubbleTexture.BottomRight, _contentProvider.Textures[ContentProvider.ChatRR]); + _chatBubbleTextures.Add(ChatBubbleTexture.Nubbin, _contentProvider.Textures[ContentProvider.ChatNUB]); } - - private ContentManager Content => _contentManagerProvider.Content; } public interface IChatBubbleTextureProvider diff --git a/EndlessClient/Rendering/MouseCursorRenderer.cs b/EndlessClient/Rendering/MouseCursorRenderer.cs index fc9e78706..acd7d0434 100644 --- a/EndlessClient/Rendering/MouseCursorRenderer.cs +++ b/EndlessClient/Rendering/MouseCursorRenderer.cs @@ -211,11 +211,13 @@ private void UpdateMapItemLabel(Option item) item.Match( some: i => { - if (!_mapItemText.Visible) + var data = _eifFileProvider.EIFFile[i.ItemID]; + var text = _itemStringService.GetStringForMapDisplay(data, i.Amount); + + if (!_mapItemText.Visible || _mapItemText.Text != text) { - var data = _eifFileProvider.EIFFile[i.ItemID]; _mapItemText.Visible = true; - _mapItemText.Text = _itemStringService.GetStringForMapDisplay(data, i.Amount); + _mapItemText.Text = text; _mapItemText.ResizeBasedOnText(); _mapItemText.ForeColor = GetColorForMapDisplay(data); @@ -239,7 +241,6 @@ private void UpdateCursorIndexForTileSpec(TileSpec tileSpec) case TileSpec.JammedDoor: case TileSpec.MapEdge: case TileSpec.FakeWall: - case TileSpec.NPCBoundary: case TileSpec.VultTypo: _shouldDrawCursor = false; break; @@ -263,6 +264,7 @@ private void UpdateCursorIndexForTileSpec(TileSpec tileSpec) case TileSpec.Jukebox: _cursorIndex = CursorIndex.HoverNormal; break; + case TileSpec.NPCBoundary: case TileSpec.Jump: case TileSpec.Water: case TileSpec.Arena: diff --git a/EndlessClient/UIControls/CharacterInfoPanel.cs b/EndlessClient/UIControls/CharacterInfoPanel.cs index f309baa6d..da5567d8a 100644 --- a/EndlessClient/UIControls/CharacterInfoPanel.cs +++ b/EndlessClient/UIControls/CharacterInfoPanel.cs @@ -199,7 +199,7 @@ private Vector2 GetAdminGraphicLocation() private static string CapitalizeName(string name) { - return (char)(name[0] - 32) + name.Substring(1); + return string.IsNullOrEmpty(name) ? string.Empty : (char)(name[0] - 32) + name.Substring(1); } private ISpriteSheet CreateAdminGraphic(AdminLevel adminLevel) diff --git a/EndlessClient/UIControls/CharacterInfoPanelFactory.cs b/EndlessClient/UIControls/CharacterInfoPanelFactory.cs index 0232f6492..2a053c0bc 100644 --- a/EndlessClient/UIControls/CharacterInfoPanelFactory.cs +++ b/EndlessClient/UIControls/CharacterInfoPanelFactory.cs @@ -5,12 +5,13 @@ using EndlessClient.Dialogs.Services; using EndlessClient.Rendering; using EndlessClient.Rendering.Factories; +using EOLib.Domain.Character; using EOLib.Domain.Login; using EOLib.Graphics; namespace EndlessClient.UIControls { - [MappedType(BaseType = typeof(ICharacterInfoPanelFactory), IsSingleton = true)] + [AutoMappedType(IsSingleton = true)] public class CharacterInfoPanelFactory : ICharacterInfoPanelFactory { private readonly ICharacterSelectorProvider _characterProvider; @@ -45,16 +46,15 @@ public void InjectCharacterManagementController(ICharacterManagementController c _characterManagementController = characterManagementController; } - public IEnumerable CreatePanels() + public IEnumerable CreatePanels(IEnumerable characters) { if(_loginController == null || _characterManagementController == null) throw new InvalidOperationException("Missing controllers - the Unity container was initialized incorrectly"); int i = 0; - for (; i < _characterProvider.Characters.Count; ++i) + foreach (var character in characters) { - var character = _characterProvider.Characters[i]; - yield return new CharacterInfoPanel(i, + yield return new CharacterInfoPanel(i++, character, _nativeGraphicsManager, _eoDialogButtonService, diff --git a/EndlessClient/UIControls/ChatTextBox.cs b/EndlessClient/UIControls/ChatTextBox.cs index 832060280..eec3ef6e7 100644 --- a/EndlessClient/UIControls/ChatTextBox.cs +++ b/EndlessClient/UIControls/ChatTextBox.cs @@ -17,10 +17,10 @@ public class ChatTextBox : XNATextBox private bool _ignoreAllInput; private Option _endMuteTime; - public ChatTextBox(IContentManagerProvider contentManagerProvider) + public ChatTextBox(IContentProvider contentManagerProvider) : base(new Rectangle(124, 308, 440, 19), Constants.FontSize08, - caretTexture: contentManagerProvider.Content.Load("cursor")) + caretTexture: contentManagerProvider.Textures[ContentProvider.Cursor]) { MaxChars = 140; _endMuteTime = Option.None(); diff --git a/EndlessClient/UIControls/ICharacterInfoPanelFactory.cs b/EndlessClient/UIControls/ICharacterInfoPanelFactory.cs index 93c87f455..ff8e41531 100644 --- a/EndlessClient/UIControls/ICharacterInfoPanelFactory.cs +++ b/EndlessClient/UIControls/ICharacterInfoPanelFactory.cs @@ -1,11 +1,12 @@ using System.Collections.Generic; using EndlessClient.Controllers; +using EOLib.Domain.Character; namespace EndlessClient.UIControls { public interface ICharacterInfoPanelFactory { - IEnumerable CreatePanels(); + IEnumerable CreatePanels(IEnumerable characters); void InjectLoginController(ILoginController loginController); void InjectCharacterManagementController(ICharacterManagementController characterManagementController); } diff --git a/README.md b/README.md index 536fcf891..e74f8a802 100644 --- a/README.md +++ b/README.md @@ -1,156 +1,132 @@ EndlessClient ============= -[![Build Status](https://ethanmoffat.visualstudio.com/EndlessClient/_apis/build/status/EndlessClient%20Build?branchName=master)](https://ethanmoffat.visualstudio.com/EndlessClient/_build/latest?definitionId=14&branchName=master) +[![Build Status](https://ethanmoffat.visualstudio.com/EndlessClient/_apis/build/status/EndlessClient%20Build?branchName=master)](https://ethanmoffat.visualstudio.com/EndlessClient/_build/latest?definitionId=14&branchName=master) [![Nuget](https://badgen.net/nuget/v/EOLib)](https://badgen.net/nuget/v/EOLib) An open source client for Endless Online written in C# #### Want more features? -This project has been on GitHub since the end of July, 2014. It is currently suffering through a rewrite of the code. If you're looking for the more feature-complete version of the code base, see the old_code branch (now protected) +This project has been on GitHub since the end of July, 2014. It is currently suffering through a rewrite of the code. If you're looking for the more feature-complete version of the code base, see the old_code branch (now protected). #### License Update As of 2020-05-09, this project is relicensed under the MIT license. Older versions of the code are still licensed under the GNU GPLv2 license. The tag `gplv2` has been added to the final commit for which this project is licensed under the GPLv2. #### Jump to: - - [Getting started](#GettingStarted) - [Contributing](contributing.md) + - [Getting started](#GettingStarted) - [Current feature list](#SoFar) - [Todo list](#ToDo) - [New features (also todo)](#NewFeatures) - - [Sample configuration file](#SampleConfigFile) - [Changes from the Original Client](#Changes) - [Included Utility Projects](#Utility) + - [EOBot](#EOBot) Getting started ------------- +### Dependencies + +Source builds require Visual Studio, the .Net 6.0 SDK, and the .Net 3.1 runtime (for building content with the MonoGame content builder pipeline tool). Other dependencies are installed via Nuget. MonoGame no longer needs to be installed ahead of time! + +.Net 6.0 runtime is required to run the pre-build binary. + +On Linux, the `ttf-mscorefonts-installer` package is required. Consult your distribution's package manager documentation for instructions on how to install this. + ### Pre-built binary -Binary releases are not currently available, but may be in the future (due to the recent addition of a CI pipeline). +See [releases](https://github.com/ethanmoffat/EndlessClient/releases) on GitHub for Linux and Windows binaries. .Net 6.0 runtime must be installed. ### Building from source -The only required external dependency is [MonoGame 3.7.1](http://community.monogame.net/t/monogame-3-7-1-release/11173). On Windows, Visual Studio (2015u3+) is used for development. Project Rider is supported on Linux, and Visual Studio 2017 for Mac will work on macOS. - -After installing, clone (or fork+clone) this repository locally and open the solution in your IDE of choice for your platform. All additional dependencies should be restored from Nuget and allow the game to launch after building. +After installing, clone (or fork+clone) this repository locally and open the solution in your IDE of choice for your platform. Current feature list --------------------- - Pre-game menus and dialogs - Debug mode for character offset calculation (press F5 from the initial game screen in a debug build) -- Map rendering and warping +- Map + - Earthquakes + - Spikes + - Map effects + - Water/jump tiles + - Map item interaction + - Map signs + - Mouse cursor + - Click to walk (A* search) + - Animated walls and ground tiles + - Refresh via F12 - Characters - - Walk animations - - Attack animations - - Equipment display (work in progress) + - All animations and equipment supported and 99.5% accurate to the original client + - Sitting + - Paperdoll display and unequipping items + - Health bars + - Context menu / paperdoll via right-click - NPCs - - Walk animations - - Attack animations - - Speech + - All animation frames + - Attacking/health bars - HUD status bars (HP, TP, SP, TNL) - Chat - All chat types properly handled - - Speech bubbles rendered + - Chat bubbles - Character stats and training -- Mouse cursor rendering - - Display of the cursor on the current grid space +- "Who is online" list +- Friend/ignore lists Todo list --------------------- -GitHub issues should be used to track progress. See issues list for more detail. -- Finish map rendering - - Animated walls/tiles -- Finish mouse cursor rendering - - Character/NPC name rendering -- Mouse interactions - - Context menu (right-click) - - Map sign interaction +- Map interactions - Board interaction - - NPC interaction (quests, shops) -- Finish character equipment rendering - - Fix offsets for all equipment types -- Finish NPC alignment to grid -- Map item interaction - - Item pickup/drop -- Paperdoll + - NPC interaction + - Quests + - Shops + - Skills + - Inns + - Law/marriage + - Guilds + - Barber + - Jukebox + - Minimap rendering +- Spell casting +- Item use, equip, drop, junk - HUD panels + - Skills - Inventory - - Online list - Party - Settings -- Friend/ignore list - Quest progress/daily exp -- Sit/stand -- Map refresh (F12) +- Trade - Sounds/music - - Need to track down a cross-platform midi player for background music + - Music depends on a cross-platform MIDI player implementation in C# +- Handling large (900+ entry), multi-part pub files via official EO protocol New features (also todo) ------------------ Here's a working list of things I want to add that would be additional features on top of the original client specs: - - Use built-in patching system prior to log-in to transfer files: help, gfx, pubs, maps, data, sounds, etc. + - Use built-in patching system prior to log-in to transfer files - More than 3 characters per account - - Trading items between characters on the same account (with restrictions) - - Unbounded display size, including scaling HUD with display size (basically, re-vamp the HUD to a more modern design) + - Trading items between characters on the same account + - Better display scaling - Timed map weather systems - - Passive skills (planned for in original but never done) - - In-game macros (planned for in original but never done) + - Passive skills -Most things on the above list would require changes to the server software which would significantly distance it from compatibility with eoserv and the original EO client, so they aren't top priority, but would still be pretty cool to have. I will most likely fork the project for these additional changes. - - -Sample configuration file ------------------- +Changes From Original Client +------------------------------------- -Here is a sample configuration file with the available configuration settings that are currently being parsed by the client. +#### Command-line arguments -A config file is automatically downloaded as part of the EndlessClient.Binaries nuget package and should have all these settings configured. If you would like to change any of these settings while debugging, edit the file in the packages/EndlessClient.Binaries directory as it will be copied over the file in bin/debug or bin/release. + **--host ** Overrides the server set in the config file with a different value. Convenient for testing against different servers from Visual Studio, since the build process will overwrite the configuration file in the output directory. -```ini -#Destination host/ip and port to connect to -[CONNECTION] -Host=ewmoffat.ddns.net #or use game.eoserv.net, enhanced clone of original main server -Port=8078 -#override the version sent from the client to the server. For testing with multiple server versions. -[VERSION] -Major=0 -Minor=0 -Client=28 -#individual settings -[SETTINGS] -Music=off #enable/disable background music -Sound=off #enable/disable sound effects -ShowBaloons=on #show/hide chat bubbles on map -ShowShadows=true #show/hide shadows on map -ShowTransition=true #enable/disable fancy transition on map (custom) -EnableLogging=true #enable/disable logging (Warning: this causes a performance hit and should only be used for debugging purposes) -[CUSTOM] -#seconds after a drop that drop protection will stop (custom) -NPCDropProtectTime=30 -PlayerDropProtectTime=5 -[LANGUAGE] -#0=english 1=dutch 2=swedish 3=portuguese (defaults to english) -Language=0 -#note - different keyboard layouts are not going to be supported -[CHAT] -Filter=off #normal curse filter -FilterAll=on #strict curse filter -LogChat=off #chat logging is currently not supported -LogFile=CHATLOG.TXT -HearWhisper=on -Interaction=on -``` + **--version ** Overrides the version set in the config file or hard-coded into the client. Convenient for connecting to different servers that might require different version numbers. -Changes From Original Client -------------------------------------- + **--clonecompat** Enables Main Clone compatibility mode. This allows using Main Clone GFX files that are packaged with the v0.0.29 that Sausage and friends put together. Specifically, it uses a BitmapV3InfoHeader and culture code 1033 when loading GFX. #### Version Numbers -To assist with debugging, I added a version number to the config file so it isn't limited to the hard-coded value that I upload here and can be changed more easily. This provides an easy debugging method for multiple servers that may have custom clients already with a hex-edited version number. +For easily switching servers, there's a version number config setting so it isn't limited to the hard-coded value build into the client by default. #### Map Transitions @@ -164,26 +140,15 @@ Part of the sound processing involves reading the audio data and rewriting the l #### Rendering Hair -*"This is horrible" - Falco, Star Fox 64* - -*I'm not even sure how accurate this section is anymore. Hair rendering will (hopefully) be fixed up to work well with the new code base.* - -There are very subtle changes I've made to handling how hair is rendered for this client. Unlike the other features of the game, I've taken it upon myself to update the file format (GASP) for the item files to better assist with hair rendering in the client. I believe the original client had some hard-coded values for certain items that should render a certain way. - -EndlessClient uses a special method of rendering hair to ensure that face masks are rendered one way, hoods/helmets are rendered a second way, and hats that should clip hair are rendered a third way. In order to ensure that your pub file is up-to-date and can render this as designed, run BatchPub to use a batch-processing method of assigning the updated values to the selected items. Otherwise, the default pubs will have some weird graphics showing up when hats are equipped. - -NOTE: this is only for connecting to servers where you a) already have any of the relevant items and b) you want it to render properly. The pub files that are modified with this tool should be placed in the server's pub directory. If a difference in PUB files is detected client-side, it will request new files from the server and overwrite your local changes. +A [configuration file](EndlessClient/ContentPipeline/HairClipTypes.ini) is included with that controls how hat items are rendered. This file is based on the EO main hat items. For example: -Open up BatchPub. - -In step two, configure as follows: Set the field to SubType, and the value to FaceMask (for masks) or HideHair (for helmets/hoods) - -In step three, configure as follows: Check the checkbox, set the field to Name, set comparison to regex, and set the value to one of the following: - - For helmets: `^[A-Za-z ]*[Hh]elm[A-Za-z ]*$` - - For hoods: `^[A-Za-z ]*[Hh]ood[A-Za-z ]*$` -Pirate hat (ID 314 in standard pubs) also needs to be updated to HideHair. Change search to ==, change the field to ID, and change the value to 314. +```ini +186 = Facemask # Bandana +187 = Standard # Mystic hat +188 = HideHair # Hood +``` -For FaceMask updates, the following regex will update the correct items: `^((Frog Head)|([A-Za-z ]*[Mm]ask[A-Za-z ]*))$` +Item ID 186 will render as a facemask (below hair), 187 will render over hair, and 188 will hide hair entirely. Included Utility Projects ------------- @@ -192,7 +157,7 @@ There are a few other projects included with the EndlessClient solution that are #### Core -The core projects are EndlessClient, EOLib, and EOLib.Graphics. They are the only required projects in order for the game to run. +The core projects are EndlessClient and the EOLib projects under the "Lib" solution directory. They are the only required projects in order for the game to run. #### Test @@ -200,7 +165,7 @@ Any projects with a ".Test" suffix in the name contain unit tests. These will be #### BatchMap -BatchMap is designed to do batch processing and error correction on the original EMF files. When running EOSERV, a number of warning messages during map loading popped up. I created BatchMap to process map files and correct these errors so that the output of EOSERV was much less verbose when starting up. +BatchMap is designed to do batch processing and error correction on the original EMF files. When running EOSERV with the default map files, a number of warning messages during map loading will pop up. BatchMap processes files and corrects these errors so that the output of EOSERV is much less verbose when starting up. BatchMap corrects for a number of errors, including: - Tiles out of map bounds @@ -211,20 +176,20 @@ BatchMap corrects for a number of errors, including: - Chest spawn using non-existent item - Chest spawn pointing to non-chest +BatchMap can easily be modified to take care of other batch processing tasks, such as dumping out values in map files for debugging or comparison. + #### BatchPub -BatchPub is designed to do batch processing of items within the EIF file. The goal behind this was to change all items matching a certain criteria to have the same updated property (for instance, when rendering hair, see above). +BatchPub is designed to do batch processing of items within the EIF file. It can be used to bulk change properties in the pubs based on certain criteria. #### EOBot -EOBot launches a number of "bot" connections to a server that a) create accounts if they don't exist, b) login, c) create characters if they don't exist, and d) get the characters in game. +EOBot has recently been updated with an interpreter to make scripting of bots possible. The scripting language is the unholy offspring of javascript and php (really just inspired by the syntax of those languages). Run `EOBot --help` without any arguments to see more information on the command-line parameters it expects. -Once the characters are in-game further code can be added to make them do whatever. Currently, they will send a party request to 'testuser' (if testuser is logged in) which was being used to test functionality of large parties. +The default behavior of EOBot when not running in script mode is as a TrainerBot. See `TrainerBot.cs` for more details on the implementation. -In the future I would like to be able to have a script processing system in place that allows an interpreter to control the bots that are being run. Anywhere from 1-25 bots can be launched. +EOBot is used by https://www.github.com/ethanmoffat/etheos to execute integration tests against server instances. #### PacketDecoder -PacketDecoder is built for analysing raw WireShark packet data. It provides a way to decode the raw data and convert the byte stream into values used in EO. - -The idea is to be able to copy/paste an init packet (to determine the encrypt/decrypt multiples) and then copy/paste the packet data that needs to be decoded for analysis. +PacketDecoder analyzes raw WireShark packet data. It provides a way to decode the raw data and convert the byte stream into values used in EO. diff --git a/contributing.md b/contributing.md index 8cf169706..f9b31db66 100644 --- a/contributing.md +++ b/contributing.md @@ -10,7 +10,7 @@ Here are the style requirements for this project. This is the bare minimum you m - Use spaces for indentation tabs - Use 4 spaces to represent one tab -- Use var instead of explicit types +- Use var instead of explicit types (except for where required by the compiler) - Use the latest available C# syntax - Example: `public int Property => 5;` instead of `public int Property { get { return 5; } }` - Use formatting from Visual Studio/ReSharper by default @@ -18,7 +18,7 @@ Here are the style requirements for this project. This is the bare minimum you m - Example: `if (condition)`, `for (int i = 0...)` - Do not: `if(condition)` - Curly braces on the next line - - Curly braces may be ommitted from trivial lines + - Curly braces may be ommitted from trivial lines, but should be left in for readability - Example: ```c# for (int i = 0; i < 5; ++i) @@ -28,6 +28,17 @@ Here are the style requirements for this project. This is the bare minimum you m - Maintain appropriate whitespace - Group statements together for logical cohesion - Put empty lines around functions, properties, etc. +- Avoid use of explicit `this` or `base` keywords + +### Naming + +Try to follow standard C# namining conventions + +- Name interfaces with an `I` prefix (.Net convention) +- Make private/protected fields `readonly` when possible +- Public access to fields should always be through properties +- Fields should be named with an `_` prefix and then `camelCase` +- Public members (methods/properties/types) should be `PascalCase` ### Architecture @@ -38,14 +49,15 @@ Here are a few notes on the architecture of the project - Follow the repository/provider pattern for storing/getting data - Collections should be IReadOnly(List|Dictionary|...) if the caller doesn't need write access - Types should be immutable -- Events should be avoided (see EOLib.Notifiers) - - This requirement may change in the near future +- Events should be avoided (see EOLib.Notifiers), except for in UI-related code (XNAControls/dialogs specifically) + - This requirement may change in the future - Separate the domain from the client code - Do not add project references where they don't need to be - Example: EOLib should not depend on MonoGame for **any** reason - If you must, use `async`/`await` where it makes sense instead of `System.Threading.Thread` - Try to avoid multiple threads +- Avoid static classes in favor of instances that can be used via the dependency injection system ### Unit tests -The goal is to eventually have 100% test coverage. Testing isn't a huge priority right now, but keeping the code testable *is*. This is the reason for adding interfaces for everything and relying heavily on dependency injection. \ No newline at end of file +While good test coverage is an eventual goal, testing isn't a huge priority right now. However, keeping the code testable *is*; this is the reason for adding interfaces for everything and relying heavily on dependency injection.