Eventy upraveny pro podporu dvou hráčů. Všechny dveře se zobrazují na správných pozicích pro oba hráče.

This commit is contained in:
Perry 2026-02-25 17:05:15 +01:00
parent cea56112ea
commit 3049417914
18 changed files with 157 additions and 75 deletions

View file

@ -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<JoinAcceptPacket>(OnJoinAccept);
processor.SubscribeReusable<UpdatePlayerPacket>(OnPlayerUpdate);
processor.SubscribeReusable<MapInitPacket>(OnMapInit);
processor.SubscribeReusable<OpponentInitPacket>(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();
}
}
}

View file

@ -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)]);
}

View file

@ -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();
}
}
}
}

View file

@ -9,8 +9,8 @@ namespace FNAF_Clone.GUI;
public class Screen {
public static Dictionary<string, Screen> 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<string, UIElement> elements = new();

View file

@ -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);

View file

@ -24,7 +24,7 @@ public class GameMain() : Core("fnafkooo", 1280, 720, false) {
base.Initialize();
UIManager.InitUI();
// UIManager.InitUI();
}
protected override void LoadContent() {

View file

@ -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<int, int, int> CoordsToId{ get; private set; }
public static Func<int, (int x, int y)> IdToCoords{ get; private set; }
private static Func<int, (int x, int y)> _IdToCoords = id => (id / ID_X_OFFSET, id % ID_X_OFFSET);
private static Func<int, (int x, int y)> _IdToCoordsInverse = id => (ID_X_OFFSET - 1 - (id / ID_X_OFFSET), ID_X_OFFSET - 1 - (id % ID_X_OFFSET));
private static Func<int, int, int> _CoordsToId = (x, y) => x * ID_X_OFFSET + y;
private static Func<int, int, int> _CoordsToIdInverse = (x, y) => (ID_X_OFFSET - 1 - x) * ID_X_OFFSET + (ID_X_OFFSET - 1 - y);
}

View file

@ -3,6 +3,6 @@ using GlobalClassLib;
namespace FNAF_Clone.Map;
public class MapTileProjection : GlobalMapTile<TileConnectorProjection, MapTileProjection> {
public MapTileProjection(int id) : base(id) {
public MapTileProjection(int id) : base(id, ClientMapManager.IdToCoords(id)) {
}
}