diff --git a/FNAF_Clone.sln.DotSettings.user b/FNAF_Clone.sln.DotSettings.user index 6fd933d..f8595f6 100644 --- a/FNAF_Clone.sln.DotSettings.user +++ b/FNAF_Clone.sln.DotSettings.user @@ -5,4 +5,7 @@ ForceIncluded ForceIncluded ForceIncluded - ForceIncluded \ No newline at end of file + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded \ No newline at end of file diff --git a/FNAF_Clone/Client.cs b/FNAF_Clone/Client.cs index 6a7a344..3fa6d5c 100644 --- a/FNAF_Clone/Client.cs +++ b/FNAF_Clone/Client.cs @@ -19,7 +19,9 @@ public class Client { 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) { writer = new NetDataWriter(); @@ -30,6 +32,7 @@ public class Client { processor.SubscribeReusable(OnJoinAccept); processor.SubscribeReusable(OnPlayerUpdate); processor.SubscribeReusable(OnMapInit); + processor.SubscribeReusable(packet => Opponent.state = packet.state); client = new NetManager(listener){ AutoRecycle = true @@ -76,10 +79,13 @@ public class Client { 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(); + 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.InitUI(); UIManager.SpawnDoors(connectors.Where(c => c.Type == ConnectorType.DOOR_REMOTE).ToArray()); + } public static void Update() { @@ -87,43 +93,10 @@ public class Client { } 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; - foreach (var e in packet.events){ - switch (e.ID){ - case 0: // join - Console.WriteLine("E: Player joined"); - break; - case 1: // leave - Console.WriteLine("E: Player left"); - break; - case 2: // switch cam - if (Player.state.pid != e.Args[0]) return; - if (Player.state.camera != e.Args[1]) Console.WriteLine("!!! DESYNC: CAMERA STATE"); - Console.WriteLine($"E: player {e.Args[0]} switched to camera {e.Args[1]}"); - break; - case 3: // toggle cam - if (Player.state.monitorUp != (e.Args[1] == 1)) Console.WriteLine("!!! DESYNC: MONITOR STATE"); - - UIManager.ChangeMonitorState(e.Args[1] == 1); - Console.WriteLine($"E: Player {e.Args[0]} toggled monitor {(e.Args[1] == 0 ? "off" : "on")}"); - break; - case 4: // toggle door - if (Player.state.doorStates[e.Args[1]] != (e.Args[2] == 1)) Console.WriteLine("!!! DESYNC: DOOR STATE"); - - // UIManager.ChangeDoorState((Direction)e.Args[1], e.Args[2] == 1); - Console.WriteLine($"E: Player {e.Args[0]} {(e.Args[2] == 1 ? "closed" : "opened")} door {e.Args[1]}"); - break; - case 5: // toggle remote door - if (ClientMapManager.GetConnector((e.Args[1], e.Args[2])).Blocked != (e.Args[3] == 1)) Console.WriteLine("!!! DESYNC: REMOTE DOOR STATE"); - Console.WriteLine($"E: Player {e.Args[0]} {(e.Args[3] == 1 ? "closed" : "opened")} door {e.Args[1]}-{e.Args[2]}"); - break; - case -1: // movement - throw new NotImplementedException(); - - } - } + } diff --git a/FNAF_Clone/CommandManager.cs b/FNAF_Clone/CommandManager.cs index f817e3b..11ccf8f 100644 --- a/FNAF_Clone/CommandManager.cs +++ b/FNAF_Clone/CommandManager.cs @@ -27,6 +27,7 @@ public class CommandManager { private static void SendToggleCamera() { Client.Player.state.monitorUp = !Client.Player.state.monitorUp; + UIManager.ChangeMonitorState(Client.Player.state.monitorUp); Client.SendCommands([PlayerCommand.SET_MONITOR(Client.Player.state.monitorUp)]); } diff --git a/FNAF_Clone/EventProcessor.cs b/FNAF_Clone/EventProcessor.cs new file mode 100644 index 0000000..ca216b4 --- /dev/null +++ b/FNAF_Clone/EventProcessor.cs @@ -0,0 +1,64 @@ +using System; +using FNAF_Clone.GUI; +using FNAF_Clone.Map; +using GlobalClassLib; +using PacketLib; + +namespace FNAF_Clone; + +public class EventProcessor { + public static void Evaluate(GameEvent[] events) { + foreach (var e in events){ + switch (e.ID){ + case 0: // join + Console.WriteLine("E: Player joined"); + break; + + case 1: // leave + Console.WriteLine("E: Player left"); + break; + + case 2: // switch cam + if (Client.Player.state.pid != e.Args[0]) return; + if (Client.Player.state.camera != e.Args[1]) Console.WriteLine("!!! DESYNC: CAMERA STATE"); + Console.WriteLine($"E: player {e.Args[0]} switched to camera {e.Args[1]}"); + break; + + case 3: // toggle cam + if (e.Args[0] == Client.Player.state.pid && Client.Player.state.monitorUp != (e.Args[1] == 1)) Console.WriteLine("!!! DESYNC: MONITOR STATE"); + + // UIManager.ChangeMonitorState(e.Args[1] == 1); + Console.WriteLine($"E: Player {e.Args[0]} toggled monitor {(e.Args[1] == 0 ? "off" : "on")}"); + break; + + case 4: // toggle door + Console.WriteLine($"E: Player {e.Args[0]} {(e.Args[2] == 1 ? "closed" : "opened")} door {e.Args[1]}"); + + if (e.Args[0] == Client.Player.state.pid){ + if (Client.Player.state.doorStates[e.Args[1]] != (e.Args[2] == 1)) Console.WriteLine("!!! DESYNC: DOOR STATE"); + break; + } + + Client.Opponent.state.doorStates[e.Args[1]] = e.Args[2] == 1; + UIManager.ChangeDoorStateOpponent((Direction)e.Args[1], e.Args[2] == 1); + break; + + case 5: // toggle remote door + Console.WriteLine($"E: Player {e.Args[0]} {(e.Args[3] == 1 ? "closed" : "opened")} door {e.Args[1]}-{e.Args[2]}"); + + if (e.Args[0] == Client.Player.state.pid){ + if (ClientMapManager.GetConnector((e.Args[1], e.Args[2])).Blocked != (e.Args[3] == 1)) Console.WriteLine("!!! DESYNC: REMOTE DOOR STATE"); + break; + } + + ClientMapManager.GetConnector((e.Args[1], e.Args[2])).Blocked = e.Args[3] == 1; + UIManager.ChangeRemoteDoorState((e.Args[1], e.Args[2]), e.Args[3] == 1); + break; + + case -1: // movement + throw new NotImplementedException(); + + } + } + } +} \ No newline at end of file diff --git a/FNAF_Clone/GUI/Screen.cs b/FNAF_Clone/GUI/Screen.cs index 69d1b12..1b29afe 100644 --- a/FNAF_Clone/GUI/Screen.cs +++ b/FNAF_Clone/GUI/Screen.cs @@ -9,8 +9,8 @@ namespace FNAF_Clone.GUI; public class Screen { public static Dictionary Screens = new(); - public static Screen CurrentScreen{ get; private set; } - + public static Screen CurrentScreen{ get; private set; } = Empty; + public static void AddScreens(Screen[] screens) { foreach (var screen in screens){ Screens.Add(screen.Label, screen); @@ -33,6 +33,8 @@ public class Screen { Screens.Remove(id); } + public static Screen Empty => new(""); + public string Label; private Dictionary elements = new(); diff --git a/FNAF_Clone/GUI/UIManager.cs b/FNAF_Clone/GUI/UIManager.cs index 4ad81ab..aae5c2b 100644 --- a/FNAF_Clone/GUI/UIManager.cs +++ b/FNAF_Clone/GUI/UIManager.cs @@ -55,8 +55,8 @@ public class UIManager { int j1 = j; Point point1 = new Point(336 + (32 * i), 144 + (32 * j)); Point point2 = new Point(367 + (32 * i), 175 + (32 * j)); - monitorScreen.AddElement($"room{MapTileProjection.CoordsToId(i, 4 - j)}", new UIElement(point1, point2) - {Pressable = true, OnMousePress = (() => CommandManager.SendChangeCamera(MapTileProjection.CoordsToId(i1, 4 - j1)))}); + monitorScreen.AddElement($"room{ClientMapManager.CoordsToId(i, 4 - j)}", new UIElement(point1, point2) + {Pressable = true, OnMousePress = (() => CommandManager.SendChangeCamera(ClientMapManager.Get((i1, 4 - j1)).Id))}); // // if (doorPositions.ContainsKey((i, j))){ // monitorScreen.AddElement("door"+doorPositions[(i, j)], new UIElement([monitorAtlas[5], monitorAtlas[6]], point1)); @@ -75,7 +75,7 @@ public class UIManager { int targetId = door.Tiles.tile1.GridPosition.y > door.Tiles.tile2.GridPosition.y ? door.Tiles.tile1.Id : door.Tiles.tile2.Id; UIElement tile = monitorScreen["room"+targetId]; - monitorScreen.AddElement("door"+targetId+"-"+(targetId == door.Tiles.tile1.Id ? door.Tiles.tile2.Id : door.Tiles.tile1.Id), new UIElement([monitorAtlas[5], monitorAtlas[6]], tile.Bounds.Item1)); + monitorScreen.AddElement("door"+Math.Max(door.Tiles.tile1.Id, door.Tiles.tile2.Id)+"-"+Math.Min(door.Tiles.tile1.Id, door.Tiles.tile2.Id), new UIElement([monitorAtlas[5], monitorAtlas[6]], tile.Bounds.Item1)); } } @@ -87,8 +87,8 @@ public class UIManager { monitorScreen.AddElement("p2-office-door-left", new UIElement([monitorAtlas[17], monitorAtlas[18]], new Point(400, 144))); } - - public static void ChangeDoorState(Direction dir, bool state) { // TODO: make this also change for p2 + + public static void ChangeDoorState(Direction dir, bool state) { int stateInt = state ? 1 : 0; switch ((int)dir){ @@ -106,6 +106,22 @@ public class UIManager { break; } } + + public static void ChangeDoorStateOpponent(Direction dir, bool state) { // TODO: overload to avoid excessive casting + int stateInt = state ? 1 : 0; + + switch ((int)dir){ + case 0: + monitorScreen["p2-office-door-left"].SetTexture(stateInt); + break; + case 1: + monitorScreen["p2-office-door-centre"].SetTexture(stateInt); + break; + case 2: + monitorScreen["p2-office-door-right"].SetTexture(stateInt); + break; + } + } public static void ChangeRemoteDoorState((int, int) id, bool state) { monitorScreen["door"+Math.Max(id.Item1, id.Item2)+"-"+Math.Min(id.Item1, id.Item2)].SetTexture(state ? 1 : 0); diff --git a/FNAF_Clone/GameMain.cs b/FNAF_Clone/GameMain.cs index 77eccac..354264a 100644 --- a/FNAF_Clone/GameMain.cs +++ b/FNAF_Clone/GameMain.cs @@ -24,7 +24,7 @@ public class GameMain() : Core("fnafkooo", 1280, 720, false) { base.Initialize(); - UIManager.InitUI(); + // UIManager.InitUI(); } protected override void LoadContent() { diff --git a/FNAF_Clone/Map/ClientMapManager.cs b/FNAF_Clone/Map/ClientMapManager.cs index 3864fb2..87dcb4b 100644 --- a/FNAF_Clone/Map/ClientMapManager.cs +++ b/FNAF_Clone/Map/ClientMapManager.cs @@ -1,3 +1,5 @@ +using System; +using System.Runtime.InteropServices.JavaScript; using GlobalClassLib; namespace FNAF_Clone.Map; @@ -5,20 +7,29 @@ namespace FNAF_Clone.Map; public class ClientMapManager { private static MapTileProjection[,] map = new MapTileProjection[5, 5]; public static MapTileProjection Get((int x, int y) coords) => map[coords.x, coords.y]; - public static MapTileProjection Get(int tileId) => Get(MapTileProjection.IdToCoords(tileId)); - public static void InitMap() { + public static MapTileProjection Get(int tileId) => Get(IdToCoords(tileId)); + + private static bool inverted; + public static void InitMap(bool invert = false) { + inverted = invert; + + IdToCoords = invert ? _IdToCoordsInverse : _IdToCoords; + CoordsToId = invert ? _CoordsToIdInverse : _CoordsToId; + for (int i = 0; i < 5; i++){ for (int j = 0; j < 2; j++){ - map[i, j] = new MapTileProjection(MapTileProjection.CoordsToId(i, j)); // TODO: implement ownership + map[i, j] = new MapTileProjection(CoordsToId(i, j)); // TODO: implement ownership } - map[i, 2] = new MapTileProjection(MapTileProjection.CoordsToId(i, 2)); + map[i, 2] = new MapTileProjection(CoordsToId(i, 2)); for (int j = 3; j < 5; j++){ - map[i, j] = new MapTileProjection(MapTileProjection.CoordsToId(i, j)); + map[i, j] = new MapTileProjection(CoordsToId(i, j)); } } - } + + } + public static void InitConnectors(TileConnectorProjection[] connectors) { foreach (var con in connectors){ // (int x, int y) coords1 = MapTileProjection.IdToCoords(con.Tiles.tile1.Id); @@ -29,5 +40,16 @@ public class ClientMapManager { public static TileConnectorProjection GetConnector((int, int) id) => Get(id.Item1).GetConnector(id.Item2); - public static TileConnectorProjection[] GetConnectors(int tileId) => Get(MapTileProjection.IdToCoords(tileId)).GetAllConnectors(); + public static TileConnectorProjection[] GetConnectors(int tileId) => Get(IdToCoords(tileId)).GetAllConnectors(); + + + + public const int ID_X_OFFSET = 5; // map grid height + public static Func CoordsToId{ get; private set; } + public static Func IdToCoords{ get; private set; } + + private static Func _IdToCoords = id => (id / ID_X_OFFSET, id % ID_X_OFFSET); + private static Func _IdToCoordsInverse = id => (ID_X_OFFSET - 1 - (id / ID_X_OFFSET), ID_X_OFFSET - 1 - (id % ID_X_OFFSET)); + private static Func _CoordsToId = (x, y) => x * ID_X_OFFSET + y; + private static Func _CoordsToIdInverse = (x, y) => (ID_X_OFFSET - 1 - x) * ID_X_OFFSET + (ID_X_OFFSET - 1 - y); } \ No newline at end of file diff --git a/FNAF_Clone/Map/MapTileProjection.cs b/FNAF_Clone/Map/MapTileProjection.cs index f891cfd..9c425d9 100644 --- a/FNAF_Clone/Map/MapTileProjection.cs +++ b/FNAF_Clone/Map/MapTileProjection.cs @@ -3,6 +3,6 @@ using GlobalClassLib; namespace FNAF_Clone.Map; public class MapTileProjection : GlobalMapTile { - public MapTileProjection(int id) : base(id) { + public MapTileProjection(int id) : base(id, ClientMapManager.IdToCoords(id)) { } } \ No newline at end of file diff --git a/FNAF_Server/GameLogic.cs b/FNAF_Server/GameLogic.cs index c83fafe..56e62e2 100644 --- a/FNAF_Server/GameLogic.cs +++ b/FNAF_Server/GameLogic.cs @@ -18,8 +18,8 @@ public class GameLogic { connectorsConverted[i * 3 + 1] = connectors[i].Tiles.tile2.Id; connectorsConverted[i * 3 + 2] = (int)connectors[i].Type; } - Server.SendPacketToAll(new MapInitPacket{Connectors = connectorsConverted}); - + Server.SendPacket(new MapInitPacket{Connectors = connectorsConverted, UpsideDown = true}, Server.P1.peer); + Server.SendPacket(new MapInitPacket{Connectors = connectorsConverted, UpsideDown = false}, Server.P2.peer); } public static void Update() { diff --git a/FNAF_Server/Map/MapManager.cs b/FNAF_Server/Map/MapManager.cs index 5354b9c..4ad343e 100644 --- a/FNAF_Server/Map/MapManager.cs +++ b/FNAF_Server/Map/MapManager.cs @@ -6,7 +6,7 @@ public static class MapManager { private static MapTile[,] map = new MapTile[5, 5]; public static MapTile Get((int x, int y) coords) => map[coords.x, coords.y]; - public static MapTile Get(int tileId) => Get(MapTile.IdToCoords(tileId)); + public static MapTile Get(int tileId) => Get(IdToCoords(tileId)); private static Dictionary<(int x1, int y1), (int x2, int y2, int value, ConnectorType type)[]> halfConnectors = new(){ @@ -30,11 +30,11 @@ public static class MapManager { public static void InitMap() { // TODO: make map size not hardcoded for (int i = 0; i < 5; i++){ for (int j = 0; j < 2; j++){ - map[i, j] = new MapTile(MapTile.CoordsToId(i, j), null); // TODO: implement ownership + map[i, j] = new MapTile(CoordsToId(i, j), null); // TODO: implement ownership } - map[i, 2] = new MapTile(MapTile.CoordsToId(i, 2), null); + map[i, 2] = new MapTile(CoordsToId(i, 2), null); for (int j = 3; j < 5; j++){ - map[i, j] = new MapTile(MapTile.CoordsToId(i, j), null); + map[i, j] = new MapTile(CoordsToId(i, j), null); } } @@ -69,4 +69,7 @@ public static class MapManager { } + public const int ID_X_OFFSET = 5; // map grid height + public static int CoordsToId(int x, int y) => x * ID_X_OFFSET + y; + public static (int, int) IdToCoords(int id) => (id / ID_X_OFFSET, id % ID_X_OFFSET); } \ No newline at end of file diff --git a/FNAF_Server/Map/MapTile.cs b/FNAF_Server/Map/MapTile.cs index a28def2..81661b2 100644 --- a/FNAF_Server/Map/MapTile.cs +++ b/FNAF_Server/Map/MapTile.cs @@ -6,7 +6,7 @@ namespace FNAF_Server.Map; public class MapTile : GlobalMapTile { public ServerPlayer Owner{ get; private set; } - public MapTile(int id, ServerPlayer owner) : base(id) { + public MapTile(int id, ServerPlayer owner) : base(id, MapManager.IdToCoords(id)) { Owner = owner; } diff --git a/FNAF_Server/Server.cs b/FNAF_Server/Server.cs index 59c09ef..ccfb27e 100644 --- a/FNAF_Server/Server.cs +++ b/FNAF_Server/Server.cs @@ -115,14 +115,10 @@ public class Server { } else{ P2 = newPlayer; + SendPacket(new OpponentInitPacket{state = newPlayer.state}, P1.peer); + SendPacket(new OpponentInitPacket{state = P1.state}, P2.peer); + GameLogic.Init(); // TODO: move this to the condition above to wait for the other player } - - - GameLogic.Init(); // TODO: move this to the condition above to wait for the other player - - - - } public static void OnNetworkReceive(NetPeer peer, NetPacketReader reader, DeliveryMethod deliveryMethod) { diff --git a/GlobalClassLib/GlobalMapTile.cs b/GlobalClassLib/GlobalMapTile.cs index 9f682c4..dcc44fa 100644 --- a/GlobalClassLib/GlobalMapTile.cs +++ b/GlobalClassLib/GlobalMapTile.cs @@ -7,9 +7,9 @@ public abstract class GlobalMapTile where TCon : GlobalTileConnecto private List connectors = new(); - public GlobalMapTile(int id) { + public GlobalMapTile(int id, (int x, int y) gridPosition) { Id = id; - GridPosition = IdToCoords(id); + GridPosition = gridPosition; } public void AddConnector(TCon connector) { // tile1 is ignored when provided connector = connector.Clone(); @@ -41,8 +41,4 @@ public abstract class GlobalMapTile where TCon : GlobalTileConnecto public TCon[] GetAllConnectors() => connectors.ToArray(); - - public const int ID_X_OFFSET = 5; // map grid height - public static int CoordsToId(int x, int y) => x * ID_X_OFFSET + y; - public static (int, int) IdToCoords(int id) => (id / ID_X_OFFSET, id % ID_X_OFFSET); } \ No newline at end of file diff --git a/PacketLib/GameEvent.cs b/PacketLib/GameEvent.cs index 9be4def..66dbc6c 100644 --- a/PacketLib/GameEvent.cs +++ b/PacketLib/GameEvent.cs @@ -5,7 +5,7 @@ namespace PacketLib; #nullable disable public struct GameEvent : INetSerializable{ - public static GameEvent PLAYER_JOIN(int pid) => new(){ID = 0, Args = [pid] }; + public static GameEvent PLAYER_JOIN(int pid) => new(){ID = 0, Args = [pid] }; // TODO: username sync public static GameEvent PLAYER_LEAVE(int pid) => new(){ID = 1, Args = [pid] }; public static GameEvent SWITCH_CAM(int pid, int id) => new(){ID = 2, Args = [pid, id] }; public static GameEvent TOGGLE_MONITOR(int pid, bool state) => new(){ID = 3, Args = [pid, state ? 1 : 0]}; diff --git a/PacketLib/JoinAcceptPacket.cs b/PacketLib/JoinAcceptPacket.cs index 178249a..82058f2 100644 --- a/PacketLib/JoinAcceptPacket.cs +++ b/PacketLib/JoinAcceptPacket.cs @@ -2,4 +2,5 @@ namespace PacketLib; public class JoinAcceptPacket { public PlayerState state { get; set; } + // public PlayerState otherPlayerState { get; set; } } \ No newline at end of file diff --git a/PacketLib/MapInitPacket.cs b/PacketLib/MapInitPacket.cs index 4e9b5bb..f31830c 100644 --- a/PacketLib/MapInitPacket.cs +++ b/PacketLib/MapInitPacket.cs @@ -2,5 +2,5 @@ namespace PacketLib; public class MapInitPacket { public int[] Connectors { get; set; } // triplets (tile1 id, tile2 id, type) - + public bool UpsideDown { get; set; } } \ No newline at end of file diff --git a/PacketLib/OpponentInitPacket.cs b/PacketLib/OpponentInitPacket.cs new file mode 100644 index 0000000..489308a --- /dev/null +++ b/PacketLib/OpponentInitPacket.cs @@ -0,0 +1,5 @@ +namespace PacketLib; + +public class OpponentInitPacket { + public PlayerState state { get; set; } +} \ No newline at end of file