Funkční komunikace mezi jedním clientem a serverem
This commit is contained in:
commit
3f235f6e04
44 changed files with 1030 additions and 0 deletions
18
FNAF_Server/FNAF_Server.csproj
Normal file
18
FNAF_Server/FNAF_Server.csproj
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LiteNetLib" Version="1.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\PacketLib\PacketLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
12
FNAF_Server/GameLogic.cs
Normal file
12
FNAF_Server/GameLogic.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
using PacketLib;
|
||||
|
||||
namespace FNAF_Server;
|
||||
|
||||
public class GameLogic {
|
||||
|
||||
public static void Update() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
9
FNAF_Server/Program.cs
Normal file
9
FNAF_Server/Program.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace FNAF_Server;
|
||||
|
||||
public class Program {
|
||||
public static void Main(string[] args) {
|
||||
Server.Start(9012);
|
||||
}
|
||||
}
|
||||
197
FNAF_Server/Server.cs
Normal file
197
FNAF_Server/Server.cs
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using LiteNetLib;
|
||||
using LiteNetLib.Utils;
|
||||
using PacketLib;
|
||||
|
||||
namespace FNAF_Server;
|
||||
|
||||
public class Server {
|
||||
public static ServerPlayer P1;
|
||||
public static ServerPlayer P2;
|
||||
|
||||
private static EventBasedNetListener listener;
|
||||
private static NetManager server;
|
||||
|
||||
private const int TargetTickRate = 30;
|
||||
private const double TargetDeltaTime = 1.0 / TargetTickRate;
|
||||
private const long TargetTickTimeMs = 1000 / TargetTickRate;
|
||||
|
||||
private static NetDataWriter writer;
|
||||
private static NetPacketProcessor processor;
|
||||
private static Dictionary<uint, ServerPlayer> players = new();
|
||||
|
||||
private static bool isRunning;
|
||||
|
||||
public static void Start(int port) {
|
||||
writer = new NetDataWriter();
|
||||
processor = new NetPacketProcessor();
|
||||
|
||||
NestedTypeManager.AutoRegister(processor);
|
||||
|
||||
processor.SubscribeReusable<JoinPacket, NetPeer>(OnJoinReceived);
|
||||
processor.SubscribeReusable<PlayerCommandPacket, NetPeer>(OnCommandReceived);
|
||||
|
||||
listener = new EventBasedNetListener(); // ← Initialize the listener!
|
||||
|
||||
|
||||
server = new NetManager(listener){
|
||||
AutoRecycle = true
|
||||
};
|
||||
|
||||
Console.WriteLine($"Starting server on {port}");
|
||||
|
||||
listener.ConnectionRequestEvent += request => {
|
||||
Console.WriteLine($"Connection Request from {request.RemoteEndPoint}");
|
||||
if (players.Count >= 2){
|
||||
Console.WriteLine($"{request.RemoteEndPoint} denied, server full");
|
||||
return;
|
||||
}
|
||||
request.Accept();
|
||||
};
|
||||
|
||||
listener.NetworkReceiveEvent += (peer, reader, channel, method) => {
|
||||
OnNetworkReceive(peer, reader, method);
|
||||
};
|
||||
|
||||
listener.PeerDisconnectedEvent += (peer, info) => {
|
||||
OnPeerDisconnected(peer, info);
|
||||
};
|
||||
|
||||
server.Start(port);
|
||||
|
||||
Run();
|
||||
}
|
||||
|
||||
public static void SendPacket<T>(T packet, NetPeer peer, DeliveryMethod deliveryMethod = DeliveryMethod.ReliableOrdered) where T : class, new() {
|
||||
if (peer != null) {
|
||||
writer.Reset();
|
||||
processor.Write(writer, packet);
|
||||
peer.Send(writer, deliveryMethod);
|
||||
}
|
||||
}
|
||||
public static void SendPacket<T>(T packet, uint pid, DeliveryMethod deliveryMethod = DeliveryMethod.ReliableOrdered) where T : class, new() {
|
||||
SendPacket(packet, players[pid].peer, deliveryMethod);
|
||||
}
|
||||
public static void SendPacketToAll<T>(T packet, DeliveryMethod deliveryMethod = DeliveryMethod.ReliableOrdered) where T : class, new() {
|
||||
foreach (var player in players.Values){
|
||||
SendPacket(packet, player.peer, deliveryMethod);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SendUpdate(GameEvent[] gevents, uint pid) {
|
||||
// SendPacket(new UpdatePlayerPacket{eventQueue = new EventQueue{Events = events}}, pid);
|
||||
SendPacket(new UpdatePlayerPacket{events = gevents}, pid);
|
||||
|
||||
}
|
||||
|
||||
public static void SendUpdateToAll(GameEvent[] gevents) {
|
||||
// SendPacketToAll(new UpdatePlayerPacket{eventQueue = new EventQueue{Events = events}});
|
||||
SendPacketToAll(new UpdatePlayerPacket{events = gevents});
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void OnJoinReceived(JoinPacket packet, NetPeer peer) {
|
||||
Console.WriteLine($"Received join from {packet.username} (pid: {(uint)peer.Id})");
|
||||
|
||||
ServerPlayer newPlayer = (players[(uint)peer.Id] = new ServerPlayer {
|
||||
peer = peer,
|
||||
state = new PlayerState {
|
||||
pid = (uint)peer.Id,
|
||||
camera = 0
|
||||
},
|
||||
username = packet.username
|
||||
});
|
||||
|
||||
SendPacket(new JoinAcceptPacket { state = newPlayer.state }, peer);
|
||||
|
||||
if (players.Count == 1){
|
||||
P1 = newPlayer;
|
||||
}
|
||||
else{
|
||||
P2 = newPlayer;
|
||||
}
|
||||
}
|
||||
|
||||
public static void OnNetworkReceive(NetPeer peer, NetPacketReader reader, DeliveryMethod deliveryMethod) {
|
||||
processor.ReadAllPackets(reader, peer);
|
||||
}
|
||||
|
||||
public static void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo) {
|
||||
if (peer.Tag != null) {
|
||||
players.Remove((uint)peer.Id);
|
||||
}
|
||||
}
|
||||
|
||||
public static void OnCommandReceived(PlayerCommandPacket packet, NetPeer peer) {
|
||||
PlayerCommand[] commands = packet.commands;
|
||||
|
||||
foreach (var playerCommand in commands){
|
||||
switch (playerCommand.ID){
|
||||
case 0:
|
||||
Console.WriteLine($"C: Player {peer.Id} switched to camera {playerCommand.Args[0]}");
|
||||
SendUpdateToAll([GameEvent.SWITCH_CAM(peer.Id, playerCommand.Args[0])]);
|
||||
break;
|
||||
case 1:
|
||||
bool newState = !players[(uint)peer.Id].state.monitorUp;
|
||||
players[(uint)peer.Id].state.monitorUp = newState;
|
||||
Console.WriteLine($"C: Player {peer.Id} toggled camera {(newState ? "on" : "off")}");
|
||||
SendUpdateToAll([GameEvent.TOGGLE_MONITOR(peer.Id, newState)]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Update() {
|
||||
server.PollEvents();
|
||||
// Console.WriteLine("update");
|
||||
GameLogic.Update(); // TODO: add a parameter for player input
|
||||
}
|
||||
|
||||
public static void Run(CancellationToken cancellationToken = default)
|
||||
{
|
||||
isRunning = true;
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
long previousTicks = 0;
|
||||
|
||||
while (isRunning && !cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
long currentTicks = stopwatch.ElapsedMilliseconds;
|
||||
long elapsed = currentTicks - previousTicks;
|
||||
|
||||
if (elapsed >= TargetTickTimeMs)
|
||||
{
|
||||
Update();
|
||||
|
||||
previousTicks = currentTicks;
|
||||
if (elapsed > TargetTickTimeMs * 2)
|
||||
{
|
||||
Console.WriteLine($"Warning: Tick took {elapsed}ms (target: {TargetTickTimeMs}ms)");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
int sleepTime = (int)(TargetTickTimeMs - elapsed - 2);
|
||||
if (sleepTime > 0)
|
||||
{
|
||||
Thread.Sleep(sleepTime);
|
||||
}
|
||||
|
||||
while (stopwatch.ElapsedMilliseconds - previousTicks < TargetTickTimeMs){
|
||||
Thread.SpinWait(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Stop()
|
||||
{
|
||||
isRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
10
FNAF_Server/ServerPlayer.cs
Normal file
10
FNAF_Server/ServerPlayer.cs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
using LiteNetLib;
|
||||
using PacketLib;
|
||||
|
||||
namespace FNAF_Server;
|
||||
|
||||
public class ServerPlayer {
|
||||
public NetPeer peer;
|
||||
public PlayerState state;
|
||||
public string username;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue