Compare commits
30 Commits
main
...
feat/netwo
Author | SHA1 | Date |
---|---|---|
Syntriax | 1b1d9dcdac | |
Syntriax | 2565617ff9 | |
Syntriax | 01668c7be3 | |
Syntriax | cafbc55780 | |
Syntriax | ea3c4a2d2a | |
Syntriax | 89b756a615 | |
Syntriax | 6af84bcb6d | |
Syntriax | 3c1528d879 | |
Syntriax | 6f3e7b4ae5 | |
Syntriax | 86ef57fb62 | |
Syntriax | 6c326b1fc6 | |
Syntriax | b8b10de08a | |
Syntriax | edd2dd8511 | |
Syntriax | 70ac012a83 | |
Syntriax | d5a904fe8f | |
Syntriax | b1582ab5c2 | |
Syntriax | 8a0a0289f9 | |
Syntriax | 776d029e7e | |
Syntriax | 5afb8b69bf | |
Syntriax | 65073ec1ca | |
Syntriax | 0d62e5c986 | |
Syntriax | fe5a08840c | |
Syntriax | 1c7b1cb78a | |
Syntriax | 78010c266e | |
Syntriax | ef8b04648c | |
Syntriax | d4c57c0153 | |
Syntriax | 0e198afeab | |
Syntriax | de267a9d0f | |
Syntriax | 977a2abdd7 | |
Syntriax | 91e88bbff8 |
|
@ -10,9 +10,9 @@
|
|||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// If you have changed target frameworks, make sure to update the program path.
|
||||
"program": "${workspaceFolder}/bin/Debug/net8.0/${workspaceFolderBasename}.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"program": "${workspaceFolder}/Game/bin/Debug/net8.0/Game.dll",
|
||||
"args": ["server"],
|
||||
"cwd": "${workspaceFolder}/Game",
|
||||
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false
|
|
@ -9,7 +9,10 @@
|
|||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"label": "build"
|
||||
"label": "build",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/Game"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
2
Engine
2
Engine
|
@ -1 +1 @@
|
|||
Subproject commit 5d897f2f56c711629f8cbf915d0ed112cf21680f
|
||||
Subproject commit 2cf6135063b12dfff4d2c8391ad8edde806183f0
|
|
@ -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 Microsoft.Xna.Framework.Audio;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
|
||||
using LiteNetLib;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
using Syntriax.Engine.Network;
|
||||
using Syntriax.Engine.Network.Abstract;
|
||||
using Syntriax.Engine.Physics2D;
|
||||
using Syntriax.Engine.Physics2D.Abstract;
|
||||
|
||||
namespace Pong.Behaviours;
|
||||
|
||||
public class BallBehaviour : BehaviourOverride
|
||||
public class BallBehaviour : NetworkBehaviour, IMonoGameContentLoader
|
||||
{
|
||||
public Vector2D StartDirection { get; private set; } = Vector2D.Zero;
|
||||
public float Speed { get; set; } = 500f;
|
||||
|
@ -14,6 +21,13 @@ public class BallBehaviour : BehaviourOverride
|
|||
|
||||
private readonly Random random = new();
|
||||
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()
|
||||
{
|
||||
|
@ -21,11 +35,13 @@ public class BallBehaviour : BehaviourOverride
|
|||
throw new Exception($"{nameof(IRigidBody2D)} is missing on {GameObject.Name}.");
|
||||
if (!BehaviourController.TryGetBehaviour(out ICollider2D? foundCollider))
|
||||
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;
|
||||
|
||||
rigidBody = foundRigidBody;
|
||||
|
||||
communicator = foundCommunicator;
|
||||
if (GameObject.GameManager.TryFindBehaviour(out PongManagerBehaviour? pongManager))
|
||||
{
|
||||
pongManager.OnReset += ResetBall;
|
||||
|
@ -45,6 +61,8 @@ public class BallBehaviour : BehaviourOverride
|
|||
StateEnable.Enabled = true;
|
||||
BehaviourController.GameObject.Transform.Position = Vector2D.Zero;
|
||||
rigidBody.Velocity = GetRandomDirection() * Speed;
|
||||
|
||||
SendBallData();
|
||||
}
|
||||
|
||||
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;
|
||||
else
|
||||
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() { }
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
|
@ -10,8 +9,8 @@ namespace Pong.Behaviours;
|
|||
|
||||
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>> OnReleased = 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 int cachePressedCurrentlyCount = 0;
|
||||
private readonly Keys[] cachePressedCurrently = new Keys[256];
|
||||
|
@ -69,7 +68,7 @@ public class KeyboardInputsBehaviour : BehaviourOverride, IButtonInputs<Keys>
|
|||
if (WasPressed(currentlyPressedKey))
|
||||
continue;
|
||||
|
||||
action.Invoke(this, currentlyPressedKey);
|
||||
action?.Invoke(this, currentlyPressedKey);
|
||||
}
|
||||
|
||||
for (int i = 0; i < cachePressedPreviouslyCount; i++)
|
||||
|
@ -82,7 +81,7 @@ public class KeyboardInputsBehaviour : BehaviourOverride, IButtonInputs<Keys>
|
|||
if (IsPressed(previouslyPressedKey))
|
||||
continue;
|
||||
|
||||
action.Invoke(this, previouslyPressedKey);
|
||||
action?.Invoke(this, previouslyPressedKey);
|
||||
}
|
||||
|
||||
Array.Copy(cachePressedCurrently, cachePressedPreviously, cachePressedCurrentlyCount);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -2,8 +2,13 @@ using System;
|
|||
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
using LiteNetLib;
|
||||
using LiteNetLib.Utils;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
using Syntriax.Engine.Input;
|
||||
using Syntriax.Engine.Network;
|
||||
using Syntriax.Engine.Network.Abstract;
|
||||
|
||||
namespace Pong.Behaviours;
|
||||
|
||||
|
@ -19,6 +24,7 @@ public class PaddleBehaviour(Keys Up, Keys Down, float High, float Low, float Sp
|
|||
private bool isDownPressed = false;
|
||||
|
||||
private IButtonInputs<Keys> inputs = null!;
|
||||
private INetworkCommunicator communicator = null!;
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
|
@ -26,23 +32,33 @@ public class PaddleBehaviour(Keys Up, Keys Down, float High, float Low, float Sp
|
|||
return;
|
||||
|
||||
if (isUpPressed)
|
||||
GameObject.Transform.Position = GameObject.Transform.Position + Vector2D.Up * (float)Time.Elapsed.TotalSeconds * Speed;
|
||||
MovePaddle(Vector2D.Up * (float)Time.Elapsed.TotalSeconds * Speed);
|
||||
else if (isDownPressed)
|
||||
GameObject.Transform.Position = GameObject.Transform.Position + -Vector2D.Up * (float)Time.Elapsed.TotalSeconds * Speed;
|
||||
MovePaddle(-Vector2D.Up * (float)Time.Elapsed.TotalSeconds * Speed);
|
||||
}
|
||||
|
||||
private void MovePaddle(Vector2D vectorToAdd)
|
||||
{
|
||||
GameObject.Transform.Position += vectorToAdd;
|
||||
GameObject.Transform.Position = new Vector2D(GameObject.Transform.Position.X, MathF.Max(MathF.Min(GameObject.Transform.Position.Y, High), Low));
|
||||
}
|
||||
|
||||
protected override void OnFirstActiveFrame()
|
||||
{
|
||||
if (!BehaviourController.TryGetBehaviour<IButtonInputs<Keys>>(out var behaviourResult))
|
||||
inputs = behaviourResult ?? BehaviourController.AddBehaviour<KeyboardInputsBehaviour>();
|
||||
BehaviourController.TryGetBehaviour<IButtonInputs<Keys>>(out var behaviourResult);
|
||||
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.RegisterOnRelease(Up, OnUpReleased);
|
||||
|
||||
inputs.RegisterOnPress(Down, OnDownPressed);
|
||||
inputs.RegisterOnRelease(Down, OnDownReleased);
|
||||
|
||||
communicator = foundCommunicator;
|
||||
communicator.RegisterEntityListener(this, OnDataReceived);
|
||||
}
|
||||
|
||||
protected override void OnFinalize()
|
||||
|
@ -54,8 +70,32 @@ public class PaddleBehaviour(Keys Up, Keys Down, float High, float Low, float Sp
|
|||
inputs.UnregisterOnRelease(Down, OnDownReleased);
|
||||
}
|
||||
|
||||
private void OnUpPressed(IButtonInputs<Keys> inputs, Keys keys) => isUpPressed = true;
|
||||
private void OnUpReleased(IButtonInputs<Keys> inputs, Keys keys) => isUpPressed = false;
|
||||
private void OnDownPressed(IButtonInputs<Keys> inputs, Keys keys) => isDownPressed = true;
|
||||
private void OnDownReleased(IButtonInputs<Keys> inputs, Keys keys) => isDownPressed = false;
|
||||
private void UpdateNetwork()
|
||||
{
|
||||
NetDataWriter netDataWriter = communicator.GetEntityWriter(this);
|
||||
netDataWriter.Put(isUpPressed);
|
||||
netDataWriter.Put(isDownPressed);
|
||||
netDataWriter.Put(Transform.Position);
|
||||
communicator.Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableOrdered);
|
||||
}
|
||||
|
||||
private void OnDataReceived(NetPacketReader reader, NetPeer peer)
|
||||
{
|
||||
if (communicator is INetworkServer server)
|
||||
{
|
||||
reader.Get(out isUpPressed);
|
||||
reader.Get(out isDownPressed);
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.Get(out isUpPressed);
|
||||
reader.Get(out 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 LiteNetLib;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
using Syntriax.Engine.Network;
|
||||
using Syntriax.Engine.Network.Abstract;
|
||||
|
||||
namespace Pong.Behaviours;
|
||||
|
||||
public class PongManagerBehaviour : BehaviourOverride
|
||||
public class PongManagerBehaviour : NetworkBehaviour
|
||||
{
|
||||
public Action<PongManagerBehaviour>? OnReset { get; set; } = null;
|
||||
public Action<PongManagerBehaviour>? OnFinished { get; set; } = null;
|
||||
public Action<PongManagerBehaviour>? OnScoresUpdated { get; set; } = null;
|
||||
public Action<PongManagerBehaviour>? OnScored { get; set; } = null;
|
||||
|
||||
private INetworkCommunicator communicator = null!;
|
||||
|
||||
public int ScoreLeft { get; private set; } = 0;
|
||||
public int ScoreRight { get; private set; } = 0;
|
||||
public int ScoreSum => ScoreLeft + ScoreRight;
|
||||
|
@ -28,30 +35,43 @@ public class PongManagerBehaviour : BehaviourOverride
|
|||
if (!BehaviourController.TryGetBehaviour(out buttonInputs))
|
||||
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()
|
||||
{
|
||||
ScoreLeft++;
|
||||
OnScoresUpdated?.Invoke(this);
|
||||
OnScored?.Invoke(this);
|
||||
|
||||
SendData();
|
||||
|
||||
CheckFinish();
|
||||
}
|
||||
|
||||
public void ScoreToRight()
|
||||
{
|
||||
ScoreRight++;
|
||||
OnScoresUpdated?.Invoke(this);
|
||||
OnScored?.Invoke(this);
|
||||
|
||||
SendData();
|
||||
|
||||
CheckFinish();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
ScoreLeft = ScoreRight = 0;
|
||||
OnScoresUpdated?.Invoke(this);
|
||||
OnReset?.Invoke(this);
|
||||
|
||||
SendData();
|
||||
}
|
||||
|
||||
private void CheckFinish()
|
||||
|
@ -61,4 +81,24 @@ public class PongManagerBehaviour : BehaviourOverride
|
|||
if (ScoreLeft > halfwayScore || ScoreRight > halfwayScore)
|
||||
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))
|
||||
return;
|
||||
|
||||
pongManager.OnScored += UpdateScores;
|
||||
pongManager.OnReset += UpdateScores;
|
||||
pongManager.OnScoresUpdated += UpdateScores;
|
||||
|
||||
UpdateScores(pongManager);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,12 @@
|
|||
|
||||
#---------------------------------- Content ---------------------------------#
|
||||
|
||||
#begin Hit.wav
|
||||
/importer:WavImporter
|
||||
/processor:SoundEffectProcessor
|
||||
/processorParam:Quality=Best
|
||||
/build:Hit.wav
|
||||
|
||||
#begin UbuntuMono.spritefont
|
||||
/importer:FontDescriptionImporter
|
||||
/processor:FontDescriptionProcessor
|
||||
|
|
Binary file not shown.
|
@ -21,6 +21,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Apos.Shapes" Version="0.2.3" />
|
||||
<PackageReference Include="LiteNetLib" Version="1.2.0" />
|
||||
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.1.303" />
|
||||
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.303" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
using System;
|
||||
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
using Pong.Behaviours;
|
||||
using Apos.Shapes;
|
||||
|
||||
using Pong.Behaviours;
|
||||
using Syntriax.Engine.Network;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
using Syntriax.Engine.Core.Abstract;
|
||||
using Syntriax.Engine.Physics2D;
|
||||
using Syntriax.Engine.Physics2D.Primitives;
|
||||
using Syntriax.Engine.Physics2D.Abstract;
|
||||
using Syntriax.Engine.Physics2D.Primitives;
|
||||
|
||||
namespace Pong;
|
||||
|
||||
|
@ -22,8 +25,9 @@ public class GamePong : Game
|
|||
private ShapeBatch shapeBatch = null!;
|
||||
|
||||
private GameManager gameManager = null!;
|
||||
private BehaviourCacher<IDisplayableSprite> displayableCacher = null!;
|
||||
private BehaviourCacher<IDisplayableShape> displayableShapeCacher = null!;
|
||||
private BehaviourCollector<IDisplayableSprite> displayableCollector = null!;
|
||||
private BehaviourCollector<IDisplayableShape> displayableShapeCollector = null!;
|
||||
private BehaviourCollector<IMonoGameContentLoader> monoGameContentLoaderCollector = null!;
|
||||
private MonoGameCamera2DBehaviour cameraBehaviour = null!;
|
||||
|
||||
private PongManagerBehaviour pongManager = null!;
|
||||
|
@ -47,9 +51,12 @@ public class GamePong : Game
|
|||
{
|
||||
// TODO: Add your initialization logic here
|
||||
gameManager = new();
|
||||
displayableCacher = new(gameManager);
|
||||
displayableShapeCacher = new(gameManager);
|
||||
physicsEngine = new PhysicsEngine2DCacher(gameManager) { IterationPerStep = 3 };
|
||||
displayableCollector = new(gameManager);
|
||||
displayableShapeCollector = new(gameManager);
|
||||
monoGameContentLoaderCollector = new(gameManager);
|
||||
physicsEngine = new PhysicsEngine2DCollector(gameManager) { IterationPerStep = 3 };
|
||||
|
||||
monoGameContentLoaderCollector.OnCollected += (_, cached) => cached.LoadContent(Content);
|
||||
|
||||
gameManager.Initialize();
|
||||
|
||||
|
@ -64,58 +71,83 @@ public class GamePong : Game
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IGameObject gameObjectCamera = gameManager.InstantiateGameObject<GameObject>().SetGameObject("Camera"); ;
|
||||
string[] commandLineArguments = Environment.GetCommandLineArgs();
|
||||
if (commandLineArguments.Length != 1)
|
||||
{
|
||||
if (commandLineArguments[1].Equals("server", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
gameManager.InstantiateGameObject().BehaviourController.AddBehaviour<NetworkServer>().Start(8888, 2);
|
||||
Window.Title = "Pong - Server";
|
||||
}
|
||||
else
|
||||
{
|
||||
Window.Title = $"Pong - Client -> {commandLineArguments[1]}";
|
||||
gameManager.InstantiateGameObject().BehaviourController.AddBehaviour<NetworkClient>().Connect(commandLineArguments[1], 8888);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gameManager.InstantiateGameObject().BehaviourController.AddBehaviour<NetworkClient>().Connect("127.0.0.1", 8888);
|
||||
Window.Title = $"Pong - Client -> 127.0.0.1";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IGameObject gameObjectCamera = gameManager.InstantiateGameObject().SetGameObject("Camera"); ;
|
||||
gameObjectCamera.BehaviourController.AddBehaviour<CameraController>();
|
||||
cameraBehaviour = gameObjectCamera.BehaviourController.AddBehaviour<MonoGameCamera2DBehaviour>(graphics);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IGameObject gameObjectPongManager = gameManager.InstantiateGameObject<GameObject>().SetGameObject("Pong Game Manager");
|
||||
IGameObject gameObjectPongManager = gameManager.InstantiateGameObject().SetGameObject("Pong Game Manager");
|
||||
pongManager = gameObjectPongManager.BehaviourController.AddBehaviour<PongManagerBehaviour>(5);
|
||||
pongManager.Id = "pongManager";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IGameObject gameObjectBall = gameManager.InstantiateGameObject<GameObject>().SetGameObject("Ball");
|
||||
IGameObject gameObjectBall = gameManager.InstantiateGameObject().SetGameObject("Ball");
|
||||
gameObjectBall.Transform.SetTransform(position: new Vector2D(0, 0f), scale: new Vector2D(10f, 10f));
|
||||
|
||||
gameObjectBall.BehaviourController.AddBehaviour<CircleBehaviour>(new Circle(Vector2D.Zero, 1f));
|
||||
gameObjectBall.BehaviourController.AddBehaviour<BallBehaviour>();
|
||||
gameObjectBall.BehaviourController.AddBehaviour<BallBehaviour>().Id = "ball";
|
||||
gameObjectBall.BehaviourController.AddBehaviour<RigidBody2D>();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IGameObject gameObjectLeftPaddle = gameManager.InstantiateGameObject<GameObject>().SetGameObject("Left Paddle");
|
||||
IGameObject gameObjectLeftPaddle = gameManager.InstantiateGameObject().SetGameObject("Left Paddle");
|
||||
gameObjectLeftPaddle.Transform.SetTransform(position: new Vector2D(-468f, 0f), scale: new Vector2D(15f, 60f));
|
||||
|
||||
gameObjectLeftPaddle.BehaviourController.AddBehaviour<PaddleBehaviour>(Keys.W, Keys.S, 228f, -228f, 400f);
|
||||
gameObjectLeftPaddle.BehaviourController.AddBehaviour<NetworkedKeyboardInputs>().Id = "leftPaddleInput";
|
||||
gameObjectLeftPaddle.BehaviourController.AddBehaviour<PaddleBehaviour>(Keys.W, Keys.S, 228f, -228f, 400f).Id = "leftPaddle";
|
||||
gameObjectLeftPaddle.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
|
||||
gameObjectLeftPaddle.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
|
||||
|
||||
IGameObject gameObjectRightPaddle = gameManager.InstantiateGameObject<GameObject>().SetGameObject("Right Paddle");
|
||||
IGameObject gameObjectRightPaddle = gameManager.InstantiateGameObject().SetGameObject("Right Paddle");
|
||||
gameObjectRightPaddle.Transform.SetTransform(position: new Vector2D(468f, 0f), scale: new Vector2D(15f, 60f));
|
||||
gameObjectRightPaddle.BehaviourController.AddBehaviour<PaddleBehaviour>(Keys.Up, Keys.Down, 228f, -228f, 400f);
|
||||
gameObjectRightPaddle.BehaviourController.AddBehaviour<NetworkedKeyboardInputs>().Id = "rightPaddleInput";
|
||||
gameObjectRightPaddle.BehaviourController.AddBehaviour<PaddleBehaviour>(Keys.Up, Keys.Down, 228f, -228f, 400f).Id = "rightPaddle";
|
||||
gameObjectRightPaddle.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
|
||||
gameObjectRightPaddle.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IGameObject gameObjectWallTop = gameManager.InstantiateGameObject<GameObject>().SetGameObject("Wall Top");
|
||||
IGameObject gameObjectWallTop = gameManager.InstantiateGameObject().SetGameObject("Wall Top");
|
||||
gameObjectWallTop.Transform.SetTransform(position: new Vector2D(0f, 308f), scale: new Vector2D(552f, 20f));
|
||||
gameObjectWallTop.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
|
||||
gameObjectWallTop.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
|
||||
|
||||
IGameObject gameObjectWallBottom = gameManager.InstantiateGameObject<GameObject>().SetGameObject("Wall Bottom");
|
||||
IGameObject gameObjectWallBottom = gameManager.InstantiateGameObject().SetGameObject("Wall Bottom");
|
||||
gameObjectWallBottom.Transform.SetTransform(position: new Vector2D(0f, -308f), scale: new Vector2D(552f, 20f));
|
||||
gameObjectWallBottom.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
|
||||
gameObjectWallBottom.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
|
||||
|
||||
IGameObject gameObjectWallRight = gameManager.InstantiateGameObject<GameObject>().SetGameObject("Wall Right");
|
||||
IGameObject gameObjectWallRight = gameManager.InstantiateGameObject().SetGameObject("Wall Right");
|
||||
gameObjectWallRight.Transform.SetTransform(position: new Vector2D(532f, 0f), scale: new Vector2D(20f, 328f));
|
||||
gameObjectWallRight.BehaviourController.AddBehaviour<WallScoreBehaviour>((Action)pongManager.ScoreToLeft);
|
||||
gameObjectWallRight.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
|
||||
gameObjectWallRight.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
|
||||
|
||||
IGameObject gameObjectWallLeft = gameManager.InstantiateGameObject<GameObject>().SetGameObject("Wall Left");
|
||||
IGameObject gameObjectWallLeft = gameManager.InstantiateGameObject().SetGameObject("Wall Left");
|
||||
gameObjectWallLeft.Transform.SetTransform(position: new Vector2D(-532f, 0f), scale: new Vector2D(20f, 328f));
|
||||
gameObjectWallLeft.BehaviourController.AddBehaviour<WallScoreBehaviour>((Action)pongManager.ScoreToRight);
|
||||
gameObjectWallLeft.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
|
||||
|
@ -123,11 +155,11 @@ public class GamePong : Game
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IGameObject gameObjectLeftScoreText = gameManager.InstantiateGameObject<GameObject>().SetGameObject("Score Left");
|
||||
IGameObject gameObjectLeftScoreText = gameManager.InstantiateGameObject().SetGameObject("Score Left");
|
||||
gameObjectLeftScoreText.Transform.SetTransform(position: new Vector2D(-250f, 250f), scale: Vector2D.One * .25f);
|
||||
gameObjectLeftScoreText.BehaviourController.AddBehaviour<TextScoreBehaviour>(true, spriteFont);
|
||||
|
||||
IGameObject gameObjectRightScoreText = gameManager.InstantiateGameObject<GameObject>().SetGameObject("Score Right");
|
||||
IGameObject gameObjectRightScoreText = gameManager.InstantiateGameObject().SetGameObject("Score Right");
|
||||
gameObjectRightScoreText.Transform.SetTransform(position: new Vector2D(250f, 250f), scale: Vector2D.One * .25f);
|
||||
gameObjectRightScoreText.BehaviourController.AddBehaviour<TextScoreBehaviour>(false, spriteFont);
|
||||
}
|
||||
|
@ -154,12 +186,12 @@ public class GamePong : Game
|
|||
gameManager.PreDraw();
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, transformMatrix: cameraBehaviour.MatrixTransform);
|
||||
foreach (var displayable in displayableCacher)
|
||||
foreach (var displayable in displayableCollector)
|
||||
displayable.Draw(spriteBatch);
|
||||
spriteBatch.End();
|
||||
|
||||
shapeBatch.Begin(cameraBehaviour.MatrixTransform);
|
||||
foreach (var displayableShape in displayableShapeCacher)
|
||||
foreach (var displayableShape in displayableShapeCollector)
|
||||
displayableShape.Draw(shapeBatch);
|
||||
shapeBatch.End();
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
using Syntriax.Engine.Core.Abstract;
|
||||
|
||||
namespace Syntriax.Engine.Network.Abstract;
|
||||
|
||||
public interface INetworkBehaviour : IBehaviour
|
||||
{
|
||||
int NetworkId { get; }
|
||||
|
||||
bool LocalAssigned { get; }
|
||||
|
||||
bool IsServer { get; }
|
||||
bool IsClient { get; }
|
||||
|
||||
INetworkCommunicator NetworkCommunicator { get; }
|
||||
|
||||
public void RequestAssignment();
|
||||
public void ReleaseAssignment();
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
namespace Syntriax.Engine.Network.Abstract;
|
||||
|
||||
public interface INetworkClient : INetworkCommunicator
|
||||
{
|
||||
void Connect(string address, int port, string? password = null);
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
|
||||
using LiteNetLib;
|
||||
using LiteNetLib.Utils;
|
||||
|
||||
using Syntriax.Engine.Core.Abstract;
|
||||
|
||||
namespace Syntriax.Engine.Network.Abstract;
|
||||
|
||||
public interface INetworkCommunicator
|
||||
{
|
||||
EventBasedNetListener Listener { get; }
|
||||
NetManager Manager { get; }
|
||||
|
||||
void PollEvents();
|
||||
void Stop();
|
||||
|
||||
void RegisterEntityListener(IEntity entity, Action<NetPacketReader, NetPeer> onDataReceived);
|
||||
void UnregisterEntityListener(IEntity entity);
|
||||
NetDataWriter GetEntityWriter(IEntity entity);
|
||||
NetDataWriter GetMessageWriter(IEntity entity);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace Syntriax.Engine.Network.Abstract;
|
||||
|
||||
internal interface INetworkEntity
|
||||
{
|
||||
Action<INetworkEntity, int> OnNetworkIdChanged { get; set; }
|
||||
int NetworkId { get; set; }
|
||||
|
||||
void SetNetworkId(int id);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
namespace Syntriax.Engine.Network.Abstract;
|
||||
|
||||
public interface INetworkManager
|
||||
{
|
||||
// Action<IGameObject>? OnNetworkGameObjectInstantiated { get; set; }
|
||||
|
||||
INetworkCommunicator NetworkCommunicator { get; }
|
||||
|
||||
// Task<T> Instantiate<T>(params object?[]? args) where T : class, IGameObject;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
namespace Syntriax.Engine.Network.Abstract;
|
||||
|
||||
public interface INetworkServer : INetworkCommunicator
|
||||
{
|
||||
string Password { get; }
|
||||
int MaxConnectionCount { get; }
|
||||
int Port { get; }
|
||||
|
||||
void Start(int port, int maxConnectionCount, string? password = null);
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using LiteNetLib;
|
||||
using LiteNetLib.Utils;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
using Syntriax.Engine.Core.Abstract;
|
||||
using Syntriax.Engine.Network.Abstract;
|
||||
|
||||
namespace Syntriax.Engine.Network;
|
||||
|
||||
public abstract class NetworkBase : BehaviourOverride, INetworkCommunicator
|
||||
{
|
||||
public EventBasedNetListener Listener { get; private set; } = null!;
|
||||
public NetManager Manager { get; private set; } = null!;
|
||||
|
||||
public NetworkBase()
|
||||
{
|
||||
Priority = 10;
|
||||
|
||||
Listener = new EventBasedNetListener();
|
||||
Manager = new NetManager(Listener);
|
||||
|
||||
Listener.NetworkReceiveEvent += NetworkReceiveEvent;
|
||||
}
|
||||
|
||||
public void PollEvents() => Manager.PollEvents();
|
||||
public void Stop() => Manager.Stop();
|
||||
|
||||
protected override void OnUpdate() => PollEvents();
|
||||
protected override void OnFinalize() => Stop();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
using System;
|
||||
|
||||
using LiteNetLib;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
using Syntriax.Engine.Network.Abstract;
|
||||
|
||||
namespace Syntriax.Engine.Network;
|
||||
|
||||
public abstract class NetworkBehaviour : BehaviourOverride, INetworkBehaviour
|
||||
{
|
||||
public int NetworkId { get; private set; } = 0;
|
||||
|
||||
public bool LocalAssigned { get; private set; } = false;
|
||||
|
||||
public bool IsServer { get; private set; } = false;
|
||||
public bool IsClient { get; private set; } = false;
|
||||
|
||||
public INetworkCommunicator NetworkCommunicator { get; private set; } = null!;
|
||||
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
NetworkCommunicator = BehaviourController.GetBehaviourInParent<INetworkCommunicator>()
|
||||
?? GameObject.GameManager.FindBehaviour<INetworkCommunicator>()
|
||||
?? throw new Exception($"Could not find an {nameof(INetworkCommunicator)}.");
|
||||
|
||||
NetworkCommunicator.RegisterEntityListener(this, OnMessageReceivedInternal);
|
||||
|
||||
if (NetworkCommunicator is INetworkClient client)
|
||||
{
|
||||
IsClient = true;
|
||||
return;
|
||||
}
|
||||
|
||||
IsServer = true;
|
||||
LocalAssigned = true;
|
||||
}
|
||||
|
||||
public void ReleaseAssignment()
|
||||
{
|
||||
if (IsServer)
|
||||
return;
|
||||
|
||||
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,
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using Syntriax.Engine.Network.Abstract;
|
||||
|
||||
namespace Syntriax.Engine.Network;
|
||||
|
||||
public class NetworkClient : NetworkBase, INetworkClient
|
||||
{
|
||||
public void Connect(string address, int port, string? password = null)
|
||||
{
|
||||
Manager.Start();
|
||||
Manager.Connect(address, port, password ?? string.Empty);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
using LiteNetLib;
|
||||
using LiteNetLib.Utils;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Network;
|
||||
|
||||
public static class NetworkExtensions
|
||||
{
|
||||
public static Vector2D GetVector2D(this NetPacketReader reader)
|
||||
=> new(reader.GetFloat(), reader.GetFloat());
|
||||
public static void GetVector2D(this NetPacketReader reader, out Vector2D vector2D)
|
||||
=> vector2D = new(reader.GetFloat(), reader.GetFloat());
|
||||
|
||||
public static void Put(this NetDataWriter writer, Vector2D vector)
|
||||
{
|
||||
writer.Put(vector.X);
|
||||
writer.Put(vector.Y);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
using LiteNetLib;
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
using Syntriax.Engine.Network.Abstract;
|
||||
|
||||
namespace Syntriax.Engine.Network;
|
||||
|
||||
public class NetworkManager : NetworkBehaviour, INetworkManager
|
||||
{
|
||||
private BehaviourCollector<INetworkEntity> entities = null!;
|
||||
|
||||
private static int networkIdIndex = 0;
|
||||
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
base.OnInitialize();
|
||||
|
||||
((INetworkEntity)this).SetNetworkId(networkIdIndex++);
|
||||
|
||||
entities = new(GameObject.GameManager);
|
||||
foreach (var entity in entities)
|
||||
entity.SetNetworkId(networkIdIndex++);
|
||||
|
||||
entities.OnCollected += OnCollected;
|
||||
}
|
||||
|
||||
private void OnCollected(BehaviourCollector<INetworkEntity> collector, INetworkEntity entity)
|
||||
=> entity.SetNetworkId(networkIdIndex++);
|
||||
|
||||
protected override void OnMessageReceived(NetPacketReader reader, NetPeer peer) { }
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
using Syntriax.Engine.Network.Abstract;
|
||||
|
||||
namespace Syntriax.Engine.Network;
|
||||
|
||||
public class NetworkServer : NetworkBase, INetworkServer
|
||||
{
|
||||
public string Password { get; private set; } = string.Empty;
|
||||
public int MaxConnectionCount { get; private set; } = 0;
|
||||
public int Port { get; private set; } = 8888;
|
||||
|
||||
public NetworkServer() : base()
|
||||
{
|
||||
Listener.ConnectionRequestEvent += request =>
|
||||
{
|
||||
if (Manager.ConnectedPeersCount < MaxConnectionCount)
|
||||
request.AcceptIfKey(Password);
|
||||
else
|
||||
request.Reject();
|
||||
};
|
||||
}
|
||||
|
||||
public void Start(int port, int maxConnectionCount, string? password = null)
|
||||
{
|
||||
Password = password ?? string.Empty;
|
||||
MaxConnectionCount = maxConnectionCount;
|
||||
Port = port;
|
||||
|
||||
Manager.Start(port);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue