mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-01 22:26:27 -05:00
Change scene names to enums. Started adding GPL headers and comments.
This commit is contained in:
parent
9f078a8ace
commit
a624fcaa66
@ -1,18 +1,41 @@
|
||||
using System;
|
||||
/* OpenDiablo 2 - An open source re-implementation of Diablo 2 in C#
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using OpenDiablo2.Common.Enums;
|
||||
|
||||
namespace OpenDiablo2.Common.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the class as a Message Frame. This is used by the client/server logic
|
||||
/// to decide how to serialize and deserialize networking objects.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
|
||||
public sealed class MessageFrameAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of message frame this class represents.
|
||||
/// </summary>
|
||||
public eMessageFrameType FrameType { get; private set; }
|
||||
|
||||
// This is a positional argument
|
||||
public MessageFrameAttribute(eMessageFrameType frameType)
|
||||
{
|
||||
this.FrameType = frameType;
|
||||
}
|
||||
/// <summary>
|
||||
/// Define this class as a message frame.
|
||||
/// </summary>
|
||||
/// <param name="frameType">The type of message frame this class represents.</param>
|
||||
public MessageFrameAttribute(eMessageFrameType frameType) => this.FrameType = frameType;
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,15 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
/* OpenDiablo 2 - An open source re-implementation of Diablo 2 in C#
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using OpenDiablo2.Common.Enums;
|
||||
|
||||
namespace OpenDiablo2.Common.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines this class as a scene.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
|
||||
public sealed class SceneAttribute : Attribute
|
||||
{
|
||||
public SceneAttribute(string sceneName) => SceneName = sceneName;
|
||||
public string SceneName { get; }
|
||||
/// <summary>
|
||||
/// Defines the type of scene that this class represents.
|
||||
/// </summary>
|
||||
public eSceneType SceneType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines this class as a scene type
|
||||
/// </summary>
|
||||
/// <param name="sceneType"></param>
|
||||
public SceneAttribute(eSceneType sceneType) => SceneType = sceneType;
|
||||
}
|
||||
}
|
||||
|
29
OpenDiablo2.Common/Enums/eSceneType.cs
Normal file
29
OpenDiablo2.Common/Enums/eSceneType.cs
Normal file
@ -0,0 +1,29 @@
|
||||
/* OpenDiablo 2 - An open source re-implementation of Diablo 2 in C#
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OpenDiablo2.Common.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a scene type.
|
||||
/// </summary>
|
||||
public enum eSceneType
|
||||
{
|
||||
MainMenu,
|
||||
SelectHeroClass,
|
||||
SelectCharacter,
|
||||
Game
|
||||
}
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
namespace OpenDiablo2.Common.Interfaces
|
||||
using OpenDiablo2.Common.Enums;
|
||||
|
||||
namespace OpenDiablo2.Common.Interfaces
|
||||
{
|
||||
public interface ISceneManager
|
||||
{
|
||||
void ChangeScene(string sceneName);
|
||||
void ChangeScene(eSceneType sceneType);
|
||||
}
|
||||
}
|
||||
|
@ -71,6 +71,7 @@
|
||||
<Compile Include="Enums\eLevelSubType.cs" />
|
||||
<Compile Include="Enums\eMPQFormatVersion.cs" />
|
||||
<Compile Include="Enums\eRenderCellType.cs" />
|
||||
<Compile Include="Enums\eSceneType.cs" />
|
||||
<Compile Include="Enums\eSessionType.cs" />
|
||||
<Compile Include="Enums\eTextAlign.cs" />
|
||||
<Compile Include="Enums\eWeaponClass.cs" />
|
||||
|
@ -4,6 +4,7 @@ using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using OpenDiablo2.Common;
|
||||
using OpenDiablo2.Common.Enums;
|
||||
using OpenDiablo2.Common.Interfaces;
|
||||
using OpenDiablo2.Common.Models;
|
||||
|
||||
@ -16,7 +17,7 @@ namespace OpenDiablo2.Core
|
||||
private readonly GlobalConfiguration globalConfig;
|
||||
private readonly IMPQProvider mpqProvider;
|
||||
private readonly Func<IRenderWindow> getRenderWindow;
|
||||
private readonly Func<string, IScene> getScene;
|
||||
private readonly Func<eSceneType, IScene> getScene;
|
||||
private readonly Func<IResourceManager> getResourceManager;
|
||||
private readonly Func<IGameState> getGameState;
|
||||
|
||||
@ -33,7 +34,7 @@ namespace OpenDiablo2.Core
|
||||
GlobalConfiguration globalConfig,
|
||||
IMPQProvider mpqProvider,
|
||||
Func<IRenderWindow> getRenderWindow,
|
||||
Func<string, IScene> getScene,
|
||||
Func<eSceneType, IScene> getScene,
|
||||
Func<IResourceManager> getResourceManager,
|
||||
Func<IGameState> getGameState
|
||||
)
|
||||
@ -84,7 +85,7 @@ namespace OpenDiablo2.Core
|
||||
var cursor = renderWindow.LoadCursor(mouseSprite, 0, new Point(0, 3));
|
||||
renderWindow.MouseCursor = cursor;
|
||||
|
||||
currentScene = getScene("Main Menu");
|
||||
currentScene = getScene(eSceneType.MainMenu);
|
||||
var lastTicks = renderWindow.GetTicks();
|
||||
while (getRenderWindow().IsRunning)
|
||||
{
|
||||
@ -135,7 +136,7 @@ namespace OpenDiablo2.Core
|
||||
currentScene?.Dispose();
|
||||
}
|
||||
|
||||
public void ChangeScene(string sceneName)
|
||||
=> nextScene = getScene(sceneName);
|
||||
public void ChangeScene(eSceneType sceneType)
|
||||
=> nextScene = getScene(sceneType);
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ namespace OpenDiablo2.Core.GameState_
|
||||
sessionManager.OnFocusOnPlayer += OnFocusOnPlayer;
|
||||
|
||||
mapInfo = new List<MapInfo>();
|
||||
sceneManager.ChangeScene("Game");
|
||||
sceneManager.ChangeScene(eSceneType.Game);
|
||||
|
||||
sessionManager.JoinGame(characterName, hero);
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ namespace OpenDiablo2.Scenes
|
||||
var att = type.GetCustomAttributes(true).First(x => typeof(SceneAttribute).IsAssignableFrom(x.GetType())) as SceneAttribute;
|
||||
builder
|
||||
.RegisterType(type)
|
||||
.Keyed<IScene>(att.SceneName)
|
||||
.Keyed<IScene>(att.SceneType)
|
||||
.SingleInstance();
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ using OpenDiablo2.Common.Interfaces;
|
||||
|
||||
namespace OpenDiablo2.Scenes
|
||||
{
|
||||
[Scene("Select Character")]
|
||||
[Scene(eSceneType.SelectCharacter)]
|
||||
public sealed class CharacterSelection : IScene
|
||||
{
|
||||
static readonly log4net.ILog log =
|
||||
@ -28,7 +28,7 @@ namespace OpenDiablo2.Scenes
|
||||
// TODO: use strCreateNewCharacter -- need to get the text to split after 10 chars though.
|
||||
createNewCharacterButton.Text = textDictionary.Translate("strCreateNewCharacter");// "Create New".ToUpper();
|
||||
createNewCharacterButton.Location = new Point(33, 467);
|
||||
createNewCharacterButton.OnActivate = () => sceneManager.ChangeScene("Select Hero Class");
|
||||
createNewCharacterButton.OnActivate = () => sceneManager.ChangeScene(eSceneType.SelectHeroClass);
|
||||
|
||||
deleteCharacterButton = createButton(eButtonType.Tall);
|
||||
deleteCharacterButton.Text = textDictionary.Translate("strDelete");
|
||||
@ -37,7 +37,7 @@ namespace OpenDiablo2.Scenes
|
||||
exitButton = createButton(eButtonType.Medium);
|
||||
exitButton.Text = textDictionary.Translate("strExit");
|
||||
exitButton.Location = new Point(33, 540);
|
||||
exitButton.OnActivate = () => sceneManager.ChangeScene("Main Menu");
|
||||
exitButton.OnActivate = () => sceneManager.ChangeScene(eSceneType.MainMenu);
|
||||
|
||||
okButton = createButton(eButtonType.Medium);
|
||||
okButton.Text = textDictionary.Translate("strOk");
|
||||
|
@ -7,7 +7,7 @@ using OpenDiablo2.Common.Interfaces;
|
||||
|
||||
namespace OpenDiablo2.Scenes
|
||||
{
|
||||
[Scene("Game")]
|
||||
[Scene(eSceneType.Game)]
|
||||
public sealed class Game : IScene
|
||||
{
|
||||
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
@ -1,19 +1,14 @@
|
||||
using OpenDiablo2.Common;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenDiablo2.Common;
|
||||
using OpenDiablo2.Common.Attributes;
|
||||
using OpenDiablo2.Common.Enums;
|
||||
using OpenDiablo2.Common.Interfaces;
|
||||
using OpenDiablo2.Common.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenDiablo2.Scenes
|
||||
{
|
||||
[Scene("Main Menu")]
|
||||
[Scene(eSceneType.MainMenu)]
|
||||
public class MainMenu : IScene
|
||||
{
|
||||
static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
@ -40,7 +35,7 @@ namespace OpenDiablo2.Scenes
|
||||
ISceneManager sceneManager,
|
||||
IResourceManager resourceManager,
|
||||
Func<eButtonType, IButton> createButton,
|
||||
Func<string, IScene> getScene // Temporary until SDL load functions are sped up
|
||||
Func<eSceneType, IScene> getScene // Temporary until SDL load functions are sped up
|
||||
)
|
||||
{
|
||||
this.renderWindow = renderWindow;
|
||||
@ -80,7 +75,7 @@ namespace OpenDiablo2.Scenes
|
||||
var loadingSprite = renderWindow.LoadSprite(ResourcePaths.LoadingScreen, Palettes.Loading, new Point(300, 400));
|
||||
|
||||
// Pre-load all the scenes for now until we fix the sdl load problem
|
||||
var scenesToLoad = new string[] {"Select Hero Class" };
|
||||
var scenesToLoad = new eSceneType[] { eSceneType.SelectHeroClass };
|
||||
for (int i = 0; i < scenesToLoad.Count(); i++)
|
||||
{
|
||||
renderWindow.Clear();
|
||||
@ -152,7 +147,7 @@ namespace OpenDiablo2.Scenes
|
||||
}
|
||||
|
||||
private void OnSinglePlayerClicked()
|
||||
=> sceneManager.ChangeScene("Select Hero Class");
|
||||
=> sceneManager.ChangeScene(eSceneType.SelectHeroClass);
|
||||
|
||||
private void OnExitClicked()
|
||||
{
|
||||
|
@ -28,7 +28,7 @@ namespace OpenDiablo2.Scenes
|
||||
public Rectangle SelectionBounds = new Rectangle();
|
||||
}
|
||||
|
||||
[Scene("Select Hero Class")]
|
||||
[Scene(eSceneType.SelectHeroClass)]
|
||||
public sealed class SelectHeroClass : IScene
|
||||
{
|
||||
static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
@ -244,7 +244,7 @@ namespace OpenDiablo2.Scenes
|
||||
okButton.Enabled = false;
|
||||
selectedHero = null;
|
||||
|
||||
sceneManager.ChangeScene("Select Character");
|
||||
sceneManager.ChangeScene(eSceneType.SelectCharacter);
|
||||
}
|
||||
|
||||
public void Render()
|
||||
|
@ -1,4 +1,20 @@
|
||||
using System;
|
||||
/* OpenDiablo 2 - An open source re-implementation of Diablo 2 in C#
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Autofac;
|
||||
using OpenDiablo2.Common.Attributes;
|
||||
|
@ -1,4 +1,20 @@
|
||||
using System;
|
||||
/* OpenDiablo 2 - An open source re-implementation of Diablo 2 in C#
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -1,5 +1,20 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
/* OpenDiablo 2 - An open source re-implementation of Diablo 2 in C#
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -1,18 +1,46 @@
|
||||
using CommandLine;
|
||||
/* OpenDiablo 2 - An open source re-implementation of Diablo 2 in C#
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using CommandLine;
|
||||
|
||||
namespace OpenDiablo2
|
||||
{
|
||||
public sealed class CommandLineOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// The root path of the data files
|
||||
/// </summary>
|
||||
[Option('p', "datapath", Required = false, HelpText = "Specifies the root data path")]
|
||||
public string DataPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When true, the hardware cursor is used instead of the software one.
|
||||
/// </summary>
|
||||
[Option("hwmouse", Default = false, Required = false, HelpText = "Use the hardware mouse instead of software")]
|
||||
public bool HardwareMouse { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When hardware cursor mode is enabled, this changes the scale of the HW cursor
|
||||
/// </summary>
|
||||
[Option("mousescale", Default = 1, Required = false, HelpText = "When hardware mouse is enabled, this defines the pixel scale of the mouse. No effect for software mode")]
|
||||
public int MouseScale { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When true, the game runs in full screen.
|
||||
/// </summary>
|
||||
[Option('f', "fullscreen", Default = false, Required = false, HelpText = "When set, the game will start in full screen mode")]
|
||||
public bool FullScreen { get; set; }
|
||||
}
|
||||
|
@ -1,4 +1,20 @@
|
||||
using System;
|
||||
/* OpenDiablo 2 - An open source re-implementation of Diablo 2 in C#
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@ -13,11 +29,18 @@ namespace OpenDiablo2
|
||||
static class Program
|
||||
{
|
||||
static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
// We store the global configuration here so we can bind it and return it to anything that needs it.
|
||||
private static GlobalConfiguration globalConfiguration;
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
log.Info("OpenDiablo 2: The Free and Open Source Diablo 2 clone!");
|
||||
log.Info("OpenDiablo 2: The Free and Open Source Diablo 2 clone!\n" +
|
||||
"This program comes with ABSOLUTELY NO WARRANTY.\n" +
|
||||
"This is free software, and you are welcome to redistribute it\n" +
|
||||
"under certain conditions; type `show c' for details.");
|
||||
|
||||
// Parse the command-line arguments.
|
||||
Parser.Default.ParseArguments<CommandLineOptions>(args).WithParsed(o => globalConfiguration = new GlobalConfiguration
|
||||
{
|
||||
BaseDataPath = Path.GetFullPath(o.DataPath ?? Directory.GetCurrentDirectory()),
|
||||
@ -34,16 +57,20 @@ namespace OpenDiablo2
|
||||
try
|
||||
{
|
||||
#endif
|
||||
// Create the AutoFac DI container
|
||||
var container = BuildContainer();
|
||||
try
|
||||
{
|
||||
// Resolve the game engine
|
||||
using (var gameEngine = container.Resolve<IGameEngine>())
|
||||
{
|
||||
// Start the game!
|
||||
gameEngine.Run();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Dispose the container, disposing any instantiated objects in the process
|
||||
container.Dispose();
|
||||
}
|
||||
|
||||
@ -67,10 +94,10 @@ namespace OpenDiablo2
|
||||
{
|
||||
containerBuilder.Register(x => globalConfiguration).AsSelf().SingleInstance();
|
||||
|
||||
containerBuilder.Register<Func<string, IScene>>(c =>
|
||||
containerBuilder.Register<Func<eSceneType, IScene>>(c =>
|
||||
{
|
||||
var componentContext = c.Resolve<IComponentContext>();
|
||||
return (sceneName) => componentContext.ResolveKeyed<IScene>(sceneName);
|
||||
return (sceneType) => componentContext.ResolveKeyed<IScene>(sceneType);
|
||||
});
|
||||
|
||||
containerBuilder.Register<Func<eButtonType, IButton>>(c =>
|
||||
|
Loading…
Reference in New Issue
Block a user