OneNightDuel/FNAF_Server/Server.cs

198 lines
6.5 KiB
C#
Raw Normal View History

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;
}
}