refactor: added server project
This commit is contained in:
parent
b835fb1582
commit
2294c06bf9
17
.vscode/launch.json
vendored
17
.vscode/launch.json
vendored
@ -28,8 +28,19 @@
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Platforms/Server/bin/Debug/net9.0/Server.exe",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"stopAtEntry": false,
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": ".NET Launch (Host)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/Platforms/Desktop/bin/Debug/net9.0/Desktop.exe",
|
||||
"args": ["-server"],
|
||||
"args": ["--server"],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"stopAtEntry": false,
|
||||
"console": "internalConsole"
|
||||
@ -37,8 +48,8 @@
|
||||
],
|
||||
"compounds": [
|
||||
{
|
||||
"name": ".NET Launch 1 Client & 1 Server",
|
||||
"configurations": [".NET Launch (Server)", ".NET Launch (Client) 1"]
|
||||
"name": ".NET Launch Client & Host",
|
||||
"configurations": [".NET Launch (Host)", ".NET Launch (Client) 1"]
|
||||
},
|
||||
{
|
||||
"name": ".NET Launch 2 Client & 1 Server",
|
||||
|
2
Engine
2
Engine
@ -1 +1 @@
|
||||
Subproject commit fbdea47dc7768aea65fe6826020cc6dd79a0b711
|
||||
Subproject commit 45524e474e1f795012d5e04f0b7f709eff2026b5
|
@ -1,16 +1,22 @@
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
using Syntriax.Engine.Integration.MonoGame;
|
||||
|
||||
using var game = new Pong.GamePong();
|
||||
bool isServerEnabled = Environment.GetCommandLineArgs().FirstOrDefault(x => x.CompareTo("--server") == 0) is not null;
|
||||
|
||||
game.Universe
|
||||
.InstantiateUniverseObject().SetUniverseObject("Desktop HO")
|
||||
IUniverse universe = Pong.PongUniverse.GetPongUniverse(isServerEnabled, isClientEnabled: true);
|
||||
|
||||
universe.InstantiateUniverseObject().SetUniverseObject("Desktop HO")
|
||||
.BehaviourController.AddBehaviour<KeyboardInputsBehaviour>();
|
||||
|
||||
game.Graphics.PreferredBackBufferWidth = 1024;
|
||||
game.Graphics.PreferredBackBufferHeight = 576;
|
||||
game.Graphics.GraphicsProfile = GraphicsProfile.HiDef;
|
||||
using MonoGameWindow monoGameWindow = new(universe);
|
||||
|
||||
game.Run();
|
||||
monoGameWindow.Graphics.PreferredBackBufferWidth = 1024;
|
||||
monoGameWindow.Graphics.PreferredBackBufferHeight = 576;
|
||||
monoGameWindow.Graphics.GraphicsProfile = GraphicsProfile.HiDef;
|
||||
|
||||
monoGameWindow.Run();
|
||||
|
22
Platforms/Server/Program.cs
Normal file
22
Platforms/Server/Program.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
IUniverse universe = Pong.PongUniverse.GetPongUniverse(isServerEnabled: true, isClientEnabled: false);
|
||||
|
||||
DateTime lastRun = DateTime.UtcNow;
|
||||
TimeSpan interval = new(0, 0, 0, 0, 16);
|
||||
TimeSpan timeSinceStart = new(0);
|
||||
|
||||
universe.Initialize();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (lastRun + interval <= DateTime.UtcNow)
|
||||
{
|
||||
lastRun += interval;
|
||||
timeSinceStart += interval;
|
||||
universe.Update(new(timeSinceStart, interval));
|
||||
}
|
||||
Thread.Sleep(1);
|
||||
}
|
20
Platforms/Server/Server.csproj
Normal file
20
Platforms/Server/Server.csproj
Normal file
@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../Shared/Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.2.1105">
|
||||
<PrivateAssets>All</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
15
Pong.sln
15
Pong.sln
@ -23,6 +23,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Engine.Integration", "Engin
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Integration.MonoGame", "Engine\Engine.Integration\Engine.Integration.MonoGame\Engine.Integration.MonoGame.csproj", "{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Platforms\Server\Server.csproj", "{A15263DB-DF65-4A07-8CA1-33A2919501A0}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -117,6 +119,18 @@ Global
|
||||
{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Release|x64.Build.0 = Release|Any CPU
|
||||
{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Release|x86.Build.0 = Release|Any CPU
|
||||
{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Release|x64.Build.0 = Release|Any CPU
|
||||
{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -129,5 +143,6 @@ Global
|
||||
{8863A1BA-2E83-419F-BACB-D4A4156EC71C} = {F7F62670-237A-4C93-A30E-CE661C6FC401}
|
||||
{9059393F-4073-9273-0EEC-2B1BA61B620B} = {F7F62670-237A-4C93-A30E-CE661C6FC401}
|
||||
{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283} = {9059393F-4073-9273-0EEC-2B1BA61B620B}
|
||||
{A15263DB-DF65-4A07-8CA1-33A2919501A0} = {FECFFD54-338F-4060-9161-1E5770D1DC33}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
@ -22,7 +22,7 @@ public class PaddleBehaviour(Keys Up, Keys Down, float High, float Low, float Sp
|
||||
private bool isUpPressed = false;
|
||||
private bool isDownPressed = false;
|
||||
|
||||
private IButtonInputs<Keys> inputs = null!;
|
||||
private IButtonInputs<Keys>? inputs = null;
|
||||
private INetworkCommunicatorClient? networkClient = null!;
|
||||
private INetworkCommunicatorServer? networkServer = null;
|
||||
private IRigidBody2D rigidBody = null!;
|
||||
@ -44,25 +44,25 @@ public class PaddleBehaviour(Keys Up, Keys Down, float High, float Low, float Sp
|
||||
public void FirstActiveFrame()
|
||||
{
|
||||
physicsEngine2D = Universe.FindRequiredBehaviour<IPhysicsEngine2D>();
|
||||
inputs = Universe.FindRequiredBehaviour<IButtonInputs<Keys>>();
|
||||
inputs = Universe.FindBehaviour<IButtonInputs<Keys>>();
|
||||
networkClient = Universe.FindBehaviour<INetworkCommunicatorClient>();
|
||||
networkServer = Universe.FindBehaviour<INetworkCommunicatorServer>();
|
||||
rigidBody = BehaviourController.GetRequiredBehaviour<IRigidBody2D>();
|
||||
|
||||
inputs.RegisterOnPress(Up, OnUpPressed);
|
||||
inputs.RegisterOnRelease(Up, OnUpReleased);
|
||||
inputs?.RegisterOnPress(Up, OnUpPressed);
|
||||
inputs?.RegisterOnRelease(Up, OnUpReleased);
|
||||
|
||||
inputs.RegisterOnPress(Down, OnDownPressed);
|
||||
inputs.RegisterOnRelease(Down, OnDownReleased);
|
||||
inputs?.RegisterOnPress(Down, OnDownPressed);
|
||||
inputs?.RegisterOnRelease(Down, OnDownReleased);
|
||||
}
|
||||
|
||||
protected override void OnFinalize()
|
||||
{
|
||||
inputs.UnregisterOnPress(Up, OnUpPressed);
|
||||
inputs.UnregisterOnRelease(Up, OnUpReleased);
|
||||
inputs?.UnregisterOnPress(Up, OnUpPressed);
|
||||
inputs?.UnregisterOnRelease(Up, OnUpReleased);
|
||||
|
||||
inputs.UnregisterOnPress(Down, OnDownPressed);
|
||||
inputs.UnregisterOnRelease(Down, OnDownReleased);
|
||||
inputs?.UnregisterOnPress(Down, OnDownPressed);
|
||||
inputs?.UnregisterOnRelease(Down, OnDownReleased);
|
||||
}
|
||||
|
||||
private void OnUpPressed(IButtonInputs<Keys> sender, IButtonInputs<Keys>.ButtonCallbackArguments args) { isUpPressed = true; networkClient?.SendToServer(new PaddleKeyStatePacket(this)); }
|
||||
|
@ -32,8 +32,8 @@ public class PongManagerBehaviour : Behaviour, INetworkEntity, IFirstFrameUpdate
|
||||
|
||||
public void FirstActiveFrame()
|
||||
{
|
||||
IButtonInputs<Keys> buttonInputs = Universe.FindRequired<IButtonInputs<Keys>>();
|
||||
buttonInputs.RegisterOnRelease(Keys.Space, (_, _1) => networkClient?.SendToServer(new RequestStartPacket()));
|
||||
IButtonInputs<Keys>? buttonInputs = Universe.FindBehaviour<IButtonInputs<Keys>>();
|
||||
buttonInputs?.RegisterOnRelease(Keys.Space, (_, _1) => networkClient?.SendToServer(new RequestStartPacket()));
|
||||
|
||||
ball = Universe.FindRequiredBehaviour<BallBehaviour>();
|
||||
networkClient = Universe.FindBehaviour<INetworkCommunicatorClient>();
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
@ -14,59 +13,60 @@ using Syntriax.Engine.Systems.Tween;
|
||||
|
||||
namespace Pong;
|
||||
|
||||
public class GamePong : MonoGameWindow
|
||||
public static class PongUniverse
|
||||
{
|
||||
protected override void Initialize()
|
||||
public static IUniverse GetPongUniverse(bool isServerEnabled, bool isClientEnabled)
|
||||
{
|
||||
base.Initialize();
|
||||
Universe universe = new();
|
||||
|
||||
if (Environment.GetCommandLineArgs().FirstOrDefault(x => x.CompareTo("-server") == 0) is not null)
|
||||
if (isServerEnabled)
|
||||
{
|
||||
LiteNetLibServer server = Universe.InstantiateUniverseObject().SetUniverseObject("Server").BehaviourController.AddBehaviour<LiteNetLibServer>();
|
||||
LiteNetLibServer server = universe.InstantiateUniverseObject().SetUniverseObject("Server").BehaviourController.AddBehaviour<LiteNetLibServer>();
|
||||
server.BehaviourController.AddBehaviour<NetworkManager>();
|
||||
server.Start(8888, 2);
|
||||
Window.Title = $"Server";
|
||||
}
|
||||
else
|
||||
|
||||
if (isClientEnabled)
|
||||
{
|
||||
LiteNetLibClient client = Universe.InstantiateUniverseObject().SetUniverseObject("Client").BehaviourController.AddBehaviour<LiteNetLibClient>();
|
||||
LiteNetLibClient client = universe.InstantiateUniverseObject().SetUniverseObject("Client").BehaviourController.AddBehaviour<LiteNetLibClient>();
|
||||
client.BehaviourController.AddBehaviour<NetworkManager>();
|
||||
client.Connect("localhost", 8888);
|
||||
Window.Title = $"Client";
|
||||
|
||||
DrawManager drawManager = Universe.InstantiateUniverseObject().SetUniverseObject("Draw Manager").BehaviourController.AddBehaviour<DrawManager>();
|
||||
Universe.InstantiateUniverseObject().SetUniverseObject("Shape Batcher", drawManager.UniverseObject).BehaviourController.AddBehaviour<ShapeBatcher>();
|
||||
Universe.InstantiateUniverseObject().SetUniverseObject("Sprite Batcher", drawManager.UniverseObject).BehaviourController.AddBehaviour<SpriteBatcher>();
|
||||
|
||||
Universe.InstantiateUniverseObject().SetUniverseObject("Score Left")
|
||||
.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(-250f, 250f), scale: Vector2D.One * .25f)
|
||||
.BehaviourController.AddBehaviour<TextScoreBehaviour>(true);
|
||||
|
||||
Universe.InstantiateUniverseObject().SetUniverseObject("Score Right")
|
||||
.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(250f, 250f), scale: Vector2D.One * .25f)
|
||||
.BehaviourController.AddBehaviour<TextScoreBehaviour>(false);
|
||||
}
|
||||
|
||||
Universe.InstantiateUniverseObject().SetUniverseObject("Update Manager").BehaviourController.AddBehaviour<UpdateManager>();
|
||||
Universe.InstantiateUniverseObject().SetUniverseObject("Coroutine Manager").BehaviourController.AddBehaviour<CoroutineManager>();
|
||||
Universe.InstantiateUniverseObject().SetUniverseObject("Tween Manager").BehaviourController.AddBehaviour<TweenManager>();
|
||||
Universe.InstantiateUniverseObject().SetUniverseObject("Physics Engine 2D").BehaviourController.AddBehaviour<PhysicsEngine2D>();
|
||||
DrawManager drawManager = universe.InstantiateUniverseObject().SetUniverseObject("Draw Manager").BehaviourController.AddBehaviour<DrawManager>();
|
||||
universe.InstantiateUniverseObject().SetUniverseObject("Shape Batcher", drawManager.UniverseObject).BehaviourController.AddBehaviour<ShapeBatcher>();
|
||||
universe.InstantiateUniverseObject().SetUniverseObject("Sprite Batcher", drawManager.UniverseObject).BehaviourController.AddBehaviour<SpriteBatcher>();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Universe.InstantiateUniverseObject().SetUniverseObject("Camera")
|
||||
universe.InstantiateUniverseObject().SetUniverseObject("Camera")
|
||||
.BehaviourController.AddBehaviour<Transform2D>()
|
||||
.BehaviourController.AddBehaviour<CameraController>()
|
||||
.BehaviourController.AddBehaviour<MonoGameCamera2DBehaviour>();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PongManagerBehaviour pongManager = Universe.InstantiateUniverseObject().SetUniverseObject("Pong Game Manager")
|
||||
universe.InstantiateUniverseObject().SetUniverseObject("Score Left")
|
||||
.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(-250f, 250f), scale: Vector2D.One * .25f)
|
||||
.BehaviourController.AddBehaviour<TextScoreBehaviour>(true);
|
||||
|
||||
universe.InstantiateUniverseObject().SetUniverseObject("Score Right")
|
||||
.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(250f, 250f), scale: Vector2D.One * .25f)
|
||||
.BehaviourController.AddBehaviour<TextScoreBehaviour>(false);
|
||||
}
|
||||
|
||||
universe.InstantiateUniverseObject().SetUniverseObject("Update Manager").BehaviourController.AddBehaviour<UpdateManager>();
|
||||
universe.InstantiateUniverseObject().SetUniverseObject("Coroutine Manager").BehaviourController.AddBehaviour<CoroutineManager>();
|
||||
universe.InstantiateUniverseObject().SetUniverseObject("Tween Manager").BehaviourController.AddBehaviour<TweenManager>();
|
||||
universe.InstantiateUniverseObject().SetUniverseObject("Physics Engine 2D").BehaviourController.AddBehaviour<PhysicsEngine2D>();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PongManagerBehaviour pongManager = universe.InstantiateUniverseObject().SetUniverseObject("Pong Game Manager")
|
||||
.BehaviourController.AddBehaviour<PongManagerBehaviour>(5);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Universe.InstantiateUniverseObject().SetUniverseObject("Ball")
|
||||
universe.InstantiateUniverseObject().SetUniverseObject("Ball")
|
||||
.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(0, 0f), scale: new Vector2D(10f, 10f))
|
||||
.BehaviourController.AddBehaviour<CircleBehaviour>(new Circle(Vector2D.Zero, 1f))
|
||||
.BehaviourController.AddBehaviour<BallBehaviour>()
|
||||
@ -81,7 +81,7 @@ public class GamePong : MonoGameWindow
|
||||
PaddleBehaviour leftPaddleBehaviour = BehaviourFactory.Instantiate<PaddleBehaviour>(Keys.W, Keys.S, 228f, -228f, 400f);
|
||||
leftPaddleBehaviour.Id = "lp";
|
||||
leftPaddle.BehaviourController.AddBehaviour(leftPaddleBehaviour);
|
||||
Universe.Register(leftPaddle);
|
||||
universe.Register(leftPaddle);
|
||||
|
||||
IUniverseObject rightPaddle = UniverseObjectFactory.Instantiate().SetUniverseObject("Right Paddle");
|
||||
rightPaddle.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(468f, 0f), scale: new Vector2D(15f, 60f))
|
||||
@ -90,30 +90,32 @@ public class GamePong : MonoGameWindow
|
||||
PaddleBehaviour rightPaddleBehaviour = BehaviourFactory.Instantiate<PaddleBehaviour>(Keys.Up, Keys.Down, 228f, -228f, 400f);
|
||||
rightPaddleBehaviour.Id = "rp";
|
||||
rightPaddle.BehaviourController.AddBehaviour(rightPaddleBehaviour);
|
||||
Universe.Register(rightPaddle);
|
||||
universe.Register(rightPaddle);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Universe.InstantiateUniverseObject().SetUniverseObject("Wall Top")
|
||||
universe.InstantiateUniverseObject().SetUniverseObject("Wall Top")
|
||||
.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(0f, 308f), scale: new Vector2D(552f, 20f))
|
||||
.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape2D.Square)
|
||||
.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
|
||||
|
||||
Universe.InstantiateUniverseObject().SetUniverseObject("Wall Bottom")
|
||||
universe.InstantiateUniverseObject().SetUniverseObject("Wall Bottom")
|
||||
.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(0f, -308f), scale: new Vector2D(552f, 20f))
|
||||
.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape2D.Square)
|
||||
.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
|
||||
|
||||
Universe.InstantiateUniverseObject().SetUniverseObject("Wall Right")
|
||||
universe.InstantiateUniverseObject().SetUniverseObject("Wall Right")
|
||||
.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(532f, 0f), scale: new Vector2D(20f, 328f))
|
||||
.BehaviourController.AddBehaviour<WallScoreBehaviour>((Action)pongManager.ScoreToLeft)
|
||||
.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape2D.Square)
|
||||
.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
|
||||
|
||||
Universe.InstantiateUniverseObject().SetUniverseObject("Wall Left")
|
||||
universe.InstantiateUniverseObject().SetUniverseObject("Wall Left")
|
||||
.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(-532f, 0f), scale: new Vector2D(20f, 328f))
|
||||
.BehaviourController.AddBehaviour<WallScoreBehaviour>((Action)pongManager.ScoreToRight)
|
||||
.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape2D.Square)
|
||||
.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
|
||||
|
||||
return universe;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user