using System; using System.Linq; using System.Net; using System.Net.Sockets; using System.Threading; using FNAF_Clone.GUI; using FNAF_Clone.Map; using GlobalClassLib; using LiteNetLib; using LiteNetLib.Utils; using PacketLib; namespace FNAF_Clone; public class Client { public enum ConnectionState { IDLE, CONNECTING, CONNECTED, ACCEPTED, GAME_STARTING, GAME_IN_PROGRESS, SERVER_NOT_FOUND, SERVER_FULL, ERROR } public static ConnectionState State { get; private set; } = ConnectionState.IDLE; private static EventBasedNetListener listener = new(); private static NetManager client; private static NetPeer server; private static NetDataWriter writer; private static NetPacketProcessor processor; public static ClientPlayer Player { get; } = new(); public static ClientPlayer Opponent { get; } = new(); public static ClientPlayer GetPlayer(int pid) => Player.state.pid == pid ? Player : Opponent; public static void Connect(string endPoint, int port) { State = ConnectionState.CONNECTING; writer = new NetDataWriter(); processor = new NetPacketProcessor(); NestedTypeManager.AutoRegister(processor); processor.SubscribeReusable(OnJoinAccept); processor.SubscribeReusable(OnPlayerUpdate); processor.SubscribeReusable(OnMapInit); processor.SubscribeReusable(packet => { // TODO: move this to a method Opponent.state = packet.state; Opponent.username = packet.username; State = ConnectionState.GAME_STARTING; }); client = new NetManager(listener){ AutoRecycle = true }; client.Start(); Console.WriteLine($"Connecting to server @ {endPoint}:{port}"); listener.NetworkReceiveEvent += (peer, reader, channel, method) => { OnNetworkReceive(peer, reader, method); }; listener.PeerConnectedEvent += peer => { Console.WriteLine("Connected to Server"); server = peer; State = ConnectionState.CONNECTED; SendPacket(new JoinPacket {username = Player.username == "" ? "Anonymous" : Player.username}, DeliveryMethod.ReliableOrdered); }; new Thread(() => client.Connect(endPoint, port, "")).Start(); // TODO: figure out how keys work } public static void SendPacket(T packet, DeliveryMethod deliveryMethod) where T : class, new() { if (server != null) { writer.Reset(); processor.Write(writer, packet); server.Send(writer, deliveryMethod); } } public static void SendCommands(PlayerCommand[] pCommands) { SendPacket(new PlayerCommandPacket{commands = pCommands}, DeliveryMethod.ReliableOrdered); } private static void OnNetworkReceive(NetPeer peer, NetPacketReader reader, DeliveryMethod deliveryMethod) { processor.ReadAllPackets(reader, peer); } private static void OnJoinAccept(JoinAcceptPacket packet) { Console.WriteLine($"Accepted by server, pid: {packet.state.pid}"); State = ConnectionState.ACCEPTED; Player.state = packet.state; } private static void OnMapInit(MapInitPacket packet) { (int id1, int id2, ConnectorType type)[] connectorsData = new (int id1, int id2, ConnectorType type)[packet.Connectors.Length / 3]; for (int i = 0; i < packet.Connectors.Length / 3; i++){ connectorsData[i] = (packet.Connectors[i * 3], packet.Connectors[i * 3 + 1], (ConnectorType)packet.Connectors[i * 3 + 2]); } ClientMapManager.InitMap(packet.UpsideDown); TileConnectorProjection[] connectors = connectorsData.Select(c => new TileConnectorProjection(ClientMapManager.Get(c.id1), ClientMapManager.Get(c.id2), c.type)).ToArray(); ClientMapManager.InitConnectors(connectors); UIManager.SpawnMapElements(connectors.Where(c => c.Type == ConnectorType.DOOR_REMOTE).ToArray()); } public static void Update() { client.PollEvents(); } public static void OnPlayerUpdate(UpdatePlayerPacket packet) { // TODO: move this to a separate class EventProcessor.Evaluate(packet.events); //Player.state = Player.state.pid == 0 ? packet.stateP1 : packet.stateP2; } }