Oprava spawnování monster, optimalizace v CommandProcessor a EventProcessor. Přesunutí některých tříd do vlastních namespaců, pročištění kódu, úpravy formátování, odstranění nepoužívaných souborů a zakomentovaného kódu
This commit is contained in:
parent
e5d746d597
commit
243f071a43
62 changed files with 873 additions and 1217 deletions
139
ONDServer/Net/CommandProcessor.cs
Normal file
139
ONDServer/Net/CommandProcessor.cs
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
using ONDServer.Map;
|
||||
using PacketLib;
|
||||
|
||||
namespace ONDServer.Net;
|
||||
|
||||
public static class CommandProcessor {
|
||||
private static readonly Dictionary<int, Action<ServerPlayer, PlayerCommand>> commandHandlers = new(){
|
||||
[0] = (p, c) => SwitchCamera(p, c.Args[0]),
|
||||
[1] = (p, c) => SetMonitorState(p, c.Args[0] == 1),
|
||||
[2] = (p, c) => SetDoorStateOffice(p, c.Args[0], c.Args[1] == 1),
|
||||
[3] = (p, c) => SetDoorStateRemote(p.State.Pid, (c.Args[0], c.Args[1]), c.Args[2] == 1),
|
||||
[4] = (p, c) => SetLightState(p, c.Args[0], c.Args[1] == 1)
|
||||
};
|
||||
|
||||
public static void Evaluate(PlayerCommand[] commands, int pid) {
|
||||
ServerPlayer currentPlayer = Server.Players[pid];
|
||||
|
||||
foreach (var playerCommand in commands){
|
||||
commandHandlers[playerCommand.Id](currentPlayer, playerCommand);
|
||||
// switch (playerCommand.ID){
|
||||
// case 0:
|
||||
// Console.WriteLine($"C: Player {pid} switched to camera {playerCommand.Args[0]}");
|
||||
// currentPlayer.state.camera = playerCommand.Args[0];
|
||||
// Server.SendUpdateToAll([GameEvent.SWITCH_CAM(pid, playerCommand.Args[0])]);
|
||||
// break;
|
||||
// case 1:
|
||||
// bool monitorState = playerCommand.Args[0] == 1;
|
||||
// currentPlayer.state.monitorUp = monitorState;
|
||||
// Console.WriteLine($"C: Player {pid} toggled camera {(monitorState ? "on" : "off")}");
|
||||
// Server.SendUpdateToAll([GameEvent.TOGGLE_MONITOR(pid, monitorState)]);
|
||||
// break;
|
||||
// case 2:
|
||||
// bool doorState = playerCommand.Args[1] == 1;
|
||||
// currentPlayer.state.doorStates[playerCommand.Args[0]] = doorState;
|
||||
// TileConnector? officeDoor = MapManager.Get(currentPlayer.state.officeTileId).GetConnector(currentPlayer.state.neighbouringTiles[playerCommand.Args[0]]);
|
||||
// officeDoor.Blocked = doorState;
|
||||
//
|
||||
// if (doorState){
|
||||
// GameLogic.PowerConsumers[officeDoor] = (GameLogic.OfficeDoorUsage, pid);
|
||||
// }
|
||||
// else{
|
||||
// GameLogic.PowerConsumers.Remove(officeDoor);
|
||||
// }
|
||||
//
|
||||
// Console.WriteLine($"C: Player {pid} {(doorState ? "closed" : "opened")} door {playerCommand.Args[0]}");
|
||||
// Server.SendUpdateToAll([GameEvent.TOGGLE_DOOR_OFFICE(pid,playerCommand.Args[0] ,doorState)]);
|
||||
// break;
|
||||
// case 3:
|
||||
// TileConnector? door = MapManager.Get(playerCommand.Args[0]).GetConnector(playerCommand.Args[1]);
|
||||
// if(door == null) return;
|
||||
//
|
||||
// door.Blocked = playerCommand.Args[2] == 1;
|
||||
// if (door.Blocked){
|
||||
// GameLogic.PowerConsumers[door] = (GameLogic.RemoteDoorUsage, pid);
|
||||
// }
|
||||
// else{
|
||||
// GameLogic.PowerConsumers.Remove(door);
|
||||
// }
|
||||
//
|
||||
// Console.WriteLine($"C: Player {pid} {(door.Blocked ? "closed" : "opened")} door {(playerCommand.Args[0], playerCommand.Args[1])}");
|
||||
// Server.SendUpdateToAll([GameEvent.TOGGLE_DOOR_REMOTE(pid, (playerCommand.Args[0], playerCommand.Args[1]), door.Blocked)]);
|
||||
// break;
|
||||
// case 4:
|
||||
// bool lit = playerCommand.Args[1] == 1;
|
||||
// MapTile lightTile = MapManager.Get(playerCommand.Args[0]);
|
||||
// lightTile.Lit = lit;
|
||||
// if (lit){
|
||||
// GameLogic.PowerConsumers[lightTile] = (GameLogic.LightUsage, pid);
|
||||
// }
|
||||
// else{
|
||||
// GameLogic.PowerConsumers.Remove(lightTile);
|
||||
// }
|
||||
//
|
||||
// Server.SendUpdateToAll([GameEvent.TOGGLE_LIGHT(pid, playerCommand.Args[0], lit)]);
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
private static void SwitchCamera(ServerPlayer currentPlayer, int cameraId) {
|
||||
if (MapManager.TryGet(cameraId) == null || Server.Players.Values.Any(p => p.State.OfficeTileId == cameraId)) return;
|
||||
Console.WriteLine($"C: Player {currentPlayer.State.Pid} switched to camera {cameraId}");
|
||||
currentPlayer.State.Camera = cameraId;
|
||||
Server.SendUpdateToAll([GameEvent.SWITCH_CAM(currentPlayer.State.Pid, cameraId)]);
|
||||
}
|
||||
private static void SetMonitorState(ServerPlayer currentPlayer, bool monitorState) {
|
||||
currentPlayer.State.MonitorUp = monitorState;
|
||||
Console.WriteLine($"C: Player {currentPlayer.State.Pid} toggled camera {(monitorState ? "on" : "off")}");
|
||||
Server.SendUpdateToAll([GameEvent.TOGGLE_MONITOR(currentPlayer.State.Pid, monitorState)]);
|
||||
}
|
||||
|
||||
private static void SetDoorStateOffice(ServerPlayer currentPlayer, int doorId, bool doorState) {
|
||||
if (doorId < 0 || currentPlayer.State.DoorStates.Length <= doorId) return;
|
||||
currentPlayer.State.DoorStates[doorId] = doorState;
|
||||
TileConnector? officeDoor = MapManager.Get(currentPlayer.State.OfficeTileId).GetConnector(currentPlayer.State.NeighbouringTiles[doorId]);
|
||||
if (officeDoor == null) return;
|
||||
officeDoor.Blocked = doorState;
|
||||
|
||||
if (doorState){
|
||||
GameLogic.PowerConsumers[officeDoor] = (GameLogic.OfficeDoorUsage, currentPlayer.State.Pid);
|
||||
}
|
||||
else{
|
||||
GameLogic.PowerConsumers.Remove(officeDoor);
|
||||
}
|
||||
|
||||
Console.WriteLine($"C: Player {currentPlayer.State.Pid} {(doorState ? "closed" : "opened")} door {doorId}");
|
||||
Server.SendUpdateToAll([GameEvent.TOGGLE_DOOR_OFFICE(currentPlayer.State.Pid, doorId ,doorState)]);
|
||||
}
|
||||
|
||||
private static void SetDoorStateRemote(int pid, (int tile1, int tile2) doorId, bool state) {
|
||||
TileConnector? door = MapManager.Get(doorId.tile1).GetConnector(doorId.tile2);
|
||||
if(door == null) return;
|
||||
|
||||
door.Blocked = state;
|
||||
if (door.Blocked){
|
||||
GameLogic.PowerConsumers[door] = (GameLogic.RemoteDoorUsage, pid);
|
||||
}
|
||||
else{
|
||||
GameLogic.PowerConsumers.Remove(door);
|
||||
}
|
||||
|
||||
Console.WriteLine($"C: Player {pid} {(door.Blocked ? "closed" : "opened")} door {doorId}");
|
||||
Server.SendUpdateToAll([GameEvent.TOGGLE_DOOR_REMOTE(pid, doorId, door.Blocked)]);
|
||||
}
|
||||
|
||||
public static void SetLightState(ServerPlayer currentPlayer, int tileId, bool state) {
|
||||
MapTile lightTile = MapManager.Get(tileId);
|
||||
lightTile.Lit = state;
|
||||
if (state){
|
||||
GameLogic.PowerConsumers[lightTile] = (GameLogic.LightUsage, currentPlayer.State.Pid);
|
||||
}
|
||||
else{
|
||||
GameLogic.PowerConsumers.Remove(lightTile);
|
||||
}
|
||||
|
||||
Server.SendUpdateToAll([GameEvent.TOGGLE_LIGHT(currentPlayer.State.Pid, tileId, state)]);
|
||||
}
|
||||
|
||||
}
|
||||
194
ONDServer/Net/Server.cs
Normal file
194
ONDServer/Net/Server.cs
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
using System.Diagnostics;
|
||||
using GlobalClassLib;
|
||||
using LiteNetLib;
|
||||
using LiteNetLib.Utils;
|
||||
using PacketLib;
|
||||
|
||||
namespace ONDServer.Net;
|
||||
|
||||
public static class Server {
|
||||
public static ServerPlayer P1;
|
||||
public static ServerPlayer P2;
|
||||
public static readonly Dictionary<int, ServerPlayer> Players = new();
|
||||
public static ServerPlayer OtherPlayer(ServerPlayer player) => player.State.Pid == P1.State.Pid ? P2 : P1;
|
||||
|
||||
public static bool AutoStop{ get; set; } = true;
|
||||
|
||||
private static EventBasedNetListener listener;
|
||||
private static NetManager server;
|
||||
|
||||
private const int TARGET_TICK_RATE = 30;
|
||||
private const double TARGET_DELTA_TIME = 1.0 / TARGET_TICK_RATE;
|
||||
private const long TARGET_TICK_TIME_MS = 1000 / TARGET_TICK_RATE;
|
||||
|
||||
private static NetDataWriter writer;
|
||||
private static NetPacketProcessor processor;
|
||||
|
||||
private static bool isRunning;
|
||||
|
||||
// AI generated
|
||||
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 += OnPeerDisconnected;
|
||||
|
||||
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, int 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, int pid) {
|
||||
SendPacket(new UpdatePlayerPacket{Events = gevents}, pid);
|
||||
|
||||
}
|
||||
|
||||
public static void SendUpdateToAll(GameEvent[] gevents) {
|
||||
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[peer.Id] = new ServerPlayer {
|
||||
Peer = peer,
|
||||
State = new PlayerState(peer.Id, GameLogic.START_CAMERA, [false, false, false],
|
||||
Power.MAX_POWER_VALUE, false),
|
||||
Username = packet.Username
|
||||
});
|
||||
|
||||
|
||||
if (Players.Count == 1){
|
||||
newPlayer.State.OfficeTileId = 10;
|
||||
newPlayer.State.NeighbouringTiles = [5, 11, 15];
|
||||
SendPacket(new JoinAcceptPacket { State = newPlayer.State }, peer);
|
||||
P1 = newPlayer;
|
||||
}
|
||||
else{
|
||||
newPlayer.State.OfficeTileId = 14;
|
||||
newPlayer.State.NeighbouringTiles = [19, 13, 9];
|
||||
|
||||
SendPacket(new JoinAcceptPacket { State = newPlayer.State }, peer);
|
||||
P2 = newPlayer;
|
||||
|
||||
SendPacket(new OpponentInitPacket{State = newPlayer.State, Username = newPlayer.Username}, P1.Peer);
|
||||
SendPacket(new OpponentInitPacket{State = P1.State, Username = P1.Username}, P2.Peer);
|
||||
GameLogic.Init();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void OnNetworkReceive(NetPeer peer, NetPacketReader reader, DeliveryMethod deliveryMethod) {
|
||||
processor.ReadAllPackets(reader, peer);
|
||||
}
|
||||
|
||||
public static void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo) {
|
||||
if (Players.Count == 2){
|
||||
GameLogic.DeclareWinner(OtherPlayer(Players.Values.First(p => Equals(p.Peer, peer))));
|
||||
}
|
||||
|
||||
Players.Remove(peer.Id);
|
||||
if (Players.Count == 0){
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
|
||||
public static void OnCommandReceived(PlayerCommandPacket packet, NetPeer peer) {
|
||||
CommandProcessor.Evaluate(packet.Commands, peer.Id);
|
||||
}
|
||||
|
||||
public static void Update() {
|
||||
server.PollEvents();
|
||||
GameLogic.Update();
|
||||
}
|
||||
|
||||
// AI generated
|
||||
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 >= TARGET_TICK_TIME_MS)
|
||||
{
|
||||
Update();
|
||||
|
||||
previousTicks = currentTicks;
|
||||
if (elapsed > TARGET_TICK_TIME_MS * 2)
|
||||
{
|
||||
Console.WriteLine($"Warning: Tick took {elapsed}ms (target: {TARGET_TICK_TIME_MS}ms)");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
int sleepTime = (int)(TARGET_TICK_TIME_MS - elapsed - 2);
|
||||
if (sleepTime > 0)
|
||||
{
|
||||
Thread.Sleep(sleepTime);
|
||||
}
|
||||
|
||||
while (stopwatch.ElapsedMilliseconds - previousTicks < TARGET_TICK_TIME_MS){
|
||||
Thread.SpinWait(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Stop()
|
||||
{
|
||||
isRunning = false;
|
||||
server.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
10
ONDServer/Net/ServerPlayer.cs
Normal file
10
ONDServer/Net/ServerPlayer.cs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
using LiteNetLib;
|
||||
using PacketLib;
|
||||
|
||||
namespace ONDServer.Net;
|
||||
|
||||
public class ServerPlayer {
|
||||
public NetPeer Peer;
|
||||
public PlayerState State;
|
||||
public string Username;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue