Compare commits
30 Commits
feat/liten
...
feat/netwo
Author | SHA1 | Date | |
---|---|---|---|
1b1d9dcdac | |||
2565617ff9 | |||
01668c7be3 | |||
cafbc55780 | |||
ea3c4a2d2a | |||
89b756a615 | |||
6af84bcb6d | |||
3c1528d879 | |||
6f3e7b4ae5 | |||
86ef57fb62 | |||
6c326b1fc6 | |||
b8b10de08a | |||
edd2dd8511 | |||
70ac012a83 | |||
d5a904fe8f | |||
b1582ab5c2 | |||
8a0a0289f9 | |||
776d029e7e | |||
5afb8b69bf | |||
65073ec1ca | |||
0d62e5c986 | |||
fe5a08840c | |||
1c7b1cb78a | |||
78010c266e | |||
ef8b04648c | |||
d4c57c0153 | |||
0e198afeab | |||
de267a9d0f | |||
977a2abdd7 | |||
91e88bbff8 |
23
.vscode/launch.json
vendored
23
.vscode/launch.json
vendored
@@ -5,33 +5,14 @@
|
|||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "Start Client",
|
"name": ".NET Core Launch (console)",
|
||||||
"type": "coreclr",
|
|
||||||
"request": "launch",
|
|
||||||
"preLaunchTask": "build",
|
|
||||||
// If you have changed target frameworks, make sure to update the program path.
|
|
||||||
"program": "${workspaceFolder}/Game/bin/Debug/net8.0/Game.dll",
|
|
||||||
"args": ["127.0.0.1"],
|
|
||||||
"cwd": "${workspaceFolder}",
|
|
||||||
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
|
||||||
"console": "internalConsole",
|
|
||||||
"stopAtEntry": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": ".NET Core Attach",
|
|
||||||
"type": "coreclr",
|
|
||||||
"request": "attach",
|
|
||||||
"processId": "${command:pickProcess}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Start Server",
|
|
||||||
"type": "coreclr",
|
"type": "coreclr",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"preLaunchTask": "build",
|
"preLaunchTask": "build",
|
||||||
// If you have changed target frameworks, make sure to update the program path.
|
// If you have changed target frameworks, make sure to update the program path.
|
||||||
"program": "${workspaceFolder}/Game/bin/Debug/net8.0/Game.dll",
|
"program": "${workspaceFolder}/Game/bin/Debug/net8.0/Game.dll",
|
||||||
"args": ["server"],
|
"args": ["server"],
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}/Game",
|
||||||
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
||||||
"console": "internalConsole",
|
"console": "internalConsole",
|
||||||
"stopAtEntry": false
|
"stopAtEntry": false
|
||||||
|
5
.vscode/tasks.json
vendored
5
.vscode/tasks.json
vendored
@@ -9,7 +9,10 @@
|
|||||||
"kind": "build",
|
"kind": "build",
|
||||||
"isDefault": true
|
"isDefault": true
|
||||||
},
|
},
|
||||||
"label": "build"
|
"label": "build",
|
||||||
|
"options": {
|
||||||
|
"cwd": "${workspaceFolder}/Game"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
2
Engine
2
Engine
Submodule Engine updated: ef21cdf213...2cf6135063
8
Game/Abstract/IContentLoader.cs
Normal file
8
Game/Abstract/IContentLoader.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using Microsoft.Xna.Framework.Content;
|
||||||
|
|
||||||
|
namespace Pong.Behaviours;
|
||||||
|
|
||||||
|
public interface IMonoGameContentLoader
|
||||||
|
{
|
||||||
|
void LoadContent(ContentManager content);
|
||||||
|
}
|
@@ -1,12 +1,19 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
|
using Microsoft.Xna.Framework.Audio;
|
||||||
|
using Microsoft.Xna.Framework.Content;
|
||||||
|
|
||||||
|
using LiteNetLib;
|
||||||
|
|
||||||
using Syntriax.Engine.Core;
|
using Syntriax.Engine.Core;
|
||||||
|
using Syntriax.Engine.Network;
|
||||||
|
using Syntriax.Engine.Network.Abstract;
|
||||||
using Syntriax.Engine.Physics2D;
|
using Syntriax.Engine.Physics2D;
|
||||||
using Syntriax.Engine.Physics2D.Abstract;
|
using Syntriax.Engine.Physics2D.Abstract;
|
||||||
|
|
||||||
namespace Pong.Behaviours;
|
namespace Pong.Behaviours;
|
||||||
|
|
||||||
public class BallBehaviour : BehaviourOverride
|
public class BallBehaviour : NetworkBehaviour, IMonoGameContentLoader
|
||||||
{
|
{
|
||||||
public Vector2D StartDirection { get; private set; } = Vector2D.Zero;
|
public Vector2D StartDirection { get; private set; } = Vector2D.Zero;
|
||||||
public float Speed { get; set; } = 500f;
|
public float Speed { get; set; } = 500f;
|
||||||
@@ -14,6 +21,13 @@ public class BallBehaviour : BehaviourOverride
|
|||||||
|
|
||||||
private readonly Random random = new();
|
private readonly Random random = new();
|
||||||
private IRigidBody2D rigidBody = null!;
|
private IRigidBody2D rigidBody = null!;
|
||||||
|
private INetworkCommunicator communicator = null!;
|
||||||
|
private SoundEffect soundEffect = null!;
|
||||||
|
|
||||||
|
public void LoadContent(ContentManager content)
|
||||||
|
{
|
||||||
|
soundEffect = content.Load<SoundEffect>("Hit");
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnFirstActiveFrame()
|
protected override void OnFirstActiveFrame()
|
||||||
{
|
{
|
||||||
@@ -21,11 +35,13 @@ public class BallBehaviour : BehaviourOverride
|
|||||||
throw new Exception($"{nameof(IRigidBody2D)} is missing on {GameObject.Name}.");
|
throw new Exception($"{nameof(IRigidBody2D)} is missing on {GameObject.Name}.");
|
||||||
if (!BehaviourController.TryGetBehaviour(out ICollider2D? foundCollider))
|
if (!BehaviourController.TryGetBehaviour(out ICollider2D? foundCollider))
|
||||||
throw new Exception($"{nameof(ICollider2D)} is missing on {GameObject.Name}.");
|
throw new Exception($"{nameof(ICollider2D)} is missing on {GameObject.Name}.");
|
||||||
|
if (!GameObject.GameManager.TryFindBehaviour(out INetworkCommunicator? foundCommunicator))
|
||||||
|
throw new Exception($"{nameof(INetworkCommunicator)} is missing on GameManager.");
|
||||||
|
|
||||||
foundCollider.OnCollisionDetected += OnCollisionDetected;
|
foundCollider.OnCollisionDetected += OnCollisionDetected;
|
||||||
|
|
||||||
rigidBody = foundRigidBody;
|
rigidBody = foundRigidBody;
|
||||||
|
communicator = foundCommunicator;
|
||||||
if (GameObject.GameManager.TryFindBehaviour(out PongManagerBehaviour? pongManager))
|
if (GameObject.GameManager.TryFindBehaviour(out PongManagerBehaviour? pongManager))
|
||||||
{
|
{
|
||||||
pongManager.OnReset += ResetBall;
|
pongManager.OnReset += ResetBall;
|
||||||
@@ -45,6 +61,8 @@ public class BallBehaviour : BehaviourOverride
|
|||||||
StateEnable.Enabled = true;
|
StateEnable.Enabled = true;
|
||||||
BehaviourController.GameObject.Transform.Position = Vector2D.Zero;
|
BehaviourController.GameObject.Transform.Position = Vector2D.Zero;
|
||||||
rigidBody.Velocity = GetRandomDirection() * Speed;
|
rigidBody.Velocity = GetRandomDirection() * Speed;
|
||||||
|
|
||||||
|
SendBallData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vector2D GetRandomDirection()
|
private Vector2D GetRandomDirection()
|
||||||
@@ -70,6 +88,27 @@ public class BallBehaviour : BehaviourOverride
|
|||||||
rigidBody.Velocity = information.Left.Transform.Position.FromTo(information.Right.Transform.Position).Normalized * rigidBody.Velocity.Magnitude;
|
rigidBody.Velocity = information.Left.Transform.Position.FromTo(information.Right.Transform.Position).Normalized * rigidBody.Velocity.Magnitude;
|
||||||
else
|
else
|
||||||
rigidBody.Velocity = rigidBody.Velocity.Reflect(information.Normal);
|
rigidBody.Velocity = rigidBody.Velocity.Reflect(information.Normal);
|
||||||
|
|
||||||
|
soundEffect.Play();
|
||||||
|
|
||||||
|
SendBallData();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SendBallData()
|
||||||
|
{
|
||||||
|
if (communicator is not INetworkServer server)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LiteNetLib.Utils.NetDataWriter dataWriter = communicator.GetMessageWriter(this);
|
||||||
|
dataWriter.Put(rigidBody.Transform.Position);
|
||||||
|
dataWriter.Put(rigidBody.Velocity);
|
||||||
|
server.Manager.SendToAll(dataWriter, LiteNetLib.DeliveryMethod.ReliableOrdered);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMessageReceived(NetPacketReader reader, NetPeer peer)
|
||||||
|
{
|
||||||
|
rigidBody.Transform.Position = reader.GetVector2D();
|
||||||
|
rigidBody.Velocity = reader.GetVector2D();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BallBehaviour() { }
|
public BallBehaviour() { }
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
using Microsoft.Xna.Framework.Input;
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
|
||||||
using Syntriax.Engine.Core;
|
using Syntriax.Engine.Core;
|
||||||
@@ -10,8 +9,8 @@ namespace Pong.Behaviours;
|
|||||||
|
|
||||||
public class KeyboardInputsBehaviour : BehaviourOverride, IButtonInputs<Keys>
|
public class KeyboardInputsBehaviour : BehaviourOverride, IButtonInputs<Keys>
|
||||||
{
|
{
|
||||||
private readonly Dictionary<Keys, Action<IButtonInputs<Keys>, Keys>> OnPressed = new(256);
|
private readonly Dictionary<Keys, Action<IButtonInputs<Keys>, Keys>?> OnPressed = new(256);
|
||||||
private readonly Dictionary<Keys, Action<IButtonInputs<Keys>, Keys>> OnReleased = new(256);
|
private readonly Dictionary<Keys, Action<IButtonInputs<Keys>, Keys>?> OnReleased = new(256);
|
||||||
|
|
||||||
private int cachePressedCurrentlyCount = 0;
|
private int cachePressedCurrentlyCount = 0;
|
||||||
private readonly Keys[] cachePressedCurrently = new Keys[256];
|
private readonly Keys[] cachePressedCurrently = new Keys[256];
|
||||||
@@ -69,7 +68,7 @@ public class KeyboardInputsBehaviour : BehaviourOverride, IButtonInputs<Keys>
|
|||||||
if (WasPressed(currentlyPressedKey))
|
if (WasPressed(currentlyPressedKey))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
action.Invoke(this, currentlyPressedKey);
|
action?.Invoke(this, currentlyPressedKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < cachePressedPreviouslyCount; i++)
|
for (int i = 0; i < cachePressedPreviouslyCount; i++)
|
||||||
@@ -82,7 +81,7 @@ public class KeyboardInputsBehaviour : BehaviourOverride, IButtonInputs<Keys>
|
|||||||
if (IsPressed(previouslyPressedKey))
|
if (IsPressed(previouslyPressedKey))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
action.Invoke(this, previouslyPressedKey);
|
action?.Invoke(this, previouslyPressedKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
Array.Copy(cachePressedCurrently, cachePressedPreviously, cachePressedCurrentlyCount);
|
Array.Copy(cachePressedCurrently, cachePressedPreviously, cachePressedCurrentlyCount);
|
||||||
|
@@ -8,9 +8,9 @@ namespace Pong.Behaviours;
|
|||||||
|
|
||||||
public class MonoGameCamera2DBehaviour(GraphicsDeviceManager Graphics) : BehaviourOverride, ICamera2D
|
public class MonoGameCamera2DBehaviour(GraphicsDeviceManager Graphics) : BehaviourOverride, ICamera2D
|
||||||
{
|
{
|
||||||
public event OnMatrixTransformChangedDelegate? OnMatrixTransformChanged = null;
|
public System.Action<MonoGameCamera2DBehaviour>? OnMatrixTransformChanged { get; set; } = null;
|
||||||
public event OnViewportChangedDelegate? OnViewportChanged = null;
|
public System.Action<MonoGameCamera2DBehaviour>? OnViewportChanged { get; set; } = null;
|
||||||
public event OnZoomChangedDelegate? OnZoomChanged = null;
|
public System.Action<MonoGameCamera2DBehaviour>? OnZoomChanged { get; set; } = null;
|
||||||
|
|
||||||
private Matrix _matrixTransform = Matrix.Identity;
|
private Matrix _matrixTransform = Matrix.Identity;
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ public class MonoGameCamera2DBehaviour(GraphicsDeviceManager Graphics) : Behavio
|
|||||||
set => Transform.Rotation = value;
|
set => Transform.Rotation = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public event IAssignableTransform.OnTransformAssignedDelegate? OnTransformAssigned { add => GameObject.OnTransformAssigned += value; remove => GameObject.OnTransformAssigned -= value; }
|
System.Action<IAssignableTransform>? IAssignableTransform.OnTransformAssigned { get => GameObject.OnTransformAssigned; set => GameObject.OnTransformAssigned = value; }
|
||||||
ITransform IAssignableTransform.Transform => GameObject.Transform;
|
ITransform IAssignableTransform.Transform => GameObject.Transform;
|
||||||
bool IAssignableTransform.Assign(ITransform transform) => GameObject.Assign(transform);
|
bool IAssignableTransform.Assign(ITransform transform) => GameObject.Assign(transform);
|
||||||
|
|
||||||
@@ -99,8 +99,4 @@ public class MonoGameCamera2DBehaviour(GraphicsDeviceManager Graphics) : Behavio
|
|||||||
Matrix.CreateScale(Zoom) *
|
Matrix.CreateScale(Zoom) *
|
||||||
Matrix.CreateTranslation(new Vector3(_viewport.Width * .5f, _viewport.Height * .5f, 0f));
|
Matrix.CreateTranslation(new Vector3(_viewport.Width * .5f, _viewport.Height * .5f, 0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
public delegate void OnMatrixTransformChangedDelegate(MonoGameCamera2DBehaviour sender);
|
|
||||||
public delegate void OnViewportChangedDelegate(MonoGameCamera2DBehaviour sender);
|
|
||||||
public delegate void OnZoomChangedDelegate(MonoGameCamera2DBehaviour sender);
|
|
||||||
}
|
}
|
||||||
|
154
Game/Behaviours/NetworkedKeyboardInputs.cs
Normal file
154
Game/Behaviours/NetworkedKeyboardInputs.cs
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using LiteNetLib;
|
||||||
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
using Syntriax.Engine.Input;
|
||||||
|
using Syntriax.Engine.Network;
|
||||||
|
|
||||||
|
namespace Pong.Behaviours;
|
||||||
|
|
||||||
|
public class NetworkedKeyboardInputs : NetworkBehaviour, IButtonInputs<Keys>
|
||||||
|
{
|
||||||
|
private readonly Dictionary<Keys, Action<IButtonInputs<Keys>, Keys>?> OnPressed = new(256);
|
||||||
|
private readonly Dictionary<Keys, Action<IButtonInputs<Keys>, Keys>?> OnReleased = new(256);
|
||||||
|
|
||||||
|
private int cachePressedCurrentlyCount = 0;
|
||||||
|
private readonly Keys[] cachePressedCurrently = new Keys[256];
|
||||||
|
|
||||||
|
private int cachePressedPreviouslyCount = 0;
|
||||||
|
private readonly Keys[] cachePressedPreviously = new Keys[256];
|
||||||
|
|
||||||
|
public void RegisterOnPress(Keys key, Action<IButtonInputs<Keys>, Keys> callback)
|
||||||
|
{
|
||||||
|
if (OnPressed.TryGetValue(key, out var action))
|
||||||
|
{
|
||||||
|
action += callback;
|
||||||
|
OnPressed.Remove(key);
|
||||||
|
OnPressed.Add(key, action);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OnPressed.Add(key, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnregisterOnPress(Keys key, Action<IButtonInputs<Keys>, Keys> callback)
|
||||||
|
{
|
||||||
|
if (OnPressed.TryGetValue(key, out var action))
|
||||||
|
action -= callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterOnRelease(Keys key, Action<IButtonInputs<Keys>, Keys> callback)
|
||||||
|
{
|
||||||
|
if (OnReleased.TryGetValue(key, out var action))
|
||||||
|
{
|
||||||
|
action += callback;
|
||||||
|
OnReleased.Remove(key);
|
||||||
|
OnReleased.Add(key, action);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OnReleased.Add(key, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnregisterOnRelease(Keys key, Action<IButtonInputs<Keys>, Keys> callback)
|
||||||
|
{
|
||||||
|
if (OnReleased.TryGetValue(key, out var action))
|
||||||
|
action -= callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnUpdate()
|
||||||
|
{
|
||||||
|
if (!IsServer && !LocalAssigned)
|
||||||
|
return;
|
||||||
|
|
||||||
|
KeyboardState keyboardState = Keyboard.GetState();
|
||||||
|
keyboardState.GetPressedKeys(cachePressedCurrently);
|
||||||
|
cachePressedCurrentlyCount = keyboardState.GetPressedKeyCount();
|
||||||
|
|
||||||
|
for (int i = 0; i < cachePressedCurrentlyCount; i++)
|
||||||
|
{
|
||||||
|
Keys currentlyPressedKey = cachePressedCurrently[i];
|
||||||
|
|
||||||
|
if (!OnPressed.TryGetValue(currentlyPressedKey, out var action))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (WasPressed(currentlyPressedKey))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
action?.Invoke(this, currentlyPressedKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < cachePressedPreviouslyCount; i++)
|
||||||
|
{
|
||||||
|
Keys previouslyPressedKey = cachePressedPreviously[i];
|
||||||
|
|
||||||
|
if (!OnReleased.TryGetValue(previouslyPressedKey, out var action))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (IsPressed(previouslyPressedKey))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
action?.Invoke(this, previouslyPressedKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
Array.Copy(cachePressedCurrently, cachePressedPreviously, cachePressedCurrentlyCount);
|
||||||
|
cachePressedPreviouslyCount = cachePressedCurrentlyCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsPressed(Keys key)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < cachePressedCurrentlyCount; i++)
|
||||||
|
if (cachePressedCurrently[i] == key)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool WasPressed(Keys key)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < cachePressedPreviouslyCount; i++)
|
||||||
|
if (cachePressedPreviously[i] == key)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnInitialize()
|
||||||
|
{
|
||||||
|
base.OnInitialize();
|
||||||
|
foreach (Keys key in Enum.GetValues(typeof(Keys)))
|
||||||
|
{
|
||||||
|
RegisterOnPress(key, (keys, keyVal) =>
|
||||||
|
{
|
||||||
|
if (!LocalAssigned && !IsServer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var netDataWriter = NetworkCommunicator.GetMessageWriter(this);
|
||||||
|
netDataWriter.Put(true);
|
||||||
|
netDataWriter.Put((int)key);
|
||||||
|
NetworkCommunicator.Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableOrdered);
|
||||||
|
});
|
||||||
|
RegisterOnRelease(key, (keys, keyVal) =>
|
||||||
|
{
|
||||||
|
if (!LocalAssigned && !IsServer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var netDataWriter = NetworkCommunicator.GetMessageWriter(this);
|
||||||
|
netDataWriter.Put(false);
|
||||||
|
netDataWriter.Put((int)key);
|
||||||
|
NetworkCommunicator.Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableOrdered);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMessageReceived(NetPacketReader reader, NetPeer peer)
|
||||||
|
{
|
||||||
|
bool isPressed = reader.GetBool();
|
||||||
|
Keys key = (Keys)reader.GetInt();
|
||||||
|
|
||||||
|
if (isPressed)
|
||||||
|
if (OnPressed.TryGetValue(key, out var action))
|
||||||
|
action?.Invoke(this, key);
|
||||||
|
if (!isPressed)
|
||||||
|
if (OnReleased.TryGetValue(key, out var action))
|
||||||
|
action?.Invoke(this, key);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,7 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using LiteNetLib.Utils;
|
|
||||||
using Microsoft.Xna.Framework.Input;
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
|
||||||
|
using LiteNetLib;
|
||||||
|
using LiteNetLib.Utils;
|
||||||
|
|
||||||
using Syntriax.Engine.Core;
|
using Syntriax.Engine.Core;
|
||||||
using Syntriax.Engine.Input;
|
using Syntriax.Engine.Input;
|
||||||
using Syntriax.Engine.Network;
|
using Syntriax.Engine.Network;
|
||||||
@@ -9,7 +12,7 @@ using Syntriax.Engine.Network.Abstract;
|
|||||||
|
|
||||||
namespace Pong.Behaviours;
|
namespace Pong.Behaviours;
|
||||||
|
|
||||||
public class PaddleBehaviour(Keys Up, Keys Down, float High, float Low, float Speed) : NetworkBehaviour
|
public class PaddleBehaviour(Keys Up, Keys Down, float High, float Low, float Speed) : BehaviourOverride
|
||||||
{
|
{
|
||||||
private Keys Up { get; } = Up;
|
private Keys Up { get; } = Up;
|
||||||
private Keys Down { get; } = Down;
|
private Keys Down { get; } = Down;
|
||||||
@@ -21,6 +24,7 @@ public class PaddleBehaviour(Keys Up, Keys Down, float High, float Low, float Sp
|
|||||||
private bool isDownPressed = false;
|
private bool isDownPressed = false;
|
||||||
|
|
||||||
private IButtonInputs<Keys> inputs = null!;
|
private IButtonInputs<Keys> inputs = null!;
|
||||||
|
private INetworkCommunicator communicator = null!;
|
||||||
|
|
||||||
protected override void OnUpdate()
|
protected override void OnUpdate()
|
||||||
{
|
{
|
||||||
@@ -28,27 +32,33 @@ public class PaddleBehaviour(Keys Up, Keys Down, float High, float Low, float Sp
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (isUpPressed)
|
if (isUpPressed)
|
||||||
Move(Vector2D.Up);
|
MovePaddle(Vector2D.Up * (float)Time.Elapsed.TotalSeconds * Speed);
|
||||||
else if (isDownPressed)
|
else if (isDownPressed)
|
||||||
Move(-Vector2D.Up);
|
MovePaddle(-Vector2D.Up * (float)Time.Elapsed.TotalSeconds * Speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Move(Vector2D vectorToMove)
|
private void MovePaddle(Vector2D vectorToAdd)
|
||||||
{
|
{
|
||||||
GameObject.Transform.Position = GameObject.Transform.Position + vectorToMove * (float)Time.Elapsed.TotalSeconds * Speed;
|
GameObject.Transform.Position += vectorToAdd;
|
||||||
GameObject.Transform.Position = new Vector2D(GameObject.Transform.Position.X, MathF.Max(MathF.Min(GameObject.Transform.Position.Y, High), Low));
|
GameObject.Transform.Position = new Vector2D(GameObject.Transform.Position.X, MathF.Max(MathF.Min(GameObject.Transform.Position.Y, High), Low));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnFirstActiveFrame()
|
protected override void OnFirstActiveFrame()
|
||||||
{
|
{
|
||||||
if (!BehaviourController.TryGetBehaviour<IButtonInputs<Keys>>(out var behaviourResult))
|
BehaviourController.TryGetBehaviour<IButtonInputs<Keys>>(out var behaviourResult);
|
||||||
inputs = behaviourResult ?? BehaviourController.AddBehaviour<KeyboardInputsBehaviour>();
|
inputs = behaviourResult ?? throw new Exception($"{nameof(IButtonInputs<Keys>)} is missing on {GameObject.Name}.");
|
||||||
|
|
||||||
|
if (!GameObject.GameManager.TryFindBehaviour(out INetworkCommunicator? foundCommunicator))
|
||||||
|
throw new Exception($"{nameof(INetworkCommunicator)} is missing on GameManager.");
|
||||||
|
|
||||||
inputs.RegisterOnPress(Up, OnUpPressed);
|
inputs.RegisterOnPress(Up, OnUpPressed);
|
||||||
inputs.RegisterOnRelease(Up, OnUpReleased);
|
inputs.RegisterOnRelease(Up, OnUpReleased);
|
||||||
|
|
||||||
inputs.RegisterOnPress(Down, OnDownPressed);
|
inputs.RegisterOnPress(Down, OnDownPressed);
|
||||||
inputs.RegisterOnRelease(Down, OnDownReleased);
|
inputs.RegisterOnRelease(Down, OnDownReleased);
|
||||||
|
|
||||||
|
communicator = foundCommunicator;
|
||||||
|
communicator.RegisterEntityListener(this, OnDataReceived);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnFinalize()
|
protected override void OnFinalize()
|
||||||
@@ -60,40 +70,32 @@ public class PaddleBehaviour(Keys Up, Keys Down, float High, float Low, float Sp
|
|||||||
inputs.UnregisterOnRelease(Down, OnDownReleased);
|
inputs.UnregisterOnRelease(Down, OnDownReleased);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnUpPressed(IButtonInputs<Keys> inputs, Keys keys) { isUpPressed = true; SendData(new PaddleInputs() { IsUpPressed = isUpPressed, IsDownPressed = isDownPressed, PositionY = Transform.Position.Y }); }
|
private void UpdateNetwork()
|
||||||
private void OnUpReleased(IButtonInputs<Keys> inputs, Keys keys) { isUpPressed = false; SendData(new PaddleInputs() { IsUpPressed = isUpPressed, IsDownPressed = isDownPressed, PositionY = Transform.Position.Y }); }
|
|
||||||
private void OnDownPressed(IButtonInputs<Keys> inputs, Keys keys) { isDownPressed = true; SendData(new PaddleInputs() { IsUpPressed = isUpPressed, IsDownPressed = isDownPressed, PositionY = Transform.Position.Y }); }
|
|
||||||
private void OnDownReleased(IButtonInputs<Keys> inputs, Keys keys) { isDownPressed = false; SendData(new PaddleInputs() { IsUpPressed = isUpPressed, IsDownPressed = isDownPressed, PositionY = Transform.Position.Y }); }
|
|
||||||
|
|
||||||
public override void ReceiveData<T>(T data)
|
|
||||||
{
|
{
|
||||||
if (data is not PaddleInputs paddleInputs)
|
NetDataWriter netDataWriter = communicator.GetEntityWriter(this);
|
||||||
return;
|
netDataWriter.Put(isUpPressed);
|
||||||
|
netDataWriter.Put(isDownPressed);
|
||||||
Transform.Position = new(Transform.Position.X, paddleInputs.PositionY);
|
netDataWriter.Put(Transform.Position);
|
||||||
isUpPressed = paddleInputs.IsUpPressed;
|
communicator.Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableOrdered);
|
||||||
isDownPressed = paddleInputs.IsDownPressed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[System.Serializable]
|
private void OnDataReceived(NetPacketReader reader, NetPeer peer)
|
||||||
public struct PaddleInputs : INetworkPacket
|
|
||||||
{
|
{
|
||||||
public float PositionY { get; set; }
|
if (communicator is INetworkServer server)
|
||||||
public bool IsUpPressed { get; set; }
|
|
||||||
public bool IsDownPressed { get; set; }
|
|
||||||
|
|
||||||
public void Deserialize(NetDataReader reader)
|
|
||||||
{
|
{
|
||||||
PositionY = reader.GetFloat();
|
reader.Get(out isUpPressed);
|
||||||
IsUpPressed = reader.GetBool();
|
reader.Get(out isDownPressed);
|
||||||
IsDownPressed = reader.GetBool();
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
public void Serialize(NetDataWriter writer)
|
|
||||||
{
|
{
|
||||||
writer.Put(PositionY);
|
reader.Get(out isUpPressed);
|
||||||
writer.Put(IsUpPressed);
|
reader.Get(out isDownPressed);
|
||||||
writer.Put(IsDownPressed);
|
Transform.Position = reader.GetVector2D();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnUpPressed(IButtonInputs<Keys> inputs, Keys keys) { isUpPressed = true; UpdateNetwork(); }
|
||||||
|
private void OnUpReleased(IButtonInputs<Keys> inputs, Keys keys) { isUpPressed = false; UpdateNetwork(); }
|
||||||
|
private void OnDownPressed(IButtonInputs<Keys> inputs, Keys keys) { isDownPressed = true; UpdateNetwork(); }
|
||||||
|
private void OnDownReleased(IButtonInputs<Keys> inputs, Keys keys) { isDownPressed = false; UpdateNetwork(); }
|
||||||
}
|
}
|
||||||
|
@@ -2,16 +2,23 @@ using System;
|
|||||||
|
|
||||||
using Microsoft.Xna.Framework.Input;
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
|
||||||
|
using LiteNetLib;
|
||||||
|
|
||||||
using Syntriax.Engine.Core;
|
using Syntriax.Engine.Core;
|
||||||
|
using Syntriax.Engine.Network;
|
||||||
|
using Syntriax.Engine.Network.Abstract;
|
||||||
|
|
||||||
namespace Pong.Behaviours;
|
namespace Pong.Behaviours;
|
||||||
|
|
||||||
public class PongManagerBehaviour : BehaviourOverride
|
public class PongManagerBehaviour : NetworkBehaviour
|
||||||
{
|
{
|
||||||
public Action<PongManagerBehaviour>? OnReset { get; set; } = null;
|
public Action<PongManagerBehaviour>? OnReset { get; set; } = null;
|
||||||
public Action<PongManagerBehaviour>? OnFinished { get; set; } = null;
|
public Action<PongManagerBehaviour>? OnFinished { get; set; } = null;
|
||||||
|
public Action<PongManagerBehaviour>? OnScoresUpdated { get; set; } = null;
|
||||||
public Action<PongManagerBehaviour>? OnScored { get; set; } = null;
|
public Action<PongManagerBehaviour>? OnScored { get; set; } = null;
|
||||||
|
|
||||||
|
private INetworkCommunicator communicator = null!;
|
||||||
|
|
||||||
public int ScoreLeft { get; private set; } = 0;
|
public int ScoreLeft { get; private set; } = 0;
|
||||||
public int ScoreRight { get; private set; } = 0;
|
public int ScoreRight { get; private set; } = 0;
|
||||||
public int ScoreSum => ScoreLeft + ScoreRight;
|
public int ScoreSum => ScoreLeft + ScoreRight;
|
||||||
@@ -28,30 +35,43 @@ public class PongManagerBehaviour : BehaviourOverride
|
|||||||
if (!BehaviourController.TryGetBehaviour(out buttonInputs))
|
if (!BehaviourController.TryGetBehaviour(out buttonInputs))
|
||||||
buttonInputs = BehaviourController.AddBehaviour<KeyboardInputsBehaviour>();
|
buttonInputs = BehaviourController.AddBehaviour<KeyboardInputsBehaviour>();
|
||||||
|
|
||||||
buttonInputs.RegisterOnRelease(Keys.Space, (_, _1) => Reset());
|
if (!GameObject.GameManager.TryFindBehaviour(out INetworkCommunicator? foundCommunicator))
|
||||||
}
|
throw new Exception($"{nameof(INetworkCommunicator)} is missing on GameManager.");
|
||||||
|
|
||||||
|
buttonInputs.RegisterOnRelease(Keys.Space, (_, _1) => Reset());
|
||||||
|
|
||||||
|
communicator = foundCommunicator;
|
||||||
|
}
|
||||||
|
|
||||||
public void ScoreToLeft()
|
public void ScoreToLeft()
|
||||||
{
|
{
|
||||||
ScoreLeft++;
|
ScoreLeft++;
|
||||||
|
OnScoresUpdated?.Invoke(this);
|
||||||
OnScored?.Invoke(this);
|
OnScored?.Invoke(this);
|
||||||
|
|
||||||
|
SendData();
|
||||||
|
|
||||||
CheckFinish();
|
CheckFinish();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ScoreToRight()
|
public void ScoreToRight()
|
||||||
{
|
{
|
||||||
ScoreRight++;
|
ScoreRight++;
|
||||||
|
OnScoresUpdated?.Invoke(this);
|
||||||
OnScored?.Invoke(this);
|
OnScored?.Invoke(this);
|
||||||
|
|
||||||
|
SendData();
|
||||||
|
|
||||||
CheckFinish();
|
CheckFinish();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
ScoreLeft = ScoreRight = 0;
|
ScoreLeft = ScoreRight = 0;
|
||||||
|
OnScoresUpdated?.Invoke(this);
|
||||||
OnReset?.Invoke(this);
|
OnReset?.Invoke(this);
|
||||||
|
|
||||||
|
SendData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckFinish()
|
private void CheckFinish()
|
||||||
@@ -61,4 +81,24 @@ public class PongManagerBehaviour : BehaviourOverride
|
|||||||
if (ScoreLeft > halfwayScore || ScoreRight > halfwayScore)
|
if (ScoreLeft > halfwayScore || ScoreRight > halfwayScore)
|
||||||
OnFinished?.Invoke(this);
|
OnFinished?.Invoke(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SendData()
|
||||||
|
{
|
||||||
|
if (communicator is not INetworkServer server)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LiteNetLib.Utils.NetDataWriter dataWriter = communicator.GetMessageWriter(this);
|
||||||
|
dataWriter.Put(ScoreLeft);
|
||||||
|
dataWriter.Put(ScoreRight);
|
||||||
|
server.Manager.SendToAll(dataWriter, LiteNetLib.DeliveryMethod.ReliableOrdered);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMessageReceived(NetPacketReader reader, NetPeer peer)
|
||||||
|
{
|
||||||
|
ScoreLeft = reader.GetInt();
|
||||||
|
ScoreRight = reader.GetInt();
|
||||||
|
OnScoresUpdated?.Invoke(this);
|
||||||
|
|
||||||
|
CheckFinish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,8 +14,7 @@ public class TextScoreBehaviour : TextBehaviour
|
|||||||
if (!GameObject.GameManager.TryFindBehaviour(out pongManager))
|
if (!GameObject.GameManager.TryFindBehaviour(out pongManager))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pongManager.OnScored += UpdateScores;
|
pongManager.OnScoresUpdated += UpdateScores;
|
||||||
pongManager.OnReset += UpdateScores;
|
|
||||||
|
|
||||||
UpdateScores(pongManager);
|
UpdateScores(pongManager);
|
||||||
}
|
}
|
||||||
|
@@ -13,6 +13,12 @@
|
|||||||
|
|
||||||
#---------------------------------- Content ---------------------------------#
|
#---------------------------------- Content ---------------------------------#
|
||||||
|
|
||||||
|
#begin Hit.wav
|
||||||
|
/importer:WavImporter
|
||||||
|
/processor:SoundEffectProcessor
|
||||||
|
/processorParam:Quality=Best
|
||||||
|
/build:Hit.wav
|
||||||
|
|
||||||
#begin UbuntuMono.spritefont
|
#begin UbuntuMono.spritefont
|
||||||
/importer:FontDescriptionImporter
|
/importer:FontDescriptionImporter
|
||||||
/processor:FontDescriptionProcessor
|
/processor:FontDescriptionProcessor
|
||||||
|
BIN
Game/Content/Hit.wav
Normal file
BIN
Game/Content/Hit.wav
Normal file
Binary file not shown.
@@ -27,6 +27,7 @@ public class GamePong : Game
|
|||||||
private GameManager gameManager = null!;
|
private GameManager gameManager = null!;
|
||||||
private BehaviourCollector<IDisplayableSprite> displayableCollector = null!;
|
private BehaviourCollector<IDisplayableSprite> displayableCollector = null!;
|
||||||
private BehaviourCollector<IDisplayableShape> displayableShapeCollector = null!;
|
private BehaviourCollector<IDisplayableShape> displayableShapeCollector = null!;
|
||||||
|
private BehaviourCollector<IMonoGameContentLoader> monoGameContentLoaderCollector = null!;
|
||||||
private MonoGameCamera2DBehaviour cameraBehaviour = null!;
|
private MonoGameCamera2DBehaviour cameraBehaviour = null!;
|
||||||
|
|
||||||
private PongManagerBehaviour pongManager = null!;
|
private PongManagerBehaviour pongManager = null!;
|
||||||
@@ -52,8 +53,11 @@ public class GamePong : Game
|
|||||||
gameManager = new();
|
gameManager = new();
|
||||||
displayableCollector = new(gameManager);
|
displayableCollector = new(gameManager);
|
||||||
displayableShapeCollector = new(gameManager);
|
displayableShapeCollector = new(gameManager);
|
||||||
|
monoGameContentLoaderCollector = new(gameManager);
|
||||||
physicsEngine = new PhysicsEngine2DCollector(gameManager) { IterationPerStep = 3 };
|
physicsEngine = new PhysicsEngine2DCollector(gameManager) { IterationPerStep = 3 };
|
||||||
|
|
||||||
|
monoGameContentLoaderCollector.OnCollected += (_, cached) => cached.LoadContent(Content);
|
||||||
|
|
||||||
gameManager.Initialize();
|
gameManager.Initialize();
|
||||||
|
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
@@ -87,9 +91,6 @@ public class GamePong : Game
|
|||||||
Window.Title = $"Pong - Client -> 127.0.0.1";
|
Window.Title = $"Pong - Client -> 127.0.0.1";
|
||||||
}
|
}
|
||||||
|
|
||||||
IGameObject gameObjectNetworkManager = gameManager.InstantiateGameObject().SetGameObject("Network Manager"); ;
|
|
||||||
gameObjectNetworkManager.BehaviourController.AddBehaviour<NetworkManager>();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
IGameObject gameObjectCamera = gameManager.InstantiateGameObject().SetGameObject("Camera"); ;
|
IGameObject gameObjectCamera = gameManager.InstantiateGameObject().SetGameObject("Camera"); ;
|
||||||
@@ -116,12 +117,14 @@ public class GamePong : Game
|
|||||||
IGameObject gameObjectLeftPaddle = gameManager.InstantiateGameObject().SetGameObject("Left Paddle");
|
IGameObject gameObjectLeftPaddle = gameManager.InstantiateGameObject().SetGameObject("Left Paddle");
|
||||||
gameObjectLeftPaddle.Transform.SetTransform(position: new Vector2D(-468f, 0f), scale: new Vector2D(15f, 60f));
|
gameObjectLeftPaddle.Transform.SetTransform(position: new Vector2D(-468f, 0f), scale: new Vector2D(15f, 60f));
|
||||||
|
|
||||||
|
gameObjectLeftPaddle.BehaviourController.AddBehaviour<NetworkedKeyboardInputs>().Id = "leftPaddleInput";
|
||||||
gameObjectLeftPaddle.BehaviourController.AddBehaviour<PaddleBehaviour>(Keys.W, Keys.S, 228f, -228f, 400f).Id = "leftPaddle";
|
gameObjectLeftPaddle.BehaviourController.AddBehaviour<PaddleBehaviour>(Keys.W, Keys.S, 228f, -228f, 400f).Id = "leftPaddle";
|
||||||
gameObjectLeftPaddle.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
|
gameObjectLeftPaddle.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
|
||||||
gameObjectLeftPaddle.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
|
gameObjectLeftPaddle.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
|
||||||
|
|
||||||
IGameObject gameObjectRightPaddle = gameManager.InstantiateGameObject().SetGameObject("Right Paddle");
|
IGameObject gameObjectRightPaddle = gameManager.InstantiateGameObject().SetGameObject("Right Paddle");
|
||||||
gameObjectRightPaddle.Transform.SetTransform(position: new Vector2D(468f, 0f), scale: new Vector2D(15f, 60f));
|
gameObjectRightPaddle.Transform.SetTransform(position: new Vector2D(468f, 0f), scale: new Vector2D(15f, 60f));
|
||||||
|
gameObjectRightPaddle.BehaviourController.AddBehaviour<NetworkedKeyboardInputs>().Id = "rightPaddleInput";
|
||||||
gameObjectRightPaddle.BehaviourController.AddBehaviour<PaddleBehaviour>(Keys.Up, Keys.Down, 228f, -228f, 400f).Id = "rightPaddle";
|
gameObjectRightPaddle.BehaviourController.AddBehaviour<PaddleBehaviour>(Keys.Up, Keys.Down, 228f, -228f, 400f).Id = "rightPaddle";
|
||||||
gameObjectRightPaddle.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
|
gameObjectRightPaddle.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
|
||||||
gameObjectRightPaddle.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
|
gameObjectRightPaddle.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
|
||||||
|
@@ -2,10 +2,17 @@ using Syntriax.Engine.Core.Abstract;
|
|||||||
|
|
||||||
namespace Syntriax.Engine.Network.Abstract;
|
namespace Syntriax.Engine.Network.Abstract;
|
||||||
|
|
||||||
public interface INetworkBehaviour : IBehaviour, INetworkEntity
|
public interface INetworkBehaviour : IBehaviour
|
||||||
{
|
{
|
||||||
|
int NetworkId { get; }
|
||||||
|
|
||||||
|
bool LocalAssigned { get; }
|
||||||
|
|
||||||
bool IsServer { get; }
|
bool IsServer { get; }
|
||||||
bool IsClient { get; }
|
bool IsClient { get; }
|
||||||
|
|
||||||
INetworkCommunicator NetworkCommunicator { get; }
|
INetworkCommunicator NetworkCommunicator { get; }
|
||||||
|
|
||||||
|
public void RequestAssignment();
|
||||||
|
public void ReleaseAssignment();
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
namespace Syntriax.Engine.Network.Abstract;
|
namespace Syntriax.Engine.Network.Abstract;
|
||||||
|
|
||||||
public interface INetworkCommunicatorClient : INetworkCommunicator
|
public interface INetworkClient : INetworkCommunicator
|
||||||
{
|
{
|
||||||
void Connect(string address, int port, string? password = null);
|
void Connect(string address, int port, string? password = null);
|
||||||
}
|
}
|
@@ -1,18 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
using LiteNetLib;
|
using LiteNetLib;
|
||||||
|
using LiteNetLib.Utils;
|
||||||
|
|
||||||
|
using Syntriax.Engine.Core.Abstract;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Network.Abstract;
|
namespace Syntriax.Engine.Network.Abstract;
|
||||||
|
|
||||||
public interface INetworkCommunicator
|
public interface INetworkCommunicator
|
||||||
{
|
{
|
||||||
event OnPacketReceivedDelegate? OnPacketReceived;
|
|
||||||
|
|
||||||
EventBasedNetListener Listener { get; }
|
EventBasedNetListener Listener { get; }
|
||||||
NetManager Manager { get; }
|
NetManager Manager { get; }
|
||||||
|
|
||||||
void PollEvents();
|
void PollEvents();
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
void Send<T>(NetworkPacket<T> Data);
|
void RegisterEntityListener(IEntity entity, Action<NetPacketReader, NetPeer> onDataReceived);
|
||||||
|
void UnregisterEntityListener(IEntity entity);
|
||||||
delegate void OnPacketReceivedDelegate(INetworkCommunicator sender, object packet);
|
NetDataWriter GetEntityWriter(IEntity entity);
|
||||||
|
NetDataWriter GetMessageWriter(IEntity entity);
|
||||||
}
|
}
|
||||||
|
@@ -1,12 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Network.Abstract;
|
namespace Syntriax.Engine.Network.Abstract;
|
||||||
|
|
||||||
public interface INetworkEntity
|
internal interface INetworkEntity
|
||||||
{
|
{
|
||||||
event OnNetworkIdChangedDelegate? OnNetworkIdChanged;
|
Action<INetworkEntity, int> OnNetworkIdChanged { get; set; }
|
||||||
|
int NetworkId { get; set; }
|
||||||
|
|
||||||
uint NetworkId { get; set; }
|
void SetNetworkId(int id);
|
||||||
|
|
||||||
void ReceiveData<T>(T data);
|
|
||||||
|
|
||||||
delegate void OnNetworkIdChangedDelegate(INetworkEntity sender, uint previousId);
|
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +0,0 @@
|
|||||||
using LiteNetLib.Utils;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Network.Abstract;
|
|
||||||
|
|
||||||
public interface INetworkPacket : INetSerializable;
|
|
@@ -1,6 +1,6 @@
|
|||||||
namespace Syntriax.Engine.Network.Abstract;
|
namespace Syntriax.Engine.Network.Abstract;
|
||||||
|
|
||||||
public interface INetworkCommunicatorServer : INetworkCommunicator
|
public interface INetworkServer : INetworkCommunicator
|
||||||
{
|
{
|
||||||
string Password { get; }
|
string Password { get; }
|
||||||
int MaxConnectionCount { get; }
|
int MaxConnectionCount { get; }
|
@@ -1,7 +0,0 @@
|
|||||||
namespace Syntriax.Engine.Network.Abstract;
|
|
||||||
|
|
||||||
public class NetworkPacket<T>
|
|
||||||
{
|
|
||||||
public uint NetworkId { get; set; } = 0;
|
|
||||||
public T Data { get; set; } = default!;
|
|
||||||
}
|
|
@@ -1,25 +1,17 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using LiteNetLib;
|
using LiteNetLib;
|
||||||
using LiteNetLib.Utils;
|
using LiteNetLib.Utils;
|
||||||
|
|
||||||
using Syntriax.Engine.Core;
|
using Syntriax.Engine.Core;
|
||||||
|
using Syntriax.Engine.Core.Abstract;
|
||||||
using Syntriax.Engine.Network.Abstract;
|
using Syntriax.Engine.Network.Abstract;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Network;
|
namespace Syntriax.Engine.Network;
|
||||||
|
|
||||||
public abstract class NetworkBase : BehaviourOverride, INetworkCommunicator
|
public abstract class NetworkBase : BehaviourOverride, INetworkCommunicator
|
||||||
{
|
{
|
||||||
public event INetworkCommunicator.OnPacketReceivedDelegate? OnPacketReceived = null;
|
|
||||||
|
|
||||||
protected readonly NetPacketProcessor netPacketProcessor = new();
|
|
||||||
|
|
||||||
protected readonly Dictionary<uint, INetworkEntity> networkEntities = [];
|
|
||||||
|
|
||||||
protected BehaviourCollector<INetworkEntity> networkEntityCollector = null!;
|
|
||||||
|
|
||||||
public EventBasedNetListener Listener { get; private set; } = null!;
|
public EventBasedNetListener Listener { get; private set; } = null!;
|
||||||
public NetManager Manager { get; private set; } = null!;
|
public NetManager Manager { get; private set; } = null!;
|
||||||
|
|
||||||
@@ -31,110 +23,59 @@ public abstract class NetworkBase : BehaviourOverride, INetworkCommunicator
|
|||||||
Manager = new NetManager(Listener);
|
Manager = new NetManager(Listener);
|
||||||
|
|
||||||
Listener.NetworkReceiveEvent += NetworkReceiveEvent;
|
Listener.NetworkReceiveEvent += NetworkReceiveEvent;
|
||||||
|
|
||||||
netPacketProcessor.RegisterNestedType<Pong.Behaviours.PaddleBehaviour.PaddleInputs>();
|
|
||||||
RegisterPackets();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RegisterPackets()
|
|
||||||
{
|
|
||||||
var packetTypes = Assembly.GetExecutingAssembly().GetTypes()
|
|
||||||
.Where(t => typeof(INetworkPacket).IsAssignableFrom(t) && !t.IsInterface)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
MethodInfo[] subscribeMethods = netPacketProcessor.GetType()
|
|
||||||
.GetMethods()
|
|
||||||
.Where(m => m.Name == nameof(NetPacketProcessor.SubscribeReusable))
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
MethodInfo subscribeMethod = subscribeMethods
|
|
||||||
.FirstOrDefault(m =>
|
|
||||||
m.GetParameters().Length == 1 &&
|
|
||||||
m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(Action<,>)
|
|
||||||
) ?? throw new Exception();
|
|
||||||
|
|
||||||
MethodInfo[] methodInfos = typeof(NetworkBase)
|
|
||||||
.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance);
|
|
||||||
|
|
||||||
MethodInfo method = methodInfos
|
|
||||||
.FirstOrDefault(
|
|
||||||
m => m.Name == nameof(OnPacketArrived) &&
|
|
||||||
m.IsGenericMethodDefinition
|
|
||||||
) ?? throw new Exception();
|
|
||||||
|
|
||||||
foreach (var packetType in packetTypes)
|
|
||||||
{
|
|
||||||
var networkPacketType = typeof(NetworkPacket<>).MakeGenericType(packetType);
|
|
||||||
MethodInfo genericSubscribe = subscribeMethod.MakeGenericMethod(networkPacketType, typeof(NetPeer));
|
|
||||||
|
|
||||||
Action<object, NetPeer> handler = (packet, peer) =>
|
|
||||||
{
|
|
||||||
MethodInfo handlerMethod = method.MakeGenericMethod(packetType);
|
|
||||||
handlerMethod.Invoke(this, [packet, peer]);
|
|
||||||
};
|
|
||||||
genericSubscribe.Invoke(netPacketProcessor, [handler]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPacketArrived<T>(NetworkPacket<T> packet, NetPeer peer) where T : INetworkPacket
|
|
||||||
{
|
|
||||||
if (networkEntities.TryGetValue(packet.NetworkId, out INetworkEntity? entity))
|
|
||||||
entity.ReceiveData(packet.Data);
|
|
||||||
|
|
||||||
OnPacketReceived?.Invoke(this, packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnInitialize()
|
|
||||||
{
|
|
||||||
base.OnInitialize();
|
|
||||||
|
|
||||||
networkEntityCollector = new(GameObject.GameManager);
|
|
||||||
networkEntityCollector.OnCollected += OnNetworkEntityCollected;
|
|
||||||
networkEntityCollector.OnRemoved += OnNetworkEntityRemoved;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnFinalize()
|
|
||||||
{
|
|
||||||
networkEntityCollector.OnCollected -= OnNetworkEntityCollected;
|
|
||||||
networkEntityCollector.OnRemoved -= OnNetworkEntityRemoved;
|
|
||||||
Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnNetworkEntityCollected(BehaviourCollector<INetworkEntity> sender, INetworkEntity behaviourCollected)
|
|
||||||
{
|
|
||||||
if (behaviourCollected.NetworkId != 0)
|
|
||||||
networkEntities.Add(behaviourCollected.NetworkId, behaviourCollected);
|
|
||||||
|
|
||||||
behaviourCollected.OnNetworkIdChanged += OnNetworkIdChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnNetworkIdChanged(INetworkEntity sender, uint previousId)
|
|
||||||
{
|
|
||||||
if (networkEntities.TryGetValue(previousId, out INetworkEntity? networkEntity) && sender == networkEntity)
|
|
||||||
networkEntities.Remove(previousId);
|
|
||||||
|
|
||||||
networkEntities.Add(sender.NetworkId, sender);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnNetworkEntityRemoved(BehaviourCollector<INetworkEntity> sender, INetworkEntity behaviourRemoved)
|
|
||||||
{
|
|
||||||
networkEntities.Remove(behaviourRemoved.NetworkId);
|
|
||||||
behaviourRemoved.OnNetworkIdChanged -= OnNetworkIdChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void NetworkReceiveEvent(NetPeer peer, NetPacketReader reader, byte channel, DeliveryMethod deliveryMethod)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
netPacketProcessor.ReadAllPackets(reader, peer);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PollEvents() => Manager.PollEvents();
|
public void PollEvents() => Manager.PollEvents();
|
||||||
public void Stop() => Manager.Stop();
|
public void Stop() => Manager.Stop();
|
||||||
|
|
||||||
protected override void OnUpdate() => PollEvents();
|
protected override void OnUpdate() => PollEvents();
|
||||||
|
protected override void OnFinalize() => Stop();
|
||||||
|
|
||||||
public abstract void Send<T>(NetworkPacket<T> packet);
|
private readonly Dictionary<string, Action<NetPacketReader, NetPeer>> callbacks = new(32);
|
||||||
|
|
||||||
|
private void NetworkReceiveEvent(NetPeer peer, NetPacketReader reader, byte channel, DeliveryMethod deliveryMethod)
|
||||||
|
{
|
||||||
|
if (callbacks.TryGetValue(reader.GetString(), out var action))
|
||||||
|
action?.Invoke(reader, peer);
|
||||||
|
|
||||||
|
reader.Recycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterEntityListener(IEntity entity, Action<NetPacketReader, NetPeer> onDataReceived)
|
||||||
|
{
|
||||||
|
if (callbacks.ContainsKey(entity.Id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
callbacks.Add(entity.Id, onDataReceived);
|
||||||
|
entity.OnIdChanged += OnEntityIdChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnregisterEntityListener(IEntity entity)
|
||||||
|
{
|
||||||
|
if (!callbacks.Remove(entity.Id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
entity.OnIdChanged -= OnEntityIdChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NetDataWriter GetMessageWriter(IEntity entity)
|
||||||
|
{
|
||||||
|
NetDataWriter netDataWriter = GetEntityWriter(entity);
|
||||||
|
netDataWriter.Put((int)MessageType.Message);
|
||||||
|
return netDataWriter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NetDataWriter GetEntityWriter(IEntity entity)
|
||||||
|
{
|
||||||
|
NetDataWriter netDataWriter = new();
|
||||||
|
netDataWriter.Put(entity.Id);
|
||||||
|
return netDataWriter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEntityIdChanged(IEntity entity, string previousId)
|
||||||
|
{
|
||||||
|
var action = callbacks[previousId];
|
||||||
|
callbacks.Remove(previousId);
|
||||||
|
callbacks.Add(entity.Id, action);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
|
using LiteNetLib;
|
||||||
|
|
||||||
using Syntriax.Engine.Core;
|
using Syntriax.Engine.Core;
|
||||||
using Syntriax.Engine.Network.Abstract;
|
using Syntriax.Engine.Network.Abstract;
|
||||||
|
|
||||||
@@ -7,46 +9,91 @@ namespace Syntriax.Engine.Network;
|
|||||||
|
|
||||||
public abstract class NetworkBehaviour : BehaviourOverride, INetworkBehaviour
|
public abstract class NetworkBehaviour : BehaviourOverride, INetworkBehaviour
|
||||||
{
|
{
|
||||||
public event INetworkEntity.OnNetworkIdChangedDelegate? OnNetworkIdChanged = null;
|
public int NetworkId { get; private set; } = 0;
|
||||||
|
|
||||||
private uint _networkId = 0;
|
public bool LocalAssigned { get; private set; } = false;
|
||||||
public uint NetworkId
|
|
||||||
{
|
|
||||||
get => _networkId;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value == _networkId)
|
|
||||||
return;
|
|
||||||
|
|
||||||
uint previousNetworkId = _networkId;
|
|
||||||
_networkId = value;
|
|
||||||
OnNetworkIdChanged?.Invoke(this, previousNetworkId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsServer { get; private set; } = false;
|
public bool IsServer { get; private set; } = false;
|
||||||
public bool IsClient { get; private set; } = false;
|
public bool IsClient { get; private set; } = false;
|
||||||
|
|
||||||
public INetworkCommunicator NetworkCommunicator { get; private set; } = null!;
|
public INetworkCommunicator NetworkCommunicator { get; private set; } = null!;
|
||||||
|
|
||||||
|
|
||||||
protected override void OnInitialize()
|
protected override void OnInitialize()
|
||||||
{
|
{
|
||||||
NetworkCommunicator = BehaviourController.GetBehaviourInParent<INetworkCommunicator>()
|
NetworkCommunicator = BehaviourController.GetBehaviourInParent<INetworkCommunicator>()
|
||||||
?? GameObject.GameManager.FindBehaviour<INetworkCommunicator>()
|
?? GameObject.GameManager.FindBehaviour<INetworkCommunicator>()
|
||||||
?? throw new Exception($"Could not find an {nameof(INetworkCommunicator)}.");
|
?? throw new Exception($"Could not find an {nameof(INetworkCommunicator)}.");
|
||||||
|
|
||||||
if (NetworkCommunicator is INetworkCommunicatorClient client)
|
NetworkCommunicator.RegisterEntityListener(this, OnMessageReceivedInternal);
|
||||||
|
|
||||||
|
if (NetworkCommunicator is INetworkClient client)
|
||||||
{
|
{
|
||||||
IsClient = true;
|
IsClient = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IsServer = true;
|
IsServer = true;
|
||||||
|
LocalAssigned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendData<T>(T data)
|
public void ReleaseAssignment()
|
||||||
=> NetworkCommunicator.Send(new NetworkPacket<T>() { NetworkId = _networkId, Data = data });
|
{
|
||||||
|
if (IsServer)
|
||||||
|
return;
|
||||||
|
|
||||||
public abstract void ReceiveData<T>(T data);
|
var netDataWriter = NetworkCommunicator.GetEntityWriter(this);
|
||||||
|
netDataWriter.Put((int)MessageType.AssignmentRelease);
|
||||||
|
NetworkCommunicator.Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableOrdered);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RequestAssignment()
|
||||||
|
{
|
||||||
|
if (IsServer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var netDataWriter = NetworkCommunicator.GetEntityWriter(this);
|
||||||
|
netDataWriter.Put((int)MessageType.AssignmentRequest);
|
||||||
|
NetworkCommunicator.Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableOrdered);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void OnMessageReceived(NetPacketReader reader, NetPeer peer);
|
||||||
|
private void OnMessageReceivedInternal(NetPacketReader reader, NetPeer peer)
|
||||||
|
{
|
||||||
|
MessageType messageType = (MessageType)reader.GetInt();
|
||||||
|
|
||||||
|
if (IsServer)
|
||||||
|
{
|
||||||
|
switch (messageType)
|
||||||
|
{
|
||||||
|
case MessageType.Message: OnMessageReceived(reader, peer); break;
|
||||||
|
case MessageType.AssignmentRequest:
|
||||||
|
case MessageType.AssignmentRelease:
|
||||||
|
var netDataWriter = NetworkCommunicator.GetEntityWriter(this);
|
||||||
|
netDataWriter.Put((int)(messageType == MessageType.AssignmentRequest ? MessageType.Assigned : MessageType.Unassigned));
|
||||||
|
peer.Send(netDataWriter, DeliveryMethod.ReliableOrdered);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (messageType)
|
||||||
|
{
|
||||||
|
case MessageType.Message: OnMessageReceived(reader, peer); break;
|
||||||
|
case MessageType.Assigned: LocalAssigned = true; break;
|
||||||
|
case MessageType.Unassigned: LocalAssigned = false; break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum MessageType
|
||||||
|
{
|
||||||
|
Message,
|
||||||
|
AssignmentRequest,
|
||||||
|
AssignmentRelease,
|
||||||
|
Assigned,
|
||||||
|
Unassigned,
|
||||||
}
|
}
|
||||||
|
@@ -1,23 +1,12 @@
|
|||||||
using LiteNetLib.Utils;
|
|
||||||
|
|
||||||
using Syntriax.Engine.Network.Abstract;
|
using Syntriax.Engine.Network.Abstract;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Network;
|
namespace Syntriax.Engine.Network;
|
||||||
|
|
||||||
public class NetworkClient : NetworkBase, INetworkCommunicatorClient
|
public class NetworkClient : NetworkBase, INetworkClient
|
||||||
{
|
{
|
||||||
private readonly NetDataWriter netDataWriter = new();
|
|
||||||
|
|
||||||
public void Connect(string address, int port, string? password = null)
|
public void Connect(string address, int port, string? password = null)
|
||||||
{
|
{
|
||||||
Manager.Start();
|
Manager.Start();
|
||||||
Manager.Connect(address, port, password ?? string.Empty);
|
Manager.Connect(address, port, password ?? string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Send<T>(NetworkPacket<T> packet)
|
|
||||||
{
|
|
||||||
netDataWriter.Reset();
|
|
||||||
netPacketProcessor.Write(netDataWriter, packet);
|
|
||||||
Manager.FirstPeer.Send(netDataWriter, LiteNetLib.DeliveryMethod.ReliableOrdered);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -9,7 +9,6 @@ public static class NetworkExtensions
|
|||||||
{
|
{
|
||||||
public static Vector2D GetVector2D(this NetPacketReader reader)
|
public static Vector2D GetVector2D(this NetPacketReader reader)
|
||||||
=> new(reader.GetFloat(), reader.GetFloat());
|
=> new(reader.GetFloat(), reader.GetFloat());
|
||||||
|
|
||||||
public static void GetVector2D(this NetPacketReader reader, out Vector2D vector2D)
|
public static void GetVector2D(this NetPacketReader reader, out Vector2D vector2D)
|
||||||
=> vector2D = new(reader.GetFloat(), reader.GetFloat());
|
=> vector2D = new(reader.GetFloat(), reader.GetFloat());
|
||||||
|
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
using LiteNetLib;
|
||||||
using Syntriax.Engine.Core;
|
using Syntriax.Engine.Core;
|
||||||
|
|
||||||
using Syntriax.Engine.Network.Abstract;
|
using Syntriax.Engine.Network.Abstract;
|
||||||
@@ -8,23 +9,23 @@ public class NetworkManager : NetworkBehaviour, INetworkManager
|
|||||||
{
|
{
|
||||||
private BehaviourCollector<INetworkEntity> entities = null!;
|
private BehaviourCollector<INetworkEntity> entities = null!;
|
||||||
|
|
||||||
private static uint networkIdIndex = 0;
|
private static int networkIdIndex = 0;
|
||||||
|
|
||||||
protected override void OnInitialize()
|
protected override void OnInitialize()
|
||||||
{
|
{
|
||||||
base.OnInitialize();
|
base.OnInitialize();
|
||||||
|
|
||||||
NetworkId = networkIdIndex++;
|
((INetworkEntity)this).SetNetworkId(networkIdIndex++);
|
||||||
|
|
||||||
entities = new(GameObject.GameManager);
|
entities = new(GameObject.GameManager);
|
||||||
foreach (var entity in entities)
|
foreach (var entity in entities)
|
||||||
entity.NetworkId = networkIdIndex++;
|
entity.SetNetworkId(networkIdIndex++);
|
||||||
|
|
||||||
entities.OnCollected += OnCollected;
|
entities.OnCollected += OnCollected;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCollected(BehaviourCollector<INetworkEntity> collector, INetworkEntity entity)
|
private void OnCollected(BehaviourCollector<INetworkEntity> collector, INetworkEntity entity)
|
||||||
=> entity.NetworkId = networkIdIndex++;
|
=> entity.SetNetworkId(networkIdIndex++);
|
||||||
|
|
||||||
public override void ReceiveData<T>(T data) { }
|
protected override void OnMessageReceived(NetPacketReader reader, NetPeer peer) { }
|
||||||
}
|
}
|
||||||
|
@@ -1,35 +1,22 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using LiteNetLib.Utils;
|
|
||||||
|
|
||||||
using Syntriax.Engine.Network.Abstract;
|
using Syntriax.Engine.Network.Abstract;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Network;
|
namespace Syntriax.Engine.Network;
|
||||||
|
|
||||||
public class NetworkServer : NetworkBase, INetworkCommunicatorServer
|
public class NetworkServer : NetworkBase, INetworkServer
|
||||||
{
|
{
|
||||||
public string Password { get; private set; } = string.Empty;
|
public string Password { get; private set; } = string.Empty;
|
||||||
public int MaxConnectionCount { get; private set; } = 2;
|
public int MaxConnectionCount { get; private set; } = 0;
|
||||||
public int Port { get; private set; } = 8888;
|
public int Port { get; private set; } = 8888;
|
||||||
|
|
||||||
private readonly NetDataWriter netDataWriter = new();
|
public NetworkServer() : base()
|
||||||
|
|
||||||
public NetworkServer() : this(8888, 2) { }
|
|
||||||
public NetworkServer(int port, int maxConnectionCount) : base()
|
|
||||||
{
|
{
|
||||||
MaxConnectionCount = maxConnectionCount;
|
|
||||||
Port = port;
|
|
||||||
|
|
||||||
Listener.ConnectionRequestEvent += request =>
|
Listener.ConnectionRequestEvent += request =>
|
||||||
{
|
{
|
||||||
if (Manager.ConnectedPeersCount < maxConnectionCount)
|
if (Manager.ConnectedPeersCount < MaxConnectionCount)
|
||||||
request.AcceptIfKey(Password);
|
request.AcceptIfKey(Password);
|
||||||
else
|
else
|
||||||
request.Reject();
|
request.Reject();
|
||||||
};
|
};
|
||||||
|
|
||||||
OnPacketReceived += ServerOnPacketReceived;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start(int port, int maxConnectionCount, string? password = null)
|
public void Start(int port, int maxConnectionCount, string? password = null)
|
||||||
@@ -40,28 +27,4 @@ public class NetworkServer : NetworkBase, INetworkCommunicatorServer
|
|||||||
|
|
||||||
Manager.Start(port);
|
Manager.Start(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Send<T>(NetworkPacket<T> packet)
|
|
||||||
{
|
|
||||||
netDataWriter.Reset();
|
|
||||||
netPacketProcessor.Write(netDataWriter, packet);
|
|
||||||
Manager.SendToAll(netDataWriter, LiteNetLib.DeliveryMethod.ReliableOrdered);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ServerOnPacketReceived(INetworkCommunicator sender, object packet)
|
|
||||||
{
|
|
||||||
MethodInfo[] methodInfos = GetType()
|
|
||||||
.GetMethods(BindingFlags.Public | BindingFlags.Instance);
|
|
||||||
|
|
||||||
MethodInfo method = methodInfos
|
|
||||||
.FirstOrDefault(
|
|
||||||
m => m.Name == nameof(Send) && m.IsGenericMethod
|
|
||||||
) ?? throw new Exception();
|
|
||||||
|
|
||||||
Type typeArguments = packet.GetType().GetGenericArguments()[0];
|
|
||||||
|
|
||||||
MethodInfo methodInfo = method.MakeGenericMethod(typeArguments);
|
|
||||||
|
|
||||||
methodInfo.Invoke(this, [packet]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user