From 7e6b3d724b302ad89217c200dfe967737521832f Mon Sep 17 00:00:00 2001 From: Perry Date: Sat, 14 Feb 2026 14:35:29 +0100 Subject: [PATCH] =?UTF-8?q?Na=20za=C4=8D=C3=A1tku=20hry=20se=20mapa=20na?= =?UTF-8?q?=20serveru=20synchronizuje=20s=20mapou=20u=20clienta.=20Roz?= =?UTF-8?q?=C5=A1=C3=AD=C5=99en=20spritesheet=20monitoru=20o=20remote=20dv?= =?UTF-8?q?e=C5=99e.=20P=C5=99id=C3=A1na=20GlobalClassLib=20pro=20k=C3=B3d?= =?UTF-8?q?=20sd=C3=ADlen=C3=BD=20mezi=20clientem=20a=20serverem.=20Z?= =?UTF-8?q?=C3=A1klad=20pro=20implementaci=20ovl=C3=A1d=C3=A1n=C3=AD=20rem?= =?UTF-8?q?ote=20dve=C5=99=C3=AD.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FNAF_Clone.sln | 6 ++ FNAF_Clone/Client.cs | 23 ++++++-- FNAF_Clone/CommandManager.cs | 30 +++++++--- .../Content/images/SpriteSheet_monitor.png | Bin 4674 -> 4683 bytes .../Content/images/monitor-definition.xml | 21 ++++++- FNAF_Clone/FNAF_Clone.csproj | 1 + FNAF_Clone/GUI/UIManager.cs | 23 ++++++-- FNAF_Clone/Map/ClientMapManager.cs | 28 +++++++++ FNAF_Clone/Map/MapTileProjection.cs | 8 +++ FNAF_Clone/Map/TileConnectorProjection.cs | 13 +++++ FNAF_Server/FNAF_Server.csproj | 1 + FNAF_Server/GameLogic.cs | 14 +++++ FNAF_Server/Map/MapManager.cs | 50 ++++++++++++----- FNAF_Server/Map/MapTile.cs | 53 ++++++++++++------ FNAF_Server/Map/TileConnector.cs | 51 +++++++++++++---- FNAF_Server/Server.cs | 7 ++- GlobalClassLib/ConnectorType.cs | 9 +++ GlobalClassLib/Direction.cs | 8 +++ GlobalClassLib/GlobalClassLib.csproj | 9 +++ GlobalClassLib/GlobalMapTile.cs | 43 ++++++++++++++ GlobalClassLib/GlobalTileConnector.cs | 28 +++++++++ PacketLib/MapInitPacket.cs | 6 ++ PacketLib/NetDataWriterExtensions.cs | 1 + PacketLib/PacketLib.csproj | 4 ++ PacketLib/PlayerCommand.cs | 4 +- 25 files changed, 374 insertions(+), 67 deletions(-) create mode 100644 FNAF_Clone/Map/ClientMapManager.cs create mode 100644 FNAF_Clone/Map/MapTileProjection.cs create mode 100644 FNAF_Clone/Map/TileConnectorProjection.cs create mode 100644 GlobalClassLib/ConnectorType.cs create mode 100644 GlobalClassLib/Direction.cs create mode 100644 GlobalClassLib/GlobalClassLib.csproj create mode 100644 GlobalClassLib/GlobalMapTile.cs create mode 100644 GlobalClassLib/GlobalTileConnector.cs create mode 100644 PacketLib/MapInitPacket.cs diff --git a/FNAF_Clone.sln b/FNAF_Clone.sln index 3652f00..1450be2 100644 --- a/FNAF_Clone.sln +++ b/FNAF_Clone.sln @@ -6,6 +6,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FNAF_Server", "FNAF_Server\ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PacketLib", "PacketLib\PacketLib.csproj", "{EDC8B98F-D2F7-4BDB-8E3B-E3120A743023}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GlobalClassLib", "GlobalClassLib\GlobalClassLib.csproj", "{4AC67290-B9A4-4CF3-A0A8-62DAAD0CF068}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -24,5 +26,9 @@ Global {EDC8B98F-D2F7-4BDB-8E3B-E3120A743023}.Debug|Any CPU.Build.0 = Debug|Any CPU {EDC8B98F-D2F7-4BDB-8E3B-E3120A743023}.Release|Any CPU.ActiveCfg = Release|Any CPU {EDC8B98F-D2F7-4BDB-8E3B-E3120A743023}.Release|Any CPU.Build.0 = Release|Any CPU + {4AC67290-B9A4-4CF3-A0A8-62DAAD0CF068}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4AC67290-B9A4-4CF3-A0A8-62DAAD0CF068}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4AC67290-B9A4-4CF3-A0A8-62DAAD0CF068}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4AC67290-B9A4-4CF3-A0A8-62DAAD0CF068}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/FNAF_Clone/Client.cs b/FNAF_Clone/Client.cs index ac6ae8c..f7e3999 100644 --- a/FNAF_Clone/Client.cs +++ b/FNAF_Clone/Client.cs @@ -2,6 +2,8 @@ using System; using System.Net; using System.Net.Sockets; using FNAF_Clone.GUI; +using FNAF_Clone.Map; +using GlobalClassLib; using LiteNetLib; using LiteNetLib.Utils; using PacketLib; @@ -26,7 +28,7 @@ public class Client { processor.SubscribeReusable(OnJoinAccept); processor.SubscribeReusable(OnPlayerUpdate); - + processor.SubscribeReusable(OnMapInit); client = new NetManager(listener){ AutoRecycle = true @@ -58,21 +60,30 @@ public class Client { public static void SendCommands(PlayerCommand[] pCommands) { SendPacket(new PlayerCommandPacket{commands = pCommands}, DeliveryMethod.ReliableOrdered); } - - public static void OnNetworkReceive(NetPeer peer, NetPacketReader reader, DeliveryMethod deliveryMethod) { + + private static void OnNetworkReceive(NetPeer peer, NetPacketReader reader, DeliveryMethod deliveryMethod) { processor.ReadAllPackets(reader, peer); } - - public static void OnJoinAccept(JoinAcceptPacket packet) { + + private static void OnJoinAccept(JoinAcceptPacket packet) { Console.WriteLine($"Accepted by server, pid: {packet.state.pid}"); Player.state = packet.state; } + + private static void OnMapInit(MapInitPacket packet) { + (int id1, int id2, ConnectorType type)[] connectors = new (int id1, int id2, ConnectorType type)[packet.Connectors.Length / 3]; + for (int i = 0; i < packet.Connectors.Length / 3; i++){ + connectors[i] = (packet.Connectors[i * 3], packet.Connectors[i * 3 + 1], (ConnectorType)packet.Connectors[i * 3 + 2]); + } + ClientMapManager.InitMap(connectors); + } public static void Update() { client.PollEvents(); } public static void OnPlayerUpdate(UpdatePlayerPacket packet) { // TODO: move this to a separate class + //Player.state = Player.state.pid == 0 ? packet.stateP1 : packet.stateP2; foreach (var e in packet.events){ @@ -96,7 +107,7 @@ public class Client { break; case 4: // toggle door Player.state.doorStates[e.Args[1]] = e.Args[2] == 1; - UIManager.ChangeDoorState(e.Args[1], e.Args[2] == 1); + 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 -1: // movement diff --git a/FNAF_Clone/CommandManager.cs b/FNAF_Clone/CommandManager.cs index f9ca51e..85e7f14 100644 --- a/FNAF_Clone/CommandManager.cs +++ b/FNAF_Clone/CommandManager.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; +using System.Linq; using FNAF_Clone.GUI; +using FNAF_Clone.Map; +using GlobalClassLib; using Microsoft.Xna.Framework.Input; using MonoGameLibrary.Input; using PacketLib; @@ -9,11 +12,11 @@ namespace FNAF_Clone; public class CommandManager { private static (string label, Keys key, Action action)[] keybinds = [ - ("Toggle Camera", Keys.Space, SendToggleCamera), + ("Toggle camera", Keys.Space, SendToggleCamera), ("Toggle left door", Keys.A, ToggleDoorLeft), ("Toggle centre door", Keys.W, ToggleDoorCentre), - ("Toggle right door", Keys.D, ToggleDoorRight) - + ("Toggle right door", Keys.D, ToggleDoorRight), + ("Toggle back door", Keys.S, ToggleDoorBack) ]; private static InputListenerHook toggleCamHook = new(true); @@ -26,16 +29,25 @@ public class CommandManager { Client.SendCommands([PlayerCommand.TOGGLE_MONITOR()]); } - private static void ToggleDoorLeft() => SendToggleDoor(0); - private static void ToggleDoorCentre() => SendToggleDoor(1); - private static void ToggleDoorRight() => SendToggleDoor(2); + private static void ToggleDoorLeft() => SendToggleDoor(Direction.EAST); + private static void ToggleDoorCentre() => SendToggleDoor(Direction.NORTH); + private static void ToggleDoorRight() => SendToggleDoor(Direction.WEST); + private static void ToggleDoorBack() => SendToggleDoor(Direction.SOUTH); + - private static void SendToggleDoor(int id) { + private static void SendToggleDoor(Direction direction) { if (Screen.CurrentScreen.Label == UIManager.ScreenTypes.CAMERAS){ - //TODO: camera doors + SendToggleRemoteDoor(direction); return; } - Client.SendCommands([PlayerCommand.TOGGLE_DOOR_OFFICE(id)]); + Client.SendCommands([PlayerCommand.TOGGLE_DOOR_OFFICE(direction)]); + } + + private static void SendToggleRemoteDoor(Direction direction) { // WIP + TileConnectorProjection[] connectors = ClientMapManager.GetConnectors(Client.Player.state.camera).Where(c => c.Type == ConnectorType.DOOR_REMOTE).ToArray(); + + + // Client.SendCommands([PlayerCommand.TOGGLE_DOOR_REMOTE()]); } public static void SendChangeCamera(int idx, int idy) { diff --git a/FNAF_Clone/Content/images/SpriteSheet_monitor.png b/FNAF_Clone/Content/images/SpriteSheet_monitor.png index b673913bfbf4ddea21b5c2ad65911d1473f50f65..4cfbf816a025a189ef98032b48642b20808f197b 100644 GIT binary patch literal 4683 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 literal 4674 zcmeHL3s93+7QP8lqoPTR1yqoS8mb}&K>>Lrf}+sy61t)ViAwm;50{LBje-~;NJJ2bN#qg2BamcoqH*m`JJXrn+1Z)(pULF^&prRW zC+B|WJKxPWzTSJ5Em^e$0I?lR7fh-T4Y1OGykb{{k-h zpSN7ggo}Fq&lWIeK^Qtvqi?Dca)>9cjzcm6w& zgpF1901W8S062^?1w=yx8erW45@dd$HeJfA*TKkIeF&Q=1^~R89hdOi6Z?1Kwjowf z0r5NLlaF&3H(aBHB50QWk$Ly(7WB&JLR3L=D**cI=U)~=XFr?`qIVq(VHN3)2W};t z)#(yI0rXmc08MBjpy82NV4C&b^ga{sG4Z|>{?AE)>nTX%%uJNTdI}Z*+P$p^EmM+) zHa{~F)N6P+yb<+BDf8cHF(c7&De-ky6bnFS=*^NzK|cnD2`ziONMw|4jmh1&?8RmG4TL<`*3r|Wd8Zd zV&*Zgumnn-$@8v&2^sqF;o$=fg{yDPWDE$UI-fF%qXn$!g7D!0lY;OW-qkYNl|xoK zIt`{M)5oo0WB{6+qNx2A+vuedk9tY|Uuw%xvXm!^^u>v6H6&{_ z7f}_GZ#S-?3T3lrD`*gtbb!Pc+{A62!+HOW7i)3Ujc*rcshIhM#ZAGf8|82GPPK{7 zAS~^&Sk!QAb{#hIRusGa(1qqxNh>pWpV{#cDB2Rm@IcO}f;?TqNd3^p=sUO+nVfiW zSX9$0ePreBG?h%sdABkC_;ARYnynh>(k}N=kJHip8Sls37$qG5Bc2=y= zq>}^=FC>9$_e$YtXn8h8H!vl|Kaf4zgQ>#!C(pZ;a?g;|`oVswA?=Y-lzGQ-$2r`t z_ycTF`H*tPq{d}5|E-4kb@&=tqcOn^ASaZw^oI4!T3*bB5D;kMr>Qf_nhb++g;=`f z?%k{;CC3aPe*C4r_~d>gJm!+Be=!mK6uO7;KuU0e?#D^ATS>|@7SJc#n6jO#8iNye zS|jcc&6+@sb9qO?WVe&58H%fbzlXU%S5AK}5yB9vp77y6R|SPwUKCN-5rOq8+3yLk zx52kqqycyP!)OSrEJ5B9E#DC#LW!{Av8hef!@9#Rw45XZ*T6&sWsZ{+R7C7 zpT3xF+|ViAKZ={JlzUR=H@r^VLM*K@Z^u-LGxPeWe1A#jU%8ngvx;dtYfDw?Jr4Ct z3Y+nb#`7KIa}Kga2|p9W^5CNA-Un|vXkarLEF31EY#Ee2fmT|hLWrTplk~4n6gZM# z-K=s9J3X}R2}CmaSVFr|A@6asM)!Fm5pV;1kcM;L1JT7`MhxtJ8z-8l1;!^gNz1rw ztiMw}K+*1tzpX8`&#Z^32yh>BXSS5c<`{cMGhgN`-^w} z&7=p$(ABUg7Z~Qkf_+;Q;~u6Ui#f?Z8Y~LA{-?U^)hXhE8}$`oQHPOGJcp}EGp2y) z;NTozuKVBJiQm)ImCH>*SsA6yfq}NR5~$>A7;6$;`}Jr9gKCBgZ<7+1s}VgV8LW9u zOB$QU_yDA@v7`J;E$WfywWt@5lxb1F*jJ1Cn^(DSP`}YidJeiSXP}UpqlAWSy;qcFJDu3TpZfa z!{1b=EaYu*WGh9nA(jP96-sPYaX>zP@el)}VUaj}JhIdL6064LdGvjewe!1b@Um+mXWl`X6RKs3fFn}NXA+zA{%cx}$m`xVZnI#J9)w;6 z7EaA~*7*56H%xJ6?tv8%RwQeESi3;CK^z20XG%&=RHTY!koK!mrSca?M6s;>^6{KH zm#5mv-Z=!mHMJav<=`d!B<=hmYTGA`;(eMVO>1bvGA6c^=hb0r@k2!Ej^%otF`UhO zoAuo+q5`gJbK5u*+_?8y1MHL}kk)u&DfY6rmgrA=`t%uPpndK1ULOW4ho^>;qth4R zV_*ONOyK4vBP~TRJ%H=k(3XNR9l8|)jo8jz;^JNz-RCZ}$wr*8N1)B*?$7QCyPx|$ z{)Rvk#v2pSM~^0#cNtLUlqW+5)wU05*l@?*>b?(SRP~C)CJb4QGDY#T*=}(sV9n}N zf%KUn5q*bZDJZSvE8`=S$hHiS`4xqkjDut5!0e$vE{RD49Tvc>%MF(TZ>9a~u=Jb3 z9o3C0z~-P|-$uIin{kk=HUkd2VX_4$nHl#wV-)qVg;&6U1=qUUmyioHcy-W)q8 z(7{7^q#MOIC8|SD1091f^heWy^%RcID|v(revQitmu7iyM%}x81WuJB6SJvM$}6QF2%(mz}6Tk8DZGSMR>Thy>!KZ=I`foS+aO7)OXUDuSXY69@` M*zLWm)Rmn64|SRE^#A|> diff --git a/FNAF_Clone/Content/images/monitor-definition.xml b/FNAF_Clone/Content/images/monitor-definition.xml index 1604fef..4985f07 100644 --- a/FNAF_Clone/Content/images/monitor-definition.xml +++ b/FNAF_Clone/Content/images/monitor-definition.xml @@ -1,5 +1,5 @@ - + images/SpriteSheet_monitor @@ -8,5 +8,24 @@ + + + + + + + + + + + + + + + + + + + diff --git a/FNAF_Clone/FNAF_Clone.csproj b/FNAF_Clone/FNAF_Clone.csproj index 83748ba..361522c 100644 --- a/FNAF_Clone/FNAF_Clone.csproj +++ b/FNAF_Clone/FNAF_Clone.csproj @@ -39,6 +39,7 @@ + diff --git a/FNAF_Clone/GUI/UIManager.cs b/FNAF_Clone/GUI/UIManager.cs index e895135..c094c4b 100644 --- a/FNAF_Clone/GUI/UIManager.cs +++ b/FNAF_Clone/GUI/UIManager.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using GlobalClassLib; using Microsoft.Xna.Framework; using MonoGameLibrary; using MonoGameLibrary.Graphics; @@ -44,21 +46,32 @@ public class UIManager { monitorScreen.AddElement("view-frame", new UIElement(monitorAtlas[1], new Point(62, 55))); monitorScreen.AddElement("map-frame", new UIElement(monitorAtlas[2], new Point(334, 135))); monitorScreen.AddElement("map", new UIElement(monitorAtlas[3], new Point(334, 135))); + + Dictionary<(int,int),string> doorPositions = new(){ + {(0, 0),"2-5"},{ (1, 0), "2-4" }, { (1, 1), "2-3" }, { (3, 0), "2-2" }, { (3, 1), "2-1" }, { (4, 0), "2-0" }, // TODO: generate this dynamically from server map info + {(0, 3),"1-0"},{ (1, 3), "1-1" }, { (1, 2), "1-2" }, { (3, 3), "1-3" }, { (3, 2), "1-4" }, { (4, 3), "1-5" } + }; - for (int i = 0; i < 5; i++){ + for (int i = 0; i < 5; i++){ // NOTE: this loop does y in reverse, y labels are inverted to match server for (int j = 0; j < 5; j++){ int i1 = i; int j1 = j; - monitorScreen.AddElement($"room{i}-{j}", new UIElement(new Point(336 + (32 * i), 144 + (32 * j)), new Point(367 + (32 * i), 175 + (32 * j))) - {Pressable = true, OnMousePress = (() => CommandManager.SendChangeCamera(i1, j1))}); + Point point1 = new Point(336 + (32 * i), 144 + (32 * j)); + Point point2 = new Point(367 + (32 * i), 175 + (32 * j)); + monitorScreen.AddElement($"room{i}-{4 - j}", new UIElement(point1, point2) + {Pressable = true, OnMousePress = (() => CommandManager.SendChangeCamera(i1, 4 - j1))}); + if (doorPositions.ContainsKey((i, j))){ + monitorScreen.AddElement("door"+doorPositions[(i, j)], new UIElement([monitorAtlas[5], monitorAtlas[6]], point1)); + } } } + } - public static void ChangeDoorState(int id, bool state) { - switch (id){ + public static void ChangeDoorState(Direction dir, bool state) { + switch ((int)dir){ case 0: officeScreen["office_left"].SetTexture(state ? 1 : 0); break; diff --git a/FNAF_Clone/Map/ClientMapManager.cs b/FNAF_Clone/Map/ClientMapManager.cs new file mode 100644 index 0000000..124b103 --- /dev/null +++ b/FNAF_Clone/Map/ClientMapManager.cs @@ -0,0 +1,28 @@ +using GlobalClassLib; + +namespace FNAF_Clone.Map; + +public class ClientMapManager { + private static MapTileProjection[,] map = new MapTileProjection[5, 5]; + private static MapTileProjection Get((int x, int y) coords) => map[coords.x, coords.y]; + public static void InitMap((int id1, int id2, ConnectorType type)[] connectors) { + 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, 2] = new MapTileProjection(MapTileProjection.CoordsToId(i, 2)); + for (int j = 3; j < 5; j++){ + map[i, j] = new MapTileProjection(MapTileProjection.CoordsToId(i, j)); + + } + } + + foreach (var con in connectors){ + (int x, int y) coords1 = MapTileProjection.IdToCoords(con.id1); + (int x, int y) coords2 = MapTileProjection.IdToCoords(con.id2); + map[coords1.x, coords1.y].AddConnector(new TileConnectorProjection(map[coords2.x, coords2.y], con.type)); + } + } + + public static TileConnectorProjection[] GetConnectors(int tileId) => Get(MapTileProjection.IdToCoords(tileId)).GetAllConnectors(); +} \ No newline at end of file diff --git a/FNAF_Clone/Map/MapTileProjection.cs b/FNAF_Clone/Map/MapTileProjection.cs new file mode 100644 index 0000000..f891cfd --- /dev/null +++ b/FNAF_Clone/Map/MapTileProjection.cs @@ -0,0 +1,8 @@ +using GlobalClassLib; + +namespace FNAF_Clone.Map; + +public class MapTileProjection : GlobalMapTile { + public MapTileProjection(int id) : base(id) { + } +} \ No newline at end of file diff --git a/FNAF_Clone/Map/TileConnectorProjection.cs b/FNAF_Clone/Map/TileConnectorProjection.cs new file mode 100644 index 0000000..c6f25d9 --- /dev/null +++ b/FNAF_Clone/Map/TileConnectorProjection.cs @@ -0,0 +1,13 @@ +using GlobalClassLib; + +namespace FNAF_Clone.Map; + +public class TileConnectorProjection : GlobalTileConnector { + public TileConnectorProjection(MapTileProjection tile1, MapTileProjection tile2, ConnectorType type) : base(tile1, tile2, type) { + } + + public TileConnectorProjection(MapTileProjection tile2, ConnectorType type) : base(tile2, type) { + } + + public override TileConnectorProjection Clone() => new(Tiles.tile1, Tiles.tile2, Type); +} \ No newline at end of file diff --git a/FNAF_Server/FNAF_Server.csproj b/FNAF_Server/FNAF_Server.csproj index d13b3e5..a8814b6 100644 --- a/FNAF_Server/FNAF_Server.csproj +++ b/FNAF_Server/FNAF_Server.csproj @@ -12,6 +12,7 @@ + diff --git a/FNAF_Server/GameLogic.cs b/FNAF_Server/GameLogic.cs index 0f15bae..c83fafe 100644 --- a/FNAF_Server/GameLogic.cs +++ b/FNAF_Server/GameLogic.cs @@ -1,4 +1,5 @@ using FNAF_Server.Map; +using GlobalClassLib; using PacketLib; namespace FNAF_Server; @@ -6,7 +7,20 @@ namespace FNAF_Server; public class GameLogic { public static void Init() { + // Create map MapManager.InitMap(); + + //Send map to client + TileConnector[] connectors = MapManager.GetAllConnectors(); + int[] connectorsConverted = new int[connectors.Length * 3]; + for (int i = 0; i < connectors.Length; i++){ + connectorsConverted[i * 3] = connectors[i].Tiles.tile1.Id; + connectorsConverted[i * 3 + 1] = connectors[i].Tiles.tile2.Id; + connectorsConverted[i * 3 + 2] = (int)connectors[i].Type; + } + Server.SendPacketToAll(new MapInitPacket{Connectors = connectorsConverted}); + + } public static void Update() { diff --git a/FNAF_Server/Map/MapManager.cs b/FNAF_Server/Map/MapManager.cs index a3a6217..4d8ee55 100644 --- a/FNAF_Server/Map/MapManager.cs +++ b/FNAF_Server/Map/MapManager.cs @@ -1,17 +1,19 @@ +using GlobalClassLib; + namespace FNAF_Server.Map; public static class MapManager { private static MapTile[,] map = new MapTile[5, 5]; - private static Dictionary<(int x1, int y1), (int x2, int y2, int value)[]> halfConnectors = new(){ - [(0, 0)] =[(1, 0, 1), (0, 1, 1)], - [(1, 0)] =[(2, 0, 1), (1, 1, 1)], - [(3, 0)] =[(2, 0, 1), (4, 0, 1), (3, 1, 1)], - [(4, 0)] =[(4, 1, 1)], - [(0, 1)] =[(1, 1, 1)], - [(1, 1)] =[(1, 2, 1)], - [(2, 1)] =[(2, 2, 1), (2, 0, 1)], - [(3, 1)] =[(3, 2, 1), (4, 1, 1)] + private static Dictionary<(int x1, int y1), (int x2, int y2, int value, ConnectorType type)[]> halfConnectors = new(){ + [(0, 0)] =[(1, 0, 1, ConnectorType.HALL), (0, 1, 1, ConnectorType.DOOR_REMOTE)], + [(1, 0)] =[(2, 0, 1, ConnectorType.DOOR_OFFICE), (1, 1, 1, ConnectorType.DOOR_REMOTE)], + [(3, 0)] =[(2, 0, 1, ConnectorType.DOOR_OFFICE), (4, 0, 1, ConnectorType.HALL), (3, 1, 1, ConnectorType.DOOR_REMOTE)], + [(4, 0)] =[(4, 1, 1, ConnectorType.DOOR_REMOTE)], + [(0, 1)] =[(1, 1, 1, ConnectorType.HALL)], + [(1, 1)] =[(1, 2, 1, ConnectorType.DOOR_REMOTE)], + [(2, 1)] =[(2, 2, 1, ConnectorType.HALL), (2, 0, 1, ConnectorType.DOOR_OFFICE)], + [(3, 1)] =[(3, 2, 1, ConnectorType.DOOR_REMOTE), (4, 1, 1, ConnectorType.HALL)] }; private static Dictionary<(int x1, int y1), (int x2, int y2, int value)[]> mainHallwayConnectors = new(){ @@ -24,24 +26,42 @@ 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(i * 5 + j, null); // TODO: implement ownership + map[i, j] = new MapTile(MapTile.CoordsToId(i, j), null); // TODO: implement ownership } - map[i, 2] = new MapTile(i * 5 + 2, null); + map[i, 2] = new MapTile(MapTile.CoordsToId(i, 2), null); for (int j = 3; j < 5; j++){ - map[i, j] = new MapTile(i * 5 + j, null); + map[i, j] = new MapTile(MapTile.CoordsToId(i, j), null); } } foreach (var con in mainHallwayConnectors){ - map[con.Key.x1, con.Key.y1].AddConnectors(con.Value.Select(c => (map[c.x2, c.y2], TileConnector.ConnectorType.HALL, c.value)).ToArray()); + map[con.Key.x1, con.Key.y1].AddConnectors(con.Value.Select(c => new TileConnector(map[c.x2, c.y2], ConnectorType.HALL, c.value)).ToArray()); } foreach (var con in halfConnectors){ - map[con.Key.x1, con.Key.y1].AddConnectors(con.Value.Select(c => (map[c.x2, c.y2], TileConnector.ConnectorType.HALL, c.value)).ToArray()); + map[con.Key.x1, con.Key.y1].AddConnectors(con.Value.Select(c => new TileConnector(map[c.x2, c.y2], c.type, c.value)).ToArray()); } foreach (var con in halfConnectors){ - map[4 - con.Key.x1, 4 - con.Key.y1].AddConnectors(con.Value.Select(c => (map[4 - c.x2, 4 - c.y2], TileConnector.ConnectorType.HALL, c.value)).ToArray()); + map[4 - con.Key.x1, 4 - con.Key.y1].AddConnectors(con.Value.Select(c => new TileConnector(map[4 - c.x2, 4 - c.y2], c.type, c.value)).ToArray()); } + } + + public static TileConnector[] GetAllConnectors() { + List connectors = new(); + + for (int i = 0; i < 5; i++){ + for (int j = 0; j < 5; j++){ + Array.ForEach(map[i, j].GetAllConnectors(), c => { + if(c.Tiles.tile1.Id < c.Tiles.tile2.Id) + connectors.Add(c); + }); + } + } + + return connectors.ToArray(); + } + + } \ No newline at end of file diff --git a/FNAF_Server/Map/MapTile.cs b/FNAF_Server/Map/MapTile.cs index 8692bec..a28def2 100644 --- a/FNAF_Server/Map/MapTile.cs +++ b/FNAF_Server/Map/MapTile.cs @@ -1,25 +1,44 @@ +using System.Net.Security; +using GlobalClassLib; + namespace FNAF_Server.Map; -public class MapTile { - public int Id { get; private set; } - public ServerPlayer Owner { get; private set; } - public bool Lit { get; set; } = false; +public class MapTile : GlobalMapTile { + public ServerPlayer Owner{ get; private set; } - private List Connectors { get; set; } = new(); - - public MapTile(int id, ServerPlayer owner) { - Id = id; + public MapTile(int id, ServerPlayer owner) : base(id) { Owner = owner; } - public void AddConnector(MapTile tile, TileConnector.ConnectorType type, int value) { - Connectors.Add(new TileConnector(this, tile, type, value)); - tile.Connectors.Add(new TileConnector(tile, this, type, value)); - } - - public void AddConnectors((MapTile tile, TileConnector.ConnectorType type, int value)[] connectors) => - Array.ForEach(connectors, c => AddConnector(c.tile, c.type, c.value)); - public override string ToString() => $"{PositionAsString} -> {string.Join(", ", Connectors.Select(c => c.Tiles.Item2.PositionAsString))}"; - public string PositionAsString => $"[{Id / 5}, {Id % 5}]"; // for debug purposes + // public int Id { get; private set; } + // public ServerPlayer Owner { get; private set; } + // public bool Lit { get; set; } = false; + // + // private List connectors = new(); + // + // public MapTile(int id, ServerPlayer owner) { + // Id = id; + // Owner = owner; + // } + // public void AddConnector(MapTile tile, TileConnector.ConnectorType type, int value) { + // connectors.Add(new TileConnector(this, tile, type, value)); + // tile.connectors.Add(new TileConnector(tile, this, type, value)); + // + // + // } + // + // public void AddConnectors((MapTile tile, TileConnector.ConnectorType type, int value)[] connectors) => + // Array.ForEach(connectors, c => AddConnector(c.tile, c.type, c.value)); + // + // public override string ToString() => $"{PositionAsString} -> {string.Join(", ", connectors.Select(c => c.Tiles.Item2.PositionAsString))}"; + // public string PositionAsString => $"[{Id}]"; // for debug purposes + // + // public TileConnector? GetConnector(int id) { + // foreach (var con in connectors){ + // if (con.Tiles.Item2.Id == id) return con; + // } + // + // return null; + // } } \ No newline at end of file diff --git a/FNAF_Server/Map/TileConnector.cs b/FNAF_Server/Map/TileConnector.cs index 521eba2..1ee2a58 100644 --- a/FNAF_Server/Map/TileConnector.cs +++ b/FNAF_Server/Map/TileConnector.cs @@ -1,18 +1,45 @@ +using GlobalClassLib; + namespace FNAF_Server.Map; -public struct TileConnector(MapTile tile1, MapTile tile2, TileConnector.ConnectorType type, int value) { - public (MapTile, MapTile) Tiles { get; set; } = (tile1, tile2); - public ConnectorType Type { get; set; } = type; - public bool Blocked { get; set; } = false; - public int Value{ get; set; } = value; +public class TileConnector : GlobalTileConnector { + public int Value{ get; set; } + public bool Blocked { get; set; } + public TileConnector(MapTile tile1, MapTile tile2, ConnectorType type, int value) : base(tile1, tile2, type) { + Value = value; + } - public MapTile OtherTile(MapTile tile) => Tiles.Item1 == tile ? Tiles.Item2 : Tiles.Item1; - - public override string ToString() => $"Con ({Tiles.Item1.PositionAsString} -> {Tiles.Item2.PositionAsString})"; - public enum ConnectorType { - HALL, - DOOR, - VENT + public TileConnector(MapTile tile2, ConnectorType type, int value) : base(tile2, type) { + Value = value; } + + + // private readonly MapTile _tile1; + // private readonly MapTile _tile2; + // + // public TileConnector(MapTile tile1, MapTile tile2, TileConnector.ConnectorType type, int value) { + // _tile1 = tile1; + // _tile2 = tile2; + // Type = type; + // Value = value; + // } + // + // public (MapTile, MapTile) Tiles => (tile1: _tile1, tile2: _tile2); + // + // public ConnectorType Type { get; set; } + // public bool Blocked { get; set; } = false; + // public int Value{ get; set; } + // + // public MapTile OtherTile(MapTile tile) => Tiles.Item1 == tile ? Tiles.Item2 : Tiles.Item1; + // + // public override string ToString() => $"Con ({Tiles.Item1.PositionAsString} -> {Tiles.Item2.PositionAsString})"; + // public enum ConnectorType { + // HALL, + // DOOR_REMOTE, + // DOOR_OFFICE, + // VENT + // } + + public override TileConnector Clone() => new(Tiles.tile1, Tiles.tile2, Type, Value); } \ No newline at end of file diff --git a/FNAF_Server/Server.cs b/FNAF_Server/Server.cs index 26ec141..59c09ef 100644 --- a/FNAF_Server/Server.cs +++ b/FNAF_Server/Server.cs @@ -2,6 +2,7 @@ using System; using System.Collections; using System.Diagnostics; using System.Threading; +using FNAF_Server.Map; using LiteNetLib; using LiteNetLib.Utils; using PacketLib; @@ -116,7 +117,11 @@ public class Server { P2 = newPlayer; } - GameLogic.Init(); // TODO: implement a way to start the game once both players join + + GameLogic.Init(); // TODO: move this to the condition above to wait for the other player + + + } diff --git a/GlobalClassLib/ConnectorType.cs b/GlobalClassLib/ConnectorType.cs new file mode 100644 index 0000000..65669e8 --- /dev/null +++ b/GlobalClassLib/ConnectorType.cs @@ -0,0 +1,9 @@ +namespace GlobalClassLib; + + +public enum ConnectorType { + HALL = 0, + DOOR_REMOTE = 1, + DOOR_OFFICE = 2, + VENT = 3 +} diff --git a/GlobalClassLib/Direction.cs b/GlobalClassLib/Direction.cs new file mode 100644 index 0000000..181ef50 --- /dev/null +++ b/GlobalClassLib/Direction.cs @@ -0,0 +1,8 @@ +namespace GlobalClassLib; + +public enum Direction { + EAST = 0, + NORTH = 1, + WEST = 2, + SOUTH = 3 +} \ No newline at end of file diff --git a/GlobalClassLib/GlobalClassLib.csproj b/GlobalClassLib/GlobalClassLib.csproj new file mode 100644 index 0000000..17b910f --- /dev/null +++ b/GlobalClassLib/GlobalClassLib.csproj @@ -0,0 +1,9 @@ + + + + net9.0 + enable + enable + + + diff --git a/GlobalClassLib/GlobalMapTile.cs b/GlobalClassLib/GlobalMapTile.cs new file mode 100644 index 0000000..0c57f90 --- /dev/null +++ b/GlobalClassLib/GlobalMapTile.cs @@ -0,0 +1,43 @@ +namespace GlobalClassLib; + +public abstract class GlobalMapTile where TCon : GlobalTileConnector where TTile : GlobalMapTile { // TTile should be the inheriting class + public int Id { get; private set; } + public bool Lit { get; set; } = false; + + private List connectors = new(); + + public GlobalMapTile(int id) { + Id = id; + } + public void AddConnector(TCon connector) { // tile1 is ignored when provided + connector.Tiles.tile1 = (TTile)this; + connectors.Add(connector); + connector.Tiles.tile2._AddConnectorNoRepeat(connector.Clone()); + // connectors.Add(new TCon(this, tile, type)); + // tile.connectors.Add(new GlobalTileConnector(tile, this, type)); + } + + private void _AddConnectorNoRepeat(TCon connector) { + (connector.Tiles.tile1, connector.Tiles.tile2) = (connector.Tiles.tile2, connector.Tiles.tile1); + connectors.Add(connector); + } + + public void AddConnectors(TCon[] connectors) => + Array.ForEach(connectors, AddConnector); + + public override string ToString() => $"{PositionAsString} -> {string.Join(", ", connectors.Select(c => c.Tiles.Item2.PositionAsString))}"; + public string PositionAsString => $"[{Id}]"; // for debug purposes + + public TCon? GetConnector(int id) { + foreach (var con in connectors){ + if (con.Tiles.Item2.Id == id) return con; + } + + return null; + } + + public TCon[] GetAllConnectors() => connectors.ToArray(); + + public static int CoordsToId(int x, int y) => x * 5 + y; + public static (int, int) IdToCoords(int id) => (id % 5, id / 5); +} \ No newline at end of file diff --git a/GlobalClassLib/GlobalTileConnector.cs b/GlobalClassLib/GlobalTileConnector.cs new file mode 100644 index 0000000..97108b0 --- /dev/null +++ b/GlobalClassLib/GlobalTileConnector.cs @@ -0,0 +1,28 @@ +namespace GlobalClassLib; + +public abstract class GlobalTileConnector where TTile : GlobalMapTile where TCon : GlobalTileConnector { + // private readonly TTile _tile1; + // private readonly TTile _tile2; + + public GlobalTileConnector(TTile tile1, TTile tile2, ConnectorType type) { + Tiles.tile1 = tile1; + Tiles.tile2 = tile2; + Type = type; + } + + public GlobalTileConnector(TTile tile2, ConnectorType type) { + Tiles.tile2 = tile2; + Type = type; + } + + public (TTile tile1, TTile tile2) Tiles; + public (int, int) Id => (Tiles.tile1.Id, Tiles.tile2.Id); + + public ConnectorType Type { get; set; } + + public TTile OtherTile(TTile tile) => Tiles.Item1 == tile ? Tiles.Item2 : Tiles.Item1; + + public override string ToString() => $"Con ({Tiles.Item1.PositionAsString} -> {Tiles.Item2.PositionAsString})"; + + public abstract TCon Clone(); +} \ No newline at end of file diff --git a/PacketLib/MapInitPacket.cs b/PacketLib/MapInitPacket.cs new file mode 100644 index 0000000..4e9b5bb --- /dev/null +++ b/PacketLib/MapInitPacket.cs @@ -0,0 +1,6 @@ +namespace PacketLib; + +public class MapInitPacket { + public int[] Connectors { get; set; } // triplets (tile1 id, tile2 id, type) + +} \ No newline at end of file diff --git a/PacketLib/NetDataWriterExtensions.cs b/PacketLib/NetDataWriterExtensions.cs index 4f74393..451d1ee 100644 --- a/PacketLib/NetDataWriterExtensions.cs +++ b/PacketLib/NetDataWriterExtensions.cs @@ -9,4 +9,5 @@ public static class NetDataWriterExtensions { gevent.Deserialize(reader); return gevent; } + } \ No newline at end of file diff --git a/PacketLib/PacketLib.csproj b/PacketLib/PacketLib.csproj index 06e6adc..3ba44a2 100644 --- a/PacketLib/PacketLib.csproj +++ b/PacketLib/PacketLib.csproj @@ -10,4 +10,8 @@ + + + + diff --git a/PacketLib/PlayerCommand.cs b/PacketLib/PlayerCommand.cs index 3e7742b..47f868f 100644 --- a/PacketLib/PlayerCommand.cs +++ b/PacketLib/PlayerCommand.cs @@ -1,3 +1,4 @@ +using GlobalClassLib; using LiteNetLib.Utils; namespace PacketLib; @@ -5,7 +6,8 @@ namespace PacketLib; public struct PlayerCommand : INetSerializable { public static PlayerCommand SWITCH_CAM(int idx, int idy) => new(){ID = 0, Args = [idx, idy] }; public static PlayerCommand TOGGLE_MONITOR() => new(){ID = 1, Args = []}; - public static PlayerCommand TOGGLE_DOOR_OFFICE(int doorId) => new(){ID = 2, Args = [doorId]}; + public static PlayerCommand TOGGLE_DOOR_OFFICE(Direction direction) => new(){ID = 2, Args = [(int)direction]}; + public static PlayerCommand TOGGLE_DOOR_REMOTE(int remoteDoorId) => new(){ID = 3, Args = [remoteDoorId]}; public int ID{ get; set; } public bool Hideable => ID < 0; public int[] Args{ get; private set; }