Compare commits
	
		
			30 Commits
		
	
	
		
			main
			...
			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 | 
@@ -10,9 +10,9 @@
 | 
				
			|||||||
      "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}/bin/Debug/net8.0/${workspaceFolderBasename}.dll",
 | 
					      "program": "${workspaceFolder}/Game/bin/Debug/net8.0/Game.dll",
 | 
				
			||||||
      "args": [],
 | 
					      "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
									
								
								Game/.vscode/tasks.json → .vscode/tasks.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								Game/.vscode/tasks.json → .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: 5d897f2f56...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);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -2,8 +2,13 @@ using System;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
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.Abstract;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Pong.Behaviours;
 | 
					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 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()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -26,23 +32,33 @@ public class PaddleBehaviour(Keys Up, Keys Down, float High, float Low, float Sp
 | 
				
			|||||||
            return;
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (isUpPressed)
 | 
					        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)
 | 
					        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));
 | 
					        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()
 | 
				
			||||||
@@ -54,8 +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;
 | 
					    private void UpdateNetwork()
 | 
				
			||||||
    private void OnUpReleased(IButtonInputs<Keys> inputs, Keys keys) => isUpPressed = false;
 | 
					    {
 | 
				
			||||||
    private void OnDownPressed(IButtonInputs<Keys> inputs, Keys keys) => isDownPressed = true;
 | 
					        NetDataWriter netDataWriter = communicator.GetEntityWriter(this);
 | 
				
			||||||
    private void OnDownReleased(IButtonInputs<Keys> inputs, Keys keys) => isDownPressed = false;
 | 
					        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 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.
										
									
								
							@@ -21,6 +21,7 @@
 | 
				
			|||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
  <ItemGroup>
 | 
					  <ItemGroup>
 | 
				
			||||||
    <PackageReference Include="Apos.Shapes" Version="0.2.3" />
 | 
					    <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.Framework.DesktopGL" Version="3.8.1.303" />
 | 
				
			||||||
    <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.303" />
 | 
					    <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.303" />
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,19 @@
 | 
				
			|||||||
using System;
 | 
					using System;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using Microsoft.Xna.Framework;
 | 
					using Microsoft.Xna.Framework;
 | 
				
			||||||
using Microsoft.Xna.Framework.Graphics;
 | 
					using Microsoft.Xna.Framework.Graphics;
 | 
				
			||||||
using Microsoft.Xna.Framework.Input;
 | 
					using Microsoft.Xna.Framework.Input;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using Pong.Behaviours;
 | 
					 | 
				
			||||||
using Apos.Shapes;
 | 
					using Apos.Shapes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Pong.Behaviours;
 | 
				
			||||||
 | 
					using Syntriax.Engine.Network;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using Syntriax.Engine.Core;
 | 
					using Syntriax.Engine.Core;
 | 
				
			||||||
using Syntriax.Engine.Core.Abstract;
 | 
					using Syntriax.Engine.Core.Abstract;
 | 
				
			||||||
using Syntriax.Engine.Physics2D;
 | 
					using Syntriax.Engine.Physics2D;
 | 
				
			||||||
using Syntriax.Engine.Physics2D.Primitives;
 | 
					 | 
				
			||||||
using Syntriax.Engine.Physics2D.Abstract;
 | 
					using Syntriax.Engine.Physics2D.Abstract;
 | 
				
			||||||
 | 
					using Syntriax.Engine.Physics2D.Primitives;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Pong;
 | 
					namespace Pong;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -22,8 +25,9 @@ public class GamePong : Game
 | 
				
			|||||||
    private ShapeBatch shapeBatch = null!;
 | 
					    private ShapeBatch shapeBatch = null!;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private GameManager gameManager = null!;
 | 
					    private GameManager gameManager = null!;
 | 
				
			||||||
    private BehaviourCacher<IDisplayableSprite> displayableCacher = null!;
 | 
					    private BehaviourCollector<IDisplayableSprite> displayableCollector = null!;
 | 
				
			||||||
    private BehaviourCacher<IDisplayableShape> displayableShapeCacher = 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!;
 | 
				
			||||||
@@ -47,9 +51,12 @@ public class GamePong : Game
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        // TODO: Add your initialization logic here
 | 
					        // TODO: Add your initialization logic here
 | 
				
			||||||
        gameManager = new();
 | 
					        gameManager = new();
 | 
				
			||||||
        displayableCacher = new(gameManager);
 | 
					        displayableCollector = new(gameManager);
 | 
				
			||||||
        displayableShapeCacher = new(gameManager);
 | 
					        displayableShapeCollector = new(gameManager);
 | 
				
			||||||
        physicsEngine = new PhysicsEngine2DCacher(gameManager) { IterationPerStep = 3 };
 | 
					        monoGameContentLoaderCollector = new(gameManager);
 | 
				
			||||||
 | 
					        physicsEngine = new PhysicsEngine2DCollector(gameManager) { IterationPerStep = 3 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        monoGameContentLoaderCollector.OnCollected += (_, cached) => cached.LoadContent(Content);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        gameManager.Initialize();
 | 
					        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>();
 | 
					        gameObjectCamera.BehaviourController.AddBehaviour<CameraController>();
 | 
				
			||||||
        cameraBehaviour = gameObjectCamera.BehaviourController.AddBehaviour<MonoGameCamera2DBehaviour>(graphics);
 | 
					        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 = 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.Transform.SetTransform(position: new Vector2D(0, 0f), scale: new Vector2D(10f, 10f));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        gameObjectBall.BehaviourController.AddBehaviour<CircleBehaviour>(new Circle(Vector2D.Zero, 1f));
 | 
					        gameObjectBall.BehaviourController.AddBehaviour<CircleBehaviour>(new Circle(Vector2D.Zero, 1f));
 | 
				
			||||||
        gameObjectBall.BehaviourController.AddBehaviour<BallBehaviour>();
 | 
					        gameObjectBall.BehaviourController.AddBehaviour<BallBehaviour>().Id = "ball";
 | 
				
			||||||
        gameObjectBall.BehaviourController.AddBehaviour<RigidBody2D>();
 | 
					        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.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<ShapeBehaviour>(Shape.Box);
 | 
				
			||||||
        gameObjectLeftPaddle.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
 | 
					        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.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<ShapeBehaviour>(Shape.Box);
 | 
				
			||||||
        gameObjectRightPaddle.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
 | 
					        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.Transform.SetTransform(position: new Vector2D(0f, 308f), scale: new Vector2D(552f, 20f));
 | 
				
			||||||
        gameObjectWallTop.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
 | 
					        gameObjectWallTop.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
 | 
				
			||||||
        gameObjectWallTop.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
 | 
					        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.Transform.SetTransform(position: new Vector2D(0f, -308f), scale: new Vector2D(552f, 20f));
 | 
				
			||||||
        gameObjectWallBottom.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
 | 
					        gameObjectWallBottom.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
 | 
				
			||||||
        gameObjectWallBottom.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
 | 
					        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.Transform.SetTransform(position: new Vector2D(532f, 0f), scale: new Vector2D(20f, 328f));
 | 
				
			||||||
        gameObjectWallRight.BehaviourController.AddBehaviour<WallScoreBehaviour>((Action)pongManager.ScoreToLeft);
 | 
					        gameObjectWallRight.BehaviourController.AddBehaviour<WallScoreBehaviour>((Action)pongManager.ScoreToLeft);
 | 
				
			||||||
        gameObjectWallRight.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
 | 
					        gameObjectWallRight.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
 | 
				
			||||||
        gameObjectWallRight.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true;
 | 
					        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.Transform.SetTransform(position: new Vector2D(-532f, 0f), scale: new Vector2D(20f, 328f));
 | 
				
			||||||
        gameObjectWallLeft.BehaviourController.AddBehaviour<WallScoreBehaviour>((Action)pongManager.ScoreToRight);
 | 
					        gameObjectWallLeft.BehaviourController.AddBehaviour<WallScoreBehaviour>((Action)pongManager.ScoreToRight);
 | 
				
			||||||
        gameObjectWallLeft.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box);
 | 
					        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.Transform.SetTransform(position: new Vector2D(-250f, 250f), scale: Vector2D.One * .25f);
 | 
				
			||||||
        gameObjectLeftScoreText.BehaviourController.AddBehaviour<TextScoreBehaviour>(true, spriteFont);
 | 
					        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.Transform.SetTransform(position: new Vector2D(250f, 250f), scale: Vector2D.One * .25f);
 | 
				
			||||||
        gameObjectRightScoreText.BehaviourController.AddBehaviour<TextScoreBehaviour>(false, spriteFont);
 | 
					        gameObjectRightScoreText.BehaviourController.AddBehaviour<TextScoreBehaviour>(false, spriteFont);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -154,12 +186,12 @@ public class GamePong : Game
 | 
				
			|||||||
        gameManager.PreDraw();
 | 
					        gameManager.PreDraw();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        spriteBatch.Begin(SpriteSortMode.Deferred, transformMatrix: cameraBehaviour.MatrixTransform);
 | 
					        spriteBatch.Begin(SpriteSortMode.Deferred, transformMatrix: cameraBehaviour.MatrixTransform);
 | 
				
			||||||
        foreach (var displayable in displayableCacher)
 | 
					        foreach (var displayable in displayableCollector)
 | 
				
			||||||
            displayable.Draw(spriteBatch);
 | 
					            displayable.Draw(spriteBatch);
 | 
				
			||||||
        spriteBatch.End();
 | 
					        spriteBatch.End();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        shapeBatch.Begin(cameraBehaviour.MatrixTransform);
 | 
					        shapeBatch.Begin(cameraBehaviour.MatrixTransform);
 | 
				
			||||||
        foreach (var displayableShape in displayableShapeCacher)
 | 
					        foreach (var displayableShape in displayableShapeCollector)
 | 
				
			||||||
            displayableShape.Draw(shapeBatch);
 | 
					            displayableShape.Draw(shapeBatch);
 | 
				
			||||||
        shapeBatch.End();
 | 
					        shapeBatch.End();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										18
									
								
								Game/Network/Abstract/INetworkBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								Game/Network/Abstract/INetworkBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								Game/Network/Abstract/INetworkClient.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Game/Network/Abstract/INetworkClient.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					namespace Syntriax.Engine.Network.Abstract;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public interface INetworkClient : INetworkCommunicator
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    void Connect(string address, int port, string? password = null);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										22
									
								
								Game/Network/Abstract/INetworkCommunicator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								Game/Network/Abstract/INetworkCommunicator.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								Game/Network/Abstract/INetworkEntity.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Game/Network/Abstract/INetworkEntity.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										10
									
								
								Game/Network/Abstract/INetworkManager.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Game/Network/Abstract/INetworkManager.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										10
									
								
								Game/Network/Abstract/INetworkServer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Game/Network/Abstract/INetworkServer.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										81
									
								
								Game/Network/NetworkBase.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								Game/Network/NetworkBase.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										99
									
								
								Game/Network/NetworkBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								Game/Network/NetworkBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								Game/Network/NetworkClient.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								Game/Network/NetworkClient.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										20
									
								
								Game/Network/NetworkExtensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								Game/Network/NetworkExtensions.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										31
									
								
								Game/Network/NetworkManager.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								Game/Network/NetworkManager.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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) { }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										30
									
								
								Game/Network/NetworkServer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								Game/Network/NetworkServer.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user