From 5e99cd92dff5b93984794f0e29d6099c6513cd1a Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Thu, 23 Jan 2025 18:59:11 +0100 Subject: [PATCH 1/7] network structure --- app/src/main/java/gui/Main.java | 5 ++ app/src/main/java/gui/menu/BaseView.java | 2 + .../main/java/gui/menu/CreateGameMenu.java | 17 ------ app/src/main/java/gui/menu/JoinGameMenu.java | 17 ------ app/src/main/java/gui/menu/MultiMenu.java | 20 ++++++- .../main/java/gui/menu/MultiPlayerView.java | 58 +++++++++++++++++++ app/src/main/java/gui/menu/StateMachine.java | 8 +++ app/src/main/java/network/Connexion.java | 27 +++++++++ .../main/java/network/ConnexionThread.java | 39 +++++++++++++ app/src/main/java/network/Packet.java | 11 ++++ app/src/main/java/network/PacketFactory.java | 8 +++ app/src/main/java/network/PacketVisitor.java | 15 +++++ app/src/main/java/network/Packets.java | 7 +++ app/src/main/java/network/client/Client.java | 17 ++++++ .../java/network/client/ClientConnexion.java | 33 +++++++++++ .../java/network/client/PacketDispatcher.java | 31 ++++++++++ .../network/packets/ConnexionInfoPacket.java | 25 ++++++++ .../java/network/packets/KeepAlivePacket.java | 26 +++++++++ app/src/main/java/network/server/Server.java | 28 +++++++++ .../java/network/server/ServerConnexion.java | 35 +++++++++++ .../java/network/server/ServerThread.java | 36 ++++++++++++ 21 files changed, 429 insertions(+), 36 deletions(-) delete mode 100644 app/src/main/java/gui/menu/CreateGameMenu.java delete mode 100644 app/src/main/java/gui/menu/JoinGameMenu.java create mode 100644 app/src/main/java/gui/menu/MultiPlayerView.java create mode 100644 app/src/main/java/network/Connexion.java create mode 100644 app/src/main/java/network/ConnexionThread.java create mode 100644 app/src/main/java/network/Packet.java create mode 100644 app/src/main/java/network/PacketFactory.java create mode 100644 app/src/main/java/network/PacketVisitor.java create mode 100644 app/src/main/java/network/Packets.java create mode 100644 app/src/main/java/network/client/Client.java create mode 100644 app/src/main/java/network/client/ClientConnexion.java create mode 100644 app/src/main/java/network/client/PacketDispatcher.java create mode 100644 app/src/main/java/network/packets/ConnexionInfoPacket.java create mode 100644 app/src/main/java/network/packets/KeepAlivePacket.java create mode 100644 app/src/main/java/network/server/Server.java create mode 100644 app/src/main/java/network/server/ServerConnexion.java create mode 100644 app/src/main/java/network/server/ServerThread.java diff --git a/app/src/main/java/gui/Main.java b/app/src/main/java/gui/Main.java index f751b4b..50ca9a6 100644 --- a/app/src/main/java/gui/Main.java +++ b/app/src/main/java/gui/Main.java @@ -15,6 +15,11 @@ public class Main extends Application { config.setTitle("Let's play sudoku!"); } + @Override + protected void disposeWindow() { + stateMachine.clear(); + } + @Override protected void initImGui(Configuration config) { super.initImGui(config); diff --git a/app/src/main/java/gui/menu/BaseView.java b/app/src/main/java/gui/menu/BaseView.java index 317fdce..9992279 100644 --- a/app/src/main/java/gui/menu/BaseView.java +++ b/app/src/main/java/gui/menu/BaseView.java @@ -12,6 +12,8 @@ public abstract class BaseView { public abstract void render(); + public void onKill() {} + public void closeMenu() { this.stateMachine.popState(); } diff --git a/app/src/main/java/gui/menu/CreateGameMenu.java b/app/src/main/java/gui/menu/CreateGameMenu.java deleted file mode 100644 index 9b99af7..0000000 --- a/app/src/main/java/gui/menu/CreateGameMenu.java +++ /dev/null @@ -1,17 +0,0 @@ -package gui.menu; - -import imgui.ImGui; - -public class CreateGameMenu extends BaseView { - - public CreateGameMenu(StateMachine stateMachine) { - super(stateMachine); - } - - @Override - public void render() { - ImGui.text("Créer"); - renderReturnButton(); - } - -} diff --git a/app/src/main/java/gui/menu/JoinGameMenu.java b/app/src/main/java/gui/menu/JoinGameMenu.java deleted file mode 100644 index cc64558..0000000 --- a/app/src/main/java/gui/menu/JoinGameMenu.java +++ /dev/null @@ -1,17 +0,0 @@ -package gui.menu; - -import imgui.ImGui; - -public class JoinGameMenu extends BaseView { - - public JoinGameMenu(StateMachine stateMachine) { - super(stateMachine); - } - - @Override - public void render() { - ImGui.text("Rejoindre"); - renderReturnButton(); - } - -} diff --git a/app/src/main/java/gui/menu/MultiMenu.java b/app/src/main/java/gui/menu/MultiMenu.java index 9a23a3f..e6e87dc 100644 --- a/app/src/main/java/gui/menu/MultiMenu.java +++ b/app/src/main/java/gui/menu/MultiMenu.java @@ -1,15 +1,22 @@ package gui.menu; +import java.io.IOException; + import imgui.ImGui; import imgui.ImVec2; import imgui.type.ImInt; import imgui.type.ImString; +import network.client.Client; +import network.server.Server; public class MultiMenu extends BaseView { private final ImInt port = new ImInt(25565); private final ImString address = new ImString("localhost"); + private Server server; + private Client client; + public MultiMenu(StateMachine stateMachine) { super(stateMachine); } @@ -19,7 +26,11 @@ public class MultiMenu extends BaseView { ImGui.beginChild("##CreateGame", new ImVec2(displaySize.x / 2.0f, displaySize.y * 8.0f / 9.0f)); ImGui.inputInt("Port", port); if (ImGui.button("Créer")) { - // TODO: create game + try { + this.stateMachine.pushState(new MultiPlayerView(stateMachine, (short) port.get())); + } catch (IOException e) { + e.printStackTrace(); + } } ImGui.endChild(); } @@ -30,7 +41,12 @@ public class MultiMenu extends BaseView { ImGui.inputText("Adresse", address); ImGui.inputInt("Port", port); if (ImGui.button("Rejoindre")) { - // TODO: join game + try { + this.stateMachine.pushState(new MultiPlayerView(stateMachine, address.get(), (short) port.get())); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } ImGui.endChild(); } diff --git a/app/src/main/java/gui/menu/MultiPlayerView.java b/app/src/main/java/gui/menu/MultiPlayerView.java new file mode 100644 index 0000000..3646f1c --- /dev/null +++ b/app/src/main/java/gui/menu/MultiPlayerView.java @@ -0,0 +1,58 @@ +package gui.menu; + +import java.io.IOException; +import java.net.UnknownHostException; + +import imgui.ImGui; +import network.client.Client; +import network.server.Server; + +public class MultiPlayerView extends BaseView { + + private Client client; + private Server server; + + /** + * Client + * + * @param stateMachine + * @param address + * @param port + * @throws IOException + * @throws UnknownHostException + */ + public MultiPlayerView(StateMachine stateMachine, String address, short port) + throws UnknownHostException, IOException { + super(stateMachine); + this.client = new Client(address, port); + } + + /** + * Server + * + * @param stateMachine + * @param port + * @throws IOException + */ + public MultiPlayerView(StateMachine stateMachine, short port) throws IOException { + super(stateMachine); + this.server = new Server(port); + this.client = new Client("localhost", port); + } + + @Override + public void onKill() { + if (this.server != null) { + this.server.stop(); + } + if (this.client != null) { + this.client.stop(); + } + } + + @Override + public void render() { + ImGui.text("Tema le gameplay"); + } + +} diff --git a/app/src/main/java/gui/menu/StateMachine.java b/app/src/main/java/gui/menu/StateMachine.java index db25a51..c698ac8 100644 --- a/app/src/main/java/gui/menu/StateMachine.java +++ b/app/src/main/java/gui/menu/StateMachine.java @@ -15,11 +15,19 @@ public class StateMachine { this.menus = new Stack<>(); } + public void clear() { + for (BaseView view : menus) { + view.onKill(); + } + menus.clear(); + } + public void pushState(BaseView menu) { menus.add(menu); } public void popState() { + menus.getLast().onKill(); menus.pop(); } diff --git a/app/src/main/java/network/Connexion.java b/app/src/main/java/network/Connexion.java new file mode 100644 index 0000000..4dd54da --- /dev/null +++ b/app/src/main/java/network/Connexion.java @@ -0,0 +1,27 @@ +package network; + +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.net.Socket; + +public abstract class Connexion implements PacketVisitor { + + final Socket socket; + private final ObjectOutputStream objectOutputStream; + private final ConnexionThread connexionThread; + + public Connexion(Socket socket) throws IOException { + this.socket = socket; + this.objectOutputStream = new ObjectOutputStream(this.socket.getOutputStream()); + this.connexionThread = new ConnexionThread(this); + this.connexionThread.start(); + } + + public void sendPacket(Packet packet) throws IOException { + objectOutputStream.writeObject(packet); + } + + public void close() { + this.connexionThread.cancel(); + } +} diff --git a/app/src/main/java/network/ConnexionThread.java b/app/src/main/java/network/ConnexionThread.java new file mode 100644 index 0000000..81ab76c --- /dev/null +++ b/app/src/main/java/network/ConnexionThread.java @@ -0,0 +1,39 @@ +package network; + +import java.io.IOException; +import java.io.ObjectInputStream; + +public class ConnexionThread extends Thread{ + + private final Connexion connexion; + private final ObjectInputStream objectInputStream; + + public ConnexionThread(Connexion connexion) throws IOException { + this.connexion = connexion; + this.objectInputStream = new ObjectInputStream(this.connexion.socket.getInputStream()); + } + + @Override + public void run() { + while(!interrupted()) { + try { + Object o = objectInputStream.readObject(); + if (o instanceof Packet packet) { + connexion.visit(packet); + } + } catch (ClassNotFoundException | IOException e) { + break; + } + } + } + + public void cancel() { + try { + objectInputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + interrupt(); + } + +} diff --git a/app/src/main/java/network/Packet.java b/app/src/main/java/network/Packet.java new file mode 100644 index 0000000..3bc5765 --- /dev/null +++ b/app/src/main/java/network/Packet.java @@ -0,0 +1,11 @@ +package network; + +import java.io.Serializable; + +public abstract class Packet implements Serializable { + + // public abstract int getId(); + + public abstract void accept(PacketVisitor packetVisitor); + +} diff --git a/app/src/main/java/network/PacketFactory.java b/app/src/main/java/network/PacketFactory.java new file mode 100644 index 0000000..45a879a --- /dev/null +++ b/app/src/main/java/network/PacketFactory.java @@ -0,0 +1,8 @@ +package network; + +import java.nio.ByteBuffer; + +public class PacketFactory { + + +} diff --git a/app/src/main/java/network/PacketVisitor.java b/app/src/main/java/network/PacketVisitor.java new file mode 100644 index 0000000..679a8f5 --- /dev/null +++ b/app/src/main/java/network/PacketVisitor.java @@ -0,0 +1,15 @@ +package network; + +import network.packets.ConnexionInfoPacket; +import network.packets.KeepAlivePacket; + +public interface PacketVisitor { + + default void visit(Packet packet) { + packet.accept(this); + } + + void visit(ConnexionInfoPacket packet); + void visit(KeepAlivePacket packet); + +} diff --git a/app/src/main/java/network/Packets.java b/app/src/main/java/network/Packets.java new file mode 100644 index 0000000..6132427 --- /dev/null +++ b/app/src/main/java/network/Packets.java @@ -0,0 +1,7 @@ +package network; + +public enum Packets { + + ConnectionInfo, KeepAlive + +} diff --git a/app/src/main/java/network/client/Client.java b/app/src/main/java/network/client/Client.java new file mode 100644 index 0000000..4b310ed --- /dev/null +++ b/app/src/main/java/network/client/Client.java @@ -0,0 +1,17 @@ +package network.client; + +import java.io.IOException; +import java.net.UnknownHostException; + +public class Client { + private final ClientConnexion clientConnection; + + public Client(String address, short port) throws UnknownHostException, IOException { + this.clientConnection = new ClientConnexion(address, port); + } + + public void stop() { + this.clientConnection.close(); + } + +} diff --git a/app/src/main/java/network/client/ClientConnexion.java b/app/src/main/java/network/client/ClientConnexion.java new file mode 100644 index 0000000..6ff751c --- /dev/null +++ b/app/src/main/java/network/client/ClientConnexion.java @@ -0,0 +1,33 @@ +package network.client; + +import java.io.IOException; +import java.net.Socket; +import java.net.UnknownHostException; + +import network.Connexion; +import network.packets.ConnexionInfoPacket; +import network.packets.KeepAlivePacket; + +public class ClientConnexion extends Connexion { + + public ClientConnexion(String address, short port) throws UnknownHostException, IOException { + super(new Socket(address, port)); + } + + @Override + public void visit(ConnexionInfoPacket packet) { + + } + + @Override + public void visit(KeepAlivePacket packet) { + System.out.println("Coucou !!!!!!!!!!!!!!!!!!!"); + try { + sendPacket(packet); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + +} diff --git a/app/src/main/java/network/client/PacketDispatcher.java b/app/src/main/java/network/client/PacketDispatcher.java new file mode 100644 index 0000000..4a6d490 --- /dev/null +++ b/app/src/main/java/network/client/PacketDispatcher.java @@ -0,0 +1,31 @@ +package network.client; + +import java.util.ArrayList; +import java.util.List; + +import network.Packet; +import network.PacketVisitor; + +public class PacketDispatcher { + + private final List handlers; + + public PacketDispatcher() { + this.handlers = new ArrayList<>(); + } + + public void dispatch(Packet packet) { + for (PacketVisitor handler : handlers) { + handler.visit(packet); + } + } + + public void registerHandler(PacketVisitor handler) { + handlers.add(handler); + } + + public void unregisterHandler(PacketVisitor handler) { + handlers.remove(handler); + } + +} diff --git a/app/src/main/java/network/packets/ConnexionInfoPacket.java b/app/src/main/java/network/packets/ConnexionInfoPacket.java new file mode 100644 index 0000000..d9a1b9d --- /dev/null +++ b/app/src/main/java/network/packets/ConnexionInfoPacket.java @@ -0,0 +1,25 @@ +package network.packets; + +import network.Packet; +import network.PacketVisitor; +import network.Packets; + +public class ConnexionInfoPacket extends Packet { + + static private final long serialVersionUID = Packets.ConnectionInfo.ordinal(); + + private final int connectionId; + + public ConnexionInfoPacket(int connectionId) { + this.connectionId = connectionId; + } + + public int getConnectionId() { + return connectionId; + } + + @Override + public void accept(PacketVisitor packetVisitor) { + packetVisitor.visit(this); + } +} diff --git a/app/src/main/java/network/packets/KeepAlivePacket.java b/app/src/main/java/network/packets/KeepAlivePacket.java new file mode 100644 index 0000000..cc4e8c6 --- /dev/null +++ b/app/src/main/java/network/packets/KeepAlivePacket.java @@ -0,0 +1,26 @@ +package network.packets; + +import network.Packet; +import network.PacketVisitor; +import network.Packets; + +public class KeepAlivePacket extends Packet { + + static private final long serialVersionUID = Packets.KeepAlive.ordinal(); + + private final long keepAliveId; + + public KeepAlivePacket(long keepAliveId) { + this.keepAliveId = keepAliveId; + } + + public long getKeepAliveId() { + return keepAliveId; + } + + @Override + public void accept(PacketVisitor packetVisitor) { + packetVisitor.visit(this); + } + +} diff --git a/app/src/main/java/network/server/Server.java b/app/src/main/java/network/server/Server.java new file mode 100644 index 0000000..8ba9e0d --- /dev/null +++ b/app/src/main/java/network/server/Server.java @@ -0,0 +1,28 @@ +package network.server; + +import java.io.IOException; +import java.net.ServerSocket; +import java.util.ArrayList; +import java.util.List; + +public class Server { + + final ServerSocket serverSocket; + final List connexions; + private final ServerThread thread; + + public Server(short port) throws IOException { + this.serverSocket = new ServerSocket(port); + this.connexions = new ArrayList<>(); + this.thread = new ServerThread(this); + this.thread.start(); + } + + public void stop() { + this.thread.cancel(); + for (ServerConnexion connexion : this.connexions) { + connexion.close(); + } + } + +} diff --git a/app/src/main/java/network/server/ServerConnexion.java b/app/src/main/java/network/server/ServerConnexion.java new file mode 100644 index 0000000..b1ba7a7 --- /dev/null +++ b/app/src/main/java/network/server/ServerConnexion.java @@ -0,0 +1,35 @@ +package network.server; + +import java.io.IOException; +import java.net.Socket; +import java.util.Random; + +import network.Connexion; +import network.packets.ConnexionInfoPacket; +import network.packets.KeepAlivePacket; + +public class ServerConnexion extends Connexion{ + + public ServerConnexion(Socket socket) throws IOException { + super(socket); + System.out.println("Bonjour le client !"); + sendKeepAlive(); + } + + public void sendKeepAlive() throws IOException { + Random r = new Random(); + sendPacket(new KeepAlivePacket(r.nextLong())); + } + + @Override + public void visit(ConnexionInfoPacket packet) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'visit'"); + } + + @Override + public void visit(KeepAlivePacket packet) { + System.out.println("Je l'ai reçu !"); + } + +} diff --git a/app/src/main/java/network/server/ServerThread.java b/app/src/main/java/network/server/ServerThread.java new file mode 100644 index 0000000..4844be8 --- /dev/null +++ b/app/src/main/java/network/server/ServerThread.java @@ -0,0 +1,36 @@ +package network.server; + +import java.io.IOException; +import java.net.Socket; + +public class ServerThread extends Thread { + + private final Server server; + + public ServerThread(Server server) { + this.server = server; + } + + public void cancel() { + try { + this.server.serverSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + interrupt(); + } + + @Override + public void run() { + try { + while(!interrupted()) { + Socket newConnection = this.server.serverSocket.accept(); + ServerConnexion serverConnection = new ServerConnexion(newConnection); + this.server.connexions.add(serverConnection); + } + } catch(IOException e) { + // e.printStackTrace(); + } + } + +} From bfe98a2cf0f91207a1e177a81c4c76d984354f90 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Thu, 23 Jan 2025 22:24:23 +0100 Subject: [PATCH 2/7] better network structure --- app/src/main/java/gui/menu/MultiMenu.java | 5 -- app/src/main/java/gui/menu/StateMachine.java | 4 +- app/src/main/java/network/Connexion.java | 12 ++++- .../main/java/network/ConnexionThread.java | 4 +- app/src/main/java/network/PacketFactory.java | 8 --- app/src/main/java/network/PacketVisitor.java | 15 ------ app/src/main/java/network/Packets.java | 7 --- app/src/main/java/network/client/Client.java | 7 ++- .../java/network/client/ClientConnexion.java | 36 +++++++++----- .../java/network/{ => protocol}/Packet.java | 2 +- .../PacketDispatcher.java | 7 +-- .../java/network/protocol/PacketFactory.java | 6 +++ .../java/network/protocol/PacketVisitor.java | 17 +++++++ .../main/java/network/protocol/Packets.java | 7 +++ .../packets/ConnexionInfoPacket.java | 10 ++-- .../protocol/packets/DisconnectPacket.java | 23 +++++++++ .../packets/KeepAlivePacket.java | 10 ++-- .../java/network/server/KeepAliveHandler.java | 49 +++++++++++++++++++ app/src/main/java/network/server/Server.java | 30 ++++++++++-- ...verThread.java => ServerAcceptThread.java} | 6 +-- .../java/network/server/ServerConnexion.java | 48 ++++++++++++------ .../network/server/ServerLogicThread.java | 28 +++++++++++ 22 files changed, 248 insertions(+), 93 deletions(-) delete mode 100644 app/src/main/java/network/PacketFactory.java delete mode 100644 app/src/main/java/network/PacketVisitor.java delete mode 100644 app/src/main/java/network/Packets.java rename app/src/main/java/network/{ => protocol}/Packet.java (87%) rename app/src/main/java/network/{client => protocol}/PacketDispatcher.java (81%) create mode 100644 app/src/main/java/network/protocol/PacketFactory.java create mode 100644 app/src/main/java/network/protocol/PacketVisitor.java create mode 100644 app/src/main/java/network/protocol/Packets.java rename app/src/main/java/network/{ => protocol}/packets/ConnexionInfoPacket.java (68%) create mode 100644 app/src/main/java/network/protocol/packets/DisconnectPacket.java rename app/src/main/java/network/{ => protocol}/packets/KeepAlivePacket.java (67%) create mode 100644 app/src/main/java/network/server/KeepAliveHandler.java rename app/src/main/java/network/server/{ServerThread.java => ServerAcceptThread.java} (83%) create mode 100644 app/src/main/java/network/server/ServerLogicThread.java diff --git a/app/src/main/java/gui/menu/MultiMenu.java b/app/src/main/java/gui/menu/MultiMenu.java index e6e87dc..cecd1fb 100644 --- a/app/src/main/java/gui/menu/MultiMenu.java +++ b/app/src/main/java/gui/menu/MultiMenu.java @@ -6,17 +6,12 @@ import imgui.ImGui; import imgui.ImVec2; import imgui.type.ImInt; import imgui.type.ImString; -import network.client.Client; -import network.server.Server; public class MultiMenu extends BaseView { private final ImInt port = new ImInt(25565); private final ImString address = new ImString("localhost"); - private Server server; - private Client client; - public MultiMenu(StateMachine stateMachine) { super(stateMachine); } diff --git a/app/src/main/java/gui/menu/StateMachine.java b/app/src/main/java/gui/menu/StateMachine.java index c698ac8..9317a25 100644 --- a/app/src/main/java/gui/menu/StateMachine.java +++ b/app/src/main/java/gui/menu/StateMachine.java @@ -27,7 +27,7 @@ public class StateMachine { } public void popState() { - menus.getLast().onKill(); + menus.get(menus.size() - 1).onKill(); menus.pop(); } @@ -43,7 +43,7 @@ public class StateMachine { ImGui.setNextWindowSize(displaySize); ImGui.begin("##Main Window", null, ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoSavedSettings | ImGuiWindowFlags.NoBackground); - menus.getLast().render(); + menus.get(menus.size() - 1).render(); ImGui.end(); checkEscape(); } diff --git a/app/src/main/java/network/Connexion.java b/app/src/main/java/network/Connexion.java index 4dd54da..a565012 100644 --- a/app/src/main/java/network/Connexion.java +++ b/app/src/main/java/network/Connexion.java @@ -4,6 +4,9 @@ import java.io.IOException; import java.io.ObjectOutputStream; import java.net.Socket; +import network.protocol.Packet; +import network.protocol.PacketVisitor; + public abstract class Connexion implements PacketVisitor { final Socket socket; @@ -17,8 +20,13 @@ public abstract class Connexion implements PacketVisitor { this.connexionThread.start(); } - public void sendPacket(Packet packet) throws IOException { - objectOutputStream.writeObject(packet); + public void sendPacket(Packet packet) { + try { + objectOutputStream.writeObject(packet); + } catch (IOException e) { + System.err.println("Error while sending packet ! " + e.getLocalizedMessage()); + close(); + } } public void close() { diff --git a/app/src/main/java/network/ConnexionThread.java b/app/src/main/java/network/ConnexionThread.java index 81ab76c..cba97bf 100644 --- a/app/src/main/java/network/ConnexionThread.java +++ b/app/src/main/java/network/ConnexionThread.java @@ -3,6 +3,8 @@ package network; import java.io.IOException; import java.io.ObjectInputStream; +import network.protocol.Packet; + public class ConnexionThread extends Thread{ private final Connexion connexion; @@ -19,7 +21,7 @@ public class ConnexionThread extends Thread{ try { Object o = objectInputStream.readObject(); if (o instanceof Packet packet) { - connexion.visit(packet); + connexion.visitPacket(packet); } } catch (ClassNotFoundException | IOException e) { break; diff --git a/app/src/main/java/network/PacketFactory.java b/app/src/main/java/network/PacketFactory.java deleted file mode 100644 index 45a879a..0000000 --- a/app/src/main/java/network/PacketFactory.java +++ /dev/null @@ -1,8 +0,0 @@ -package network; - -import java.nio.ByteBuffer; - -public class PacketFactory { - - -} diff --git a/app/src/main/java/network/PacketVisitor.java b/app/src/main/java/network/PacketVisitor.java deleted file mode 100644 index 679a8f5..0000000 --- a/app/src/main/java/network/PacketVisitor.java +++ /dev/null @@ -1,15 +0,0 @@ -package network; - -import network.packets.ConnexionInfoPacket; -import network.packets.KeepAlivePacket; - -public interface PacketVisitor { - - default void visit(Packet packet) { - packet.accept(this); - } - - void visit(ConnexionInfoPacket packet); - void visit(KeepAlivePacket packet); - -} diff --git a/app/src/main/java/network/Packets.java b/app/src/main/java/network/Packets.java deleted file mode 100644 index 6132427..0000000 --- a/app/src/main/java/network/Packets.java +++ /dev/null @@ -1,7 +0,0 @@ -package network; - -public enum Packets { - - ConnectionInfo, KeepAlive - -} diff --git a/app/src/main/java/network/client/Client.java b/app/src/main/java/network/client/Client.java index 4b310ed..2baa2a0 100644 --- a/app/src/main/java/network/client/Client.java +++ b/app/src/main/java/network/client/Client.java @@ -7,11 +7,16 @@ public class Client { private final ClientConnexion clientConnection; public Client(String address, short port) throws UnknownHostException, IOException { - this.clientConnection = new ClientConnexion(address, port); + this.clientConnection = new ClientConnexion(address, port, this); } public void stop() { this.clientConnection.close(); } + + public void onDisconnect() { + // do some stuff + System.out.println("OSEKOUR"); + } } diff --git a/app/src/main/java/network/client/ClientConnexion.java b/app/src/main/java/network/client/ClientConnexion.java index 6ff751c..42b2f1c 100644 --- a/app/src/main/java/network/client/ClientConnexion.java +++ b/app/src/main/java/network/client/ClientConnexion.java @@ -5,29 +5,39 @@ import java.net.Socket; import java.net.UnknownHostException; import network.Connexion; -import network.packets.ConnexionInfoPacket; -import network.packets.KeepAlivePacket; +import network.protocol.packets.ConnexionInfoPacket; +import network.protocol.packets.DisconnectPacket; +import network.protocol.packets.KeepAlivePacket; public class ClientConnexion extends Connexion { - public ClientConnexion(String address, short port) throws UnknownHostException, IOException { + private final Client client; + + public ClientConnexion(String address, short port, Client client) throws UnknownHostException, IOException { super(new Socket(address, port)); + this.client = client; } @Override - public void visit(ConnexionInfoPacket packet) { - + public void close() { + super.close(); + client.onDisconnect(); } @Override - public void visit(KeepAlivePacket packet) { - System.out.println("Coucou !!!!!!!!!!!!!!!!!!!"); - try { - sendPacket(packet); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + public void visitPacket(ConnexionInfoPacket packet) { + + } + + @Override + public void visitPacket(KeepAlivePacket packet) { + // we just send the packet back to the server + sendPacket(packet); + } + + @Override + public void visitPacket(DisconnectPacket packet) { + close(); } } diff --git a/app/src/main/java/network/Packet.java b/app/src/main/java/network/protocol/Packet.java similarity index 87% rename from app/src/main/java/network/Packet.java rename to app/src/main/java/network/protocol/Packet.java index 3bc5765..d7b4c19 100644 --- a/app/src/main/java/network/Packet.java +++ b/app/src/main/java/network/protocol/Packet.java @@ -1,4 +1,4 @@ -package network; +package network.protocol; import java.io.Serializable; diff --git a/app/src/main/java/network/client/PacketDispatcher.java b/app/src/main/java/network/protocol/PacketDispatcher.java similarity index 81% rename from app/src/main/java/network/client/PacketDispatcher.java rename to app/src/main/java/network/protocol/PacketDispatcher.java index 4a6d490..376ab96 100644 --- a/app/src/main/java/network/client/PacketDispatcher.java +++ b/app/src/main/java/network/protocol/PacketDispatcher.java @@ -1,11 +1,8 @@ -package network.client; +package network.protocol; import java.util.ArrayList; import java.util.List; -import network.Packet; -import network.PacketVisitor; - public class PacketDispatcher { private final List handlers; @@ -16,7 +13,7 @@ public class PacketDispatcher { public void dispatch(Packet packet) { for (PacketVisitor handler : handlers) { - handler.visit(packet); + handler.visitPacket(packet); } } diff --git a/app/src/main/java/network/protocol/PacketFactory.java b/app/src/main/java/network/protocol/PacketFactory.java new file mode 100644 index 0000000..14b2347 --- /dev/null +++ b/app/src/main/java/network/protocol/PacketFactory.java @@ -0,0 +1,6 @@ +package network.protocol; + +public class PacketFactory { + + +} diff --git a/app/src/main/java/network/protocol/PacketVisitor.java b/app/src/main/java/network/protocol/PacketVisitor.java new file mode 100644 index 0000000..73babe1 --- /dev/null +++ b/app/src/main/java/network/protocol/PacketVisitor.java @@ -0,0 +1,17 @@ +package network.protocol; + +import network.protocol.packets.ConnexionInfoPacket; +import network.protocol.packets.DisconnectPacket; +import network.protocol.packets.KeepAlivePacket; + +public interface PacketVisitor { + + default void visitPacket(Packet packet) { + packet.accept(this); + } + + void visitPacket(ConnexionInfoPacket packet); + void visitPacket(DisconnectPacket packet); + void visitPacket(KeepAlivePacket packet); + +} diff --git a/app/src/main/java/network/protocol/Packets.java b/app/src/main/java/network/protocol/Packets.java new file mode 100644 index 0000000..716b9be --- /dev/null +++ b/app/src/main/java/network/protocol/Packets.java @@ -0,0 +1,7 @@ +package network.protocol; + +public enum Packets { + + ConnectionInfo, KeepAlive, Disconnect + +} diff --git a/app/src/main/java/network/packets/ConnexionInfoPacket.java b/app/src/main/java/network/protocol/packets/ConnexionInfoPacket.java similarity index 68% rename from app/src/main/java/network/packets/ConnexionInfoPacket.java rename to app/src/main/java/network/protocol/packets/ConnexionInfoPacket.java index d9a1b9d..5be408b 100644 --- a/app/src/main/java/network/packets/ConnexionInfoPacket.java +++ b/app/src/main/java/network/protocol/packets/ConnexionInfoPacket.java @@ -1,8 +1,8 @@ -package network.packets; +package network.protocol.packets; -import network.Packet; -import network.PacketVisitor; -import network.Packets; +import network.protocol.Packet; +import network.protocol.PacketVisitor; +import network.protocol.Packets; public class ConnexionInfoPacket extends Packet { @@ -20,6 +20,6 @@ public class ConnexionInfoPacket extends Packet { @Override public void accept(PacketVisitor packetVisitor) { - packetVisitor.visit(this); + packetVisitor.visitPacket(this); } } diff --git a/app/src/main/java/network/protocol/packets/DisconnectPacket.java b/app/src/main/java/network/protocol/packets/DisconnectPacket.java new file mode 100644 index 0000000..2d8f854 --- /dev/null +++ b/app/src/main/java/network/protocol/packets/DisconnectPacket.java @@ -0,0 +1,23 @@ +package network.protocol.packets; + +import network.protocol.Packet; +import network.protocol.PacketVisitor; + +public class DisconnectPacket extends Packet { + + private final String reason; + + public DisconnectPacket(String reason) { + this.reason = reason; + } + + public String getReason() { + return reason; + } + + @Override + public void accept(PacketVisitor packetVisitor) { + packetVisitor.visitPacket(this); + } + +} diff --git a/app/src/main/java/network/packets/KeepAlivePacket.java b/app/src/main/java/network/protocol/packets/KeepAlivePacket.java similarity index 67% rename from app/src/main/java/network/packets/KeepAlivePacket.java rename to app/src/main/java/network/protocol/packets/KeepAlivePacket.java index cc4e8c6..5804470 100644 --- a/app/src/main/java/network/packets/KeepAlivePacket.java +++ b/app/src/main/java/network/protocol/packets/KeepAlivePacket.java @@ -1,8 +1,8 @@ -package network.packets; +package network.protocol.packets; -import network.Packet; -import network.PacketVisitor; -import network.Packets; +import network.protocol.Packet; +import network.protocol.PacketVisitor; +import network.protocol.Packets; public class KeepAlivePacket extends Packet { @@ -20,7 +20,7 @@ public class KeepAlivePacket extends Packet { @Override public void accept(PacketVisitor packetVisitor) { - packetVisitor.visit(this); + packetVisitor.visitPacket(this); } } diff --git a/app/src/main/java/network/server/KeepAliveHandler.java b/app/src/main/java/network/server/KeepAliveHandler.java new file mode 100644 index 0000000..ae1ba22 --- /dev/null +++ b/app/src/main/java/network/server/KeepAliveHandler.java @@ -0,0 +1,49 @@ +package network.server; + +import java.util.Random; + +import network.protocol.packets.KeepAlivePacket; + +public class KeepAliveHandler { + + private final ServerConnexion serverConnexion; + + private static final int KEEP_ALIVE_COOLDOWN = 5 * 1000; + + private long lastKeepAlive = 0; + private long lastSend = 0; + private volatile boolean keepAliveRecieved = false; + + public KeepAliveHandler(ServerConnexion serverConnexion) { + this.serverConnexion = serverConnexion; + sendKeepAlive(); + } + + public boolean update() { + var currentTime = System.currentTimeMillis(); + if (currentTime - lastSend > KEEP_ALIVE_COOLDOWN) { + if (keepAliveRecieved) { + sendKeepAlive(); + } else { + System.out.println("Zombie"); + serverConnexion.close(); + return false; + } + } + return true; + } + + public void recievedKeepAlive(long keepAliveId) { + if (lastKeepAlive == keepAliveId) + this.keepAliveRecieved = true; + } + + private void sendKeepAlive() { + Random r = new Random(); + lastKeepAlive = r.nextLong(); + lastSend = System.currentTimeMillis(); + keepAliveRecieved = false; + this.serverConnexion.sendPacket(new KeepAlivePacket(lastKeepAlive)); + } + +} diff --git a/app/src/main/java/network/server/Server.java b/app/src/main/java/network/server/Server.java index 8ba9e0d..ac07cf7 100644 --- a/app/src/main/java/network/server/Server.java +++ b/app/src/main/java/network/server/Server.java @@ -5,21 +5,43 @@ import java.net.ServerSocket; import java.util.ArrayList; import java.util.List; +import network.protocol.Packet; + public class Server { final ServerSocket serverSocket; final List connexions; - private final ServerThread thread; + private final ServerAcceptThread acceptThread; + private final ServerLogicThread logicThread; public Server(short port) throws IOException { this.serverSocket = new ServerSocket(port); this.connexions = new ArrayList<>(); - this.thread = new ServerThread(this); - this.thread.start(); + this.acceptThread = new ServerAcceptThread(this); + this.acceptThread.start(); + this.logicThread = new ServerLogicThread(this); + this.logicThread.start(); + } + + public void broadcastPacket(Packet packet) { + for (ServerConnexion connexion : this.connexions) { + connexion.sendPacket(packet); + } + } + + public void update() { + for (var it = connexions.iterator(); it.hasNext();) { + ServerConnexion connexion = it.next(); + if(!connexion.update()) { + connexion.close(); + it.remove(); + } + } } public void stop() { - this.thread.cancel(); + this.acceptThread.cancel(); + this.logicThread.cancel(); for (ServerConnexion connexion : this.connexions) { connexion.close(); } diff --git a/app/src/main/java/network/server/ServerThread.java b/app/src/main/java/network/server/ServerAcceptThread.java similarity index 83% rename from app/src/main/java/network/server/ServerThread.java rename to app/src/main/java/network/server/ServerAcceptThread.java index 4844be8..61800db 100644 --- a/app/src/main/java/network/server/ServerThread.java +++ b/app/src/main/java/network/server/ServerAcceptThread.java @@ -3,11 +3,11 @@ package network.server; import java.io.IOException; import java.net.Socket; -public class ServerThread extends Thread { +public class ServerAcceptThread extends Thread { private final Server server; - public ServerThread(Server server) { + public ServerAcceptThread(Server server) { this.server = server; } @@ -25,7 +25,7 @@ public class ServerThread extends Thread { try { while(!interrupted()) { Socket newConnection = this.server.serverSocket.accept(); - ServerConnexion serverConnection = new ServerConnexion(newConnection); + ServerConnexion serverConnection = new ServerConnexion(newConnection, this.server); this.server.connexions.add(serverConnection); } } catch(IOException e) { diff --git a/app/src/main/java/network/server/ServerConnexion.java b/app/src/main/java/network/server/ServerConnexion.java index b1ba7a7..9ac20cb 100644 --- a/app/src/main/java/network/server/ServerConnexion.java +++ b/app/src/main/java/network/server/ServerConnexion.java @@ -2,34 +2,50 @@ package network.server; import java.io.IOException; import java.net.Socket; -import java.util.Random; import network.Connexion; -import network.packets.ConnexionInfoPacket; -import network.packets.KeepAlivePacket; +import network.protocol.packets.ConnexionInfoPacket; +import network.protocol.packets.DisconnectPacket; +import network.protocol.packets.KeepAlivePacket; -public class ServerConnexion extends Connexion{ +public class ServerConnexion extends Connexion { - public ServerConnexion(Socket socket) throws IOException { + private final Server server; + private final KeepAliveHandler keepAliveHandler; + private boolean shouldClose = false; + + public ServerConnexion(Socket socket, Server server) throws IOException { super(socket); - System.out.println("Bonjour le client !"); - sendKeepAlive(); + this.server = server; + this.keepAliveHandler = new KeepAliveHandler(this); } - public void sendKeepAlive() throws IOException { - Random r = new Random(); - sendPacket(new KeepAlivePacket(r.nextLong())); + public boolean update() { + if (shouldClose) + return false; + return this.keepAliveHandler.update(); } @Override - public void visit(ConnexionInfoPacket packet) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'visit'"); + public void close() { + sendPacket(new DisconnectPacket("Server stopped")); + super.close(); + shouldClose = true; } @Override - public void visit(KeepAlivePacket packet) { - System.out.println("Je l'ai reçu !"); + public void visitPacket(ConnexionInfoPacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacket'"); } - + + @Override + public void visitPacket(KeepAlivePacket packet) { + this.keepAliveHandler.recievedKeepAlive(packet.getKeepAliveId()); + } + + @Override + public void visitPacket(DisconnectPacket packet) { + close(); + } + } diff --git a/app/src/main/java/network/server/ServerLogicThread.java b/app/src/main/java/network/server/ServerLogicThread.java new file mode 100644 index 0000000..c9b2a4b --- /dev/null +++ b/app/src/main/java/network/server/ServerLogicThread.java @@ -0,0 +1,28 @@ +package network.server; + +public class ServerLogicThread extends Thread { + + private final Server server; + + public ServerLogicThread(Server server) { + this.server = server; + } + + public void cancel() { + interrupt(); + } + + @Override + public void run() { + while (!interrupted()) { + server.update(); + try { + Thread.sleep(50); + } catch (InterruptedException e) { + // e.printStackTrace(); + break; + } + } + } + +} From caf7011f08ea8d00efdce0e3adf52cb40b8a874c Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Thu, 23 Jan 2025 22:24:48 +0100 Subject: [PATCH 3/7] update Gradle --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index bdc9a83..5c40527 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From e51cc2345955257c43853faf77f987acf646ab69 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 26 Jan 2025 13:46:23 +0100 Subject: [PATCH 4/7] mooore stuff --- app/src/main/java/common/Signal.java | 31 ++++++++++ app/src/main/java/game/Game.java | 30 ++++++++++ app/src/main/java/game/Player.java | 25 ++++++++ app/src/main/java/gui/menu/BaseView.java | 2 +- .../java/gui/menu/ConnexionStatusView.java | 60 +++++++++++++++++++ app/src/main/java/gui/menu/MultiMenu.java | 4 +- .../main/java/gui/menu/MultiPlayerView.java | 53 +++++----------- app/src/main/java/gui/menu/StateMachine.java | 6 +- app/src/main/java/network/Connexion.java | 7 ++- .../main/java/network/ConnexionThread.java | 7 ++- app/src/main/java/network/client/Client.java | 33 ++++++++-- .../java/network/client/ClientConnexion.java | 30 +++++++++- .../java/network/protocol/PacketVisitor.java | 6 ++ .../main/java/network/protocol/Packets.java | 2 +- .../protocol/packets/DisconnectPacket.java | 3 + .../network/protocol/packets/LoginPacket.java | 26 ++++++++ .../protocol/packets/PlayerJoinPacket.java | 29 +++++++++ .../protocol/packets/PlayerLeavePacket.java | 28 +++++++++ app/src/main/java/network/server/Server.java | 19 +++++- .../java/network/server/ServerConnexion.java | 59 +++++++++++++++--- 20 files changed, 395 insertions(+), 65 deletions(-) create mode 100644 app/src/main/java/common/Signal.java create mode 100644 app/src/main/java/game/Game.java create mode 100644 app/src/main/java/game/Player.java create mode 100644 app/src/main/java/gui/menu/ConnexionStatusView.java create mode 100644 app/src/main/java/network/protocol/packets/LoginPacket.java create mode 100644 app/src/main/java/network/protocol/packets/PlayerJoinPacket.java create mode 100644 app/src/main/java/network/protocol/packets/PlayerLeavePacket.java diff --git a/app/src/main/java/common/Signal.java b/app/src/main/java/common/Signal.java new file mode 100644 index 0000000..6e4154d --- /dev/null +++ b/app/src/main/java/common/Signal.java @@ -0,0 +1,31 @@ +package common; + +import java.util.HashSet; +import java.util.Set; + +public class Signal { + + private final Set listeners; + + public Signal() { + this.listeners = new HashSet<>(); + } + + public void connect(Runnable listener) { + this.listeners.add(listener); + } + + public void clear() { + this.listeners.clear(); + } + + public void emit() { + for (Runnable listener : this.listeners) { + listener.run(); + } + } + + // public void disconnect(Runnable listener) { + // this.listeners.remove(listener); + // } +} diff --git a/app/src/main/java/game/Game.java b/app/src/main/java/game/Game.java new file mode 100644 index 0000000..e3aaa82 --- /dev/null +++ b/app/src/main/java/game/Game.java @@ -0,0 +1,30 @@ +package game; + +import java.util.HashMap; +import java.util.Map; + +public class Game { + + private final Map players; + + public Game() { + this.players = new HashMap<>(); + } + + public Player getPlayerById(int id) { + return players.get(id); + } + + public void addPlayer(Player player) { + players.put(player.getId(), player); + } + + public void removePlayer(int id) { + players.remove(id); + } + + public Map getPlayers() { + return players; + } + +} diff --git a/app/src/main/java/game/Player.java b/app/src/main/java/game/Player.java new file mode 100644 index 0000000..2336152 --- /dev/null +++ b/app/src/main/java/game/Player.java @@ -0,0 +1,25 @@ +package game; + +import java.io.Serializable; + +public class Player implements Serializable { + + static private final long serialVersionUID = 9999; + + private final String pseudo; + private final int id; + + public Player(int id, String pseudo) { + this.pseudo = pseudo; + this.id = id; + } + + public String getPseudo() { + return this.pseudo; + } + + public int getId() { + return this.id; + } + +} diff --git a/app/src/main/java/gui/menu/BaseView.java b/app/src/main/java/gui/menu/BaseView.java index 9992279..de5c16d 100644 --- a/app/src/main/java/gui/menu/BaseView.java +++ b/app/src/main/java/gui/menu/BaseView.java @@ -12,7 +12,7 @@ public abstract class BaseView { public abstract void render(); - public void onKill() {} + public void cleanResources() {} public void closeMenu() { this.stateMachine.popState(); diff --git a/app/src/main/java/gui/menu/ConnexionStatusView.java b/app/src/main/java/gui/menu/ConnexionStatusView.java new file mode 100644 index 0000000..82cb12f --- /dev/null +++ b/app/src/main/java/gui/menu/ConnexionStatusView.java @@ -0,0 +1,60 @@ +package gui.menu; + +import java.io.IOException; +import java.net.UnknownHostException; + +import imgui.ImGui; +import network.client.Client; +import network.server.Server; + +public class ConnexionStatusView extends BaseView { + + private Client client; + private Server server; + + public ConnexionStatusView(StateMachine stateMachine, String address, short port) throws UnknownHostException, IOException { + this(stateMachine, null, new Client(address, port)); + } + + public ConnexionStatusView(StateMachine stateMachine, short port) throws UnknownHostException, IOException { + this(stateMachine, new Server(port), new Client("localhost", port)); + } + + private ConnexionStatusView(StateMachine stateMachine, Server server, Client client) { + super(stateMachine); + this.client = client; + this.client.onConnect.connect(this::onConnect); + this.client.onClosed.connect(this::onLeave); + this.server = server; + } + + public void onConnect() { + // System.out.println("Connecté"); + this.stateMachine.pushState(new MultiPlayerView(stateMachine, client)); + } + + public void onLeave() { + // System.out.println("Quitté !"); + this.client.onDisconnect.clear(); + this.client = null; + // on passe le menu de la connexion + this.closeMenu(); + } + + @Override + public void render() { + ImGui.text("Connecting ..."); + } + + @Override + public void cleanResources() { + // System.out.println("Bye bye !"); + if (this.server != null) { + this.server.stop(); + } + if (this.client != null) { + this.client.stop(); + } + } + +} diff --git a/app/src/main/java/gui/menu/MultiMenu.java b/app/src/main/java/gui/menu/MultiMenu.java index cecd1fb..090f629 100644 --- a/app/src/main/java/gui/menu/MultiMenu.java +++ b/app/src/main/java/gui/menu/MultiMenu.java @@ -22,7 +22,7 @@ public class MultiMenu extends BaseView { ImGui.inputInt("Port", port); if (ImGui.button("Créer")) { try { - this.stateMachine.pushState(new MultiPlayerView(stateMachine, (short) port.get())); + this.stateMachine.pushState(new ConnexionStatusView(stateMachine, (short) port.get())); } catch (IOException e) { e.printStackTrace(); } @@ -37,7 +37,7 @@ public class MultiMenu extends BaseView { ImGui.inputInt("Port", port); if (ImGui.button("Rejoindre")) { try { - this.stateMachine.pushState(new MultiPlayerView(stateMachine, address.get(), (short) port.get())); + this.stateMachine.pushState(new ConnexionStatusView(stateMachine, address.get(), (short) port.get())); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); diff --git a/app/src/main/java/gui/menu/MultiPlayerView.java b/app/src/main/java/gui/menu/MultiPlayerView.java index 3646f1c..a4d3e83 100644 --- a/app/src/main/java/gui/menu/MultiPlayerView.java +++ b/app/src/main/java/gui/menu/MultiPlayerView.java @@ -1,53 +1,28 @@ package gui.menu; -import java.io.IOException; -import java.net.UnknownHostException; - import imgui.ImGui; import network.client.Client; -import network.server.Server; public class MultiPlayerView extends BaseView { + + private final Client client; - private Client client; - private Server server; - - /** - * Client - * - * @param stateMachine - * @param address - * @param port - * @throws IOException - * @throws UnknownHostException - */ - public MultiPlayerView(StateMachine stateMachine, String address, short port) - throws UnknownHostException, IOException { + public MultiPlayerView(StateMachine stateMachine, Client client) { super(stateMachine); - this.client = new Client(address, port); - } - - /** - * Server - * - * @param stateMachine - * @param port - * @throws IOException - */ - public MultiPlayerView(StateMachine stateMachine, short port) throws IOException { - super(stateMachine); - this.server = new Server(port); - this.client = new Client("localhost", port); + this.client = client; + this.client.onDisconnect.connect(this::onDisconnect); } @Override - public void onKill() { - if (this.server != null) { - this.server.stop(); - } - if (this.client != null) { - this.client.stop(); - } + public void closeMenu() { + this.client.forceDisconnect(); + super.closeMenu(); + } + + public void onDisconnect() { + // System.out.println("ohohohohohohoho"); + this.stateMachine.popState(); + this.client.onDisconnect.clear(); } @Override diff --git a/app/src/main/java/gui/menu/StateMachine.java b/app/src/main/java/gui/menu/StateMachine.java index 9317a25..81ea005 100644 --- a/app/src/main/java/gui/menu/StateMachine.java +++ b/app/src/main/java/gui/menu/StateMachine.java @@ -17,7 +17,7 @@ public class StateMachine { public void clear() { for (BaseView view : menus) { - view.onKill(); + view.cleanResources(); } menus.clear(); } @@ -27,13 +27,13 @@ public class StateMachine { } public void popState() { - menus.get(menus.size() - 1).onKill(); + menus.getLast().cleanResources(); menus.pop(); } private void checkEscape() { if (ImGui.isKeyPressed(ImGuiKey.Escape) && menus.size() > 1) { - popState(); + menus.getLast().closeMenu(); } } diff --git a/app/src/main/java/network/Connexion.java b/app/src/main/java/network/Connexion.java index a565012..1b1e285 100644 --- a/app/src/main/java/network/Connexion.java +++ b/app/src/main/java/network/Connexion.java @@ -20,9 +20,14 @@ public abstract class Connexion implements PacketVisitor { this.connexionThread.start(); } - public void sendPacket(Packet packet) { + public boolean isClosed() { + return this.socket.isClosed(); + } + + public synchronized void sendPacket(Packet packet) { try { objectOutputStream.writeObject(packet); + objectOutputStream.flush(); } catch (IOException e) { System.err.println("Error while sending packet ! " + e.getLocalizedMessage()); close(); diff --git a/app/src/main/java/network/ConnexionThread.java b/app/src/main/java/network/ConnexionThread.java index cba97bf..6752d92 100644 --- a/app/src/main/java/network/ConnexionThread.java +++ b/app/src/main/java/network/ConnexionThread.java @@ -5,7 +5,7 @@ import java.io.ObjectInputStream; import network.protocol.Packet; -public class ConnexionThread extends Thread{ +public class ConnexionThread extends Thread { private final Connexion connexion; private final ObjectInputStream objectInputStream; @@ -17,13 +17,16 @@ public class ConnexionThread extends Thread{ @Override public void run() { - while(!interrupted()) { + while (!interrupted()) { try { + // System.out.println(objectInputStream.available()); Object o = objectInputStream.readObject(); if (o instanceof Packet packet) { connexion.visitPacket(packet); } } catch (ClassNotFoundException | IOException e) { + e.printStackTrace(); + this.connexion.close(); break; } } diff --git a/app/src/main/java/network/client/Client.java b/app/src/main/java/network/client/Client.java index 2baa2a0..a6d8efc 100644 --- a/app/src/main/java/network/client/Client.java +++ b/app/src/main/java/network/client/Client.java @@ -3,20 +3,45 @@ package network.client; import java.io.IOException; import java.net.UnknownHostException; +import common.Signal; +import game.Game; +import game.Player; +import network.protocol.packets.LoginPacket; + public class Client { private final ClientConnexion clientConnection; + private final Game game; + + public final Signal onConnect = new Signal(); + public final Signal onDisconnect = new Signal(); + public final Signal onClosed = new Signal(); public Client(String address, short port) throws UnknownHostException, IOException { this.clientConnection = new ClientConnexion(address, port, this); + this.game = new Game(); + login("Player2" + Math.random()); + } + + public void login(String pseudo) { + System.out.println("Logging in with pseudo " + pseudo + " ..."); + this.clientConnection.sendPacket(new LoginPacket(pseudo)); } public void stop() { this.clientConnection.close(); } - public void onDisconnect() { - // do some stuff - System.out.println("OSEKOUR"); + public void addPlayer(Player player) { + this.game.addPlayer(player); } - + + public Game getGame() { + return game; + } + + public void forceDisconnect() { + this.onClosed.emit(); + stop(); + } + } diff --git a/app/src/main/java/network/client/ClientConnexion.java b/app/src/main/java/network/client/ClientConnexion.java index 42b2f1c..07ca721 100644 --- a/app/src/main/java/network/client/ClientConnexion.java +++ b/app/src/main/java/network/client/ClientConnexion.java @@ -4,14 +4,19 @@ import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; +import game.Player; import network.Connexion; import network.protocol.packets.ConnexionInfoPacket; import network.protocol.packets.DisconnectPacket; import network.protocol.packets.KeepAlivePacket; +import network.protocol.packets.LoginPacket; +import network.protocol.packets.PlayerJoinPacket; +import network.protocol.packets.PlayerLeavePacket; public class ClientConnexion extends Connexion { private final Client client; + private Player player = null; public ClientConnexion(String address, short port, Client client) throws UnknownHostException, IOException { super(new Socket(address, port)); @@ -20,13 +25,16 @@ public class ClientConnexion extends Connexion { @Override public void close() { - super.close(); - client.onDisconnect(); + if (!this.isClosed()) { + super.close(); + client.onDisconnect.emit(); + } } @Override public void visitPacket(ConnexionInfoPacket packet) { - + this.player = this.client.getGame().getPlayerById(packet.getConnectionId()); + client.onConnect.emit(); } @Override @@ -40,4 +48,20 @@ public class ClientConnexion extends Connexion { close(); } + @Override + public void visitPacket(LoginPacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacketLogin'"); + } + + @Override + public void visitPacket(PlayerJoinPacket packet) { + this.client.addPlayer(packet.getPlayer()); + System.out.println("[Client] " + packet.getPlayer().getPseudo() + " joined the game !"); + } + + @Override + public void visitPacket(PlayerLeavePacket packet) { + this.client.getGame().removePlayer(packet.getPlayer()); + } + } diff --git a/app/src/main/java/network/protocol/PacketVisitor.java b/app/src/main/java/network/protocol/PacketVisitor.java index 73babe1..f57e0bf 100644 --- a/app/src/main/java/network/protocol/PacketVisitor.java +++ b/app/src/main/java/network/protocol/PacketVisitor.java @@ -3,6 +3,9 @@ package network.protocol; import network.protocol.packets.ConnexionInfoPacket; import network.protocol.packets.DisconnectPacket; import network.protocol.packets.KeepAlivePacket; +import network.protocol.packets.LoginPacket; +import network.protocol.packets.PlayerJoinPacket; +import network.protocol.packets.PlayerLeavePacket; public interface PacketVisitor { @@ -13,5 +16,8 @@ public interface PacketVisitor { void visitPacket(ConnexionInfoPacket packet); void visitPacket(DisconnectPacket packet); void visitPacket(KeepAlivePacket packet); + void visitPacket(LoginPacket packet); + void visitPacket(PlayerJoinPacket packet); + void visitPacket(PlayerLeavePacket packet); } diff --git a/app/src/main/java/network/protocol/Packets.java b/app/src/main/java/network/protocol/Packets.java index 716b9be..27b5162 100644 --- a/app/src/main/java/network/protocol/Packets.java +++ b/app/src/main/java/network/protocol/Packets.java @@ -2,6 +2,6 @@ package network.protocol; public enum Packets { - ConnectionInfo, KeepAlive, Disconnect + ConnectionInfo, KeepAlive, Disconnect, Login, PlayerJoin, PlayerLeave } diff --git a/app/src/main/java/network/protocol/packets/DisconnectPacket.java b/app/src/main/java/network/protocol/packets/DisconnectPacket.java index 2d8f854..bcec9ba 100644 --- a/app/src/main/java/network/protocol/packets/DisconnectPacket.java +++ b/app/src/main/java/network/protocol/packets/DisconnectPacket.java @@ -2,9 +2,12 @@ package network.protocol.packets; import network.protocol.Packet; import network.protocol.PacketVisitor; +import network.protocol.Packets; public class DisconnectPacket extends Packet { + static private final long serialVersionUID = Packets.Disconnect.ordinal(); + private final String reason; public DisconnectPacket(String reason) { diff --git a/app/src/main/java/network/protocol/packets/LoginPacket.java b/app/src/main/java/network/protocol/packets/LoginPacket.java new file mode 100644 index 0000000..237dd3f --- /dev/null +++ b/app/src/main/java/network/protocol/packets/LoginPacket.java @@ -0,0 +1,26 @@ +package network.protocol.packets; + +import network.protocol.Packet; +import network.protocol.PacketVisitor; +import network.protocol.Packets; + +public class LoginPacket extends Packet { + + static private final long serialVersionUID = Packets.Login.ordinal(); + + private final String pseudo; + + public LoginPacket(String pseudo) { + this.pseudo = pseudo; + } + + public String getPseudo() { + return pseudo; + } + + @Override + public void accept(PacketVisitor packetVisitor) { + packetVisitor.visitPacket(this); + } + +} diff --git a/app/src/main/java/network/protocol/packets/PlayerJoinPacket.java b/app/src/main/java/network/protocol/packets/PlayerJoinPacket.java new file mode 100644 index 0000000..4badf2d --- /dev/null +++ b/app/src/main/java/network/protocol/packets/PlayerJoinPacket.java @@ -0,0 +1,29 @@ +package network.protocol.packets; + +import game.Player; +import network.protocol.Packet; +import network.protocol.PacketVisitor; +import network.protocol.Packets; + +public class PlayerJoinPacket extends Packet{ + + static private final long serialVersionUID = Packets.PlayerJoin.ordinal(); + + private final Player player; + + public PlayerJoinPacket(Player player) { + this.player = player; + } + + public Player getPlayer() { + return player; + } + + @Override + public void accept(PacketVisitor packetVisitor) { + packetVisitor.visitPacket(this); + } + + + +} diff --git a/app/src/main/java/network/protocol/packets/PlayerLeavePacket.java b/app/src/main/java/network/protocol/packets/PlayerLeavePacket.java new file mode 100644 index 0000000..b22b7cc --- /dev/null +++ b/app/src/main/java/network/protocol/packets/PlayerLeavePacket.java @@ -0,0 +1,28 @@ +package network.protocol.packets; + +import network.protocol.Packet; +import network.protocol.PacketVisitor; +import network.protocol.Packets; + +public class PlayerLeavePacket extends Packet{ + + static private final long serialVersionUID = Packets.PlayerLeave.ordinal(); + + private final int playerId; + + public PlayerLeavePacket(int playerId) { + this.playerId = playerId; + } + + public int getPlayer() { + return playerId; + } + + @Override + public void accept(PacketVisitor packetVisitor) { + packetVisitor.visitPacket(this); + } + + + +} diff --git a/app/src/main/java/network/server/Server.java b/app/src/main/java/network/server/Server.java index ac07cf7..a8d8765 100644 --- a/app/src/main/java/network/server/Server.java +++ b/app/src/main/java/network/server/Server.java @@ -5,6 +5,8 @@ import java.net.ServerSocket; import java.util.ArrayList; import java.util.List; +import game.Game; +import game.Player; import network.protocol.Packet; public class Server { @@ -13,6 +15,8 @@ public class Server { final List connexions; private final ServerAcceptThread acceptThread; private final ServerLogicThread logicThread; + private final Game game; + private int nextPlayerId = 0; public Server(short port) throws IOException { this.serverSocket = new ServerSocket(port); @@ -21,6 +25,7 @@ public class Server { this.acceptThread.start(); this.logicThread = new ServerLogicThread(this); this.logicThread.start(); + this.game = new Game(); } public void broadcastPacket(Packet packet) { @@ -32,8 +37,9 @@ public class Server { public void update() { for (var it = connexions.iterator(); it.hasNext();) { ServerConnexion connexion = it.next(); - if(!connexion.update()) { + if (!connexion.update()) { connexion.close(); + connexion.nukeConnection(); it.remove(); } } @@ -47,4 +53,15 @@ public class Server { } } + public Player addPlayer(String pseudo) { + Player p = new Player(nextPlayerId, pseudo); + this.game.addPlayer(p); + nextPlayerId++; + return p; + } + + public Game getGame() { + return game; + } + } diff --git a/app/src/main/java/network/server/ServerConnexion.java b/app/src/main/java/network/server/ServerConnexion.java index 9ac20cb..a4eb568 100644 --- a/app/src/main/java/network/server/ServerConnexion.java +++ b/app/src/main/java/network/server/ServerConnexion.java @@ -3,16 +3,21 @@ package network.server; import java.io.IOException; import java.net.Socket; +import game.Player; import network.Connexion; import network.protocol.packets.ConnexionInfoPacket; import network.protocol.packets.DisconnectPacket; import network.protocol.packets.KeepAlivePacket; +import network.protocol.packets.LoginPacket; +import network.protocol.packets.PlayerJoinPacket; +import network.protocol.packets.PlayerLeavePacket; public class ServerConnexion extends Connexion { private final Server server; private final KeepAliveHandler keepAliveHandler; private boolean shouldClose = false; + private Player player = null; public ServerConnexion(Socket socket, Server server) throws IOException { super(socket); @@ -21,21 +26,36 @@ public class ServerConnexion extends Connexion { } public boolean update() { - if (shouldClose) + if (shouldClose | isClosed()) return false; return this.keepAliveHandler.update(); } - @Override - public void close() { - sendPacket(new DisconnectPacket("Server stopped")); - super.close(); - shouldClose = true; + public void nukeConnection() { + if (player != null) { + sendPacket(new DisconnectPacket("Server stopped")); + this.server.broadcastPacket(new PlayerLeavePacket(player.getId())); + this.server.getGame().removePlayer(player.getId()); + } } @Override - public void visitPacket(ConnexionInfoPacket packet) { - throw new UnsupportedOperationException("Unimplemented method 'visitPacket'"); + public synchronized void close() { + if(shouldClose) + return; + super.close(); + shouldClose = true; + System.out.println("[Server] Closing connexion !"); + } + + private void finishLogin() { + // send players that have already joined (excluding this one) + for (Player p : this.server.getGame().getPlayers().values()) { + if (p.getId() != player.getId()) + sendPacket(new PlayerJoinPacket(p)); + } + this.server.broadcastPacket(new PlayerJoinPacket(player)); + sendPacket(new ConnexionInfoPacket(player.getId())); } @Override @@ -48,4 +68,27 @@ public class ServerConnexion extends Connexion { close(); } + @Override + public void visitPacket(LoginPacket packet) { + if (this.player != null) + return; + this.player = this.server.addPlayer(packet.getPseudo()); + finishLogin(); + } + + @Override + public void visitPacket(ConnexionInfoPacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacketConnexionInfo'"); + } + + @Override + public void visitPacket(PlayerJoinPacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacketPlayerJoin'"); + } + + @Override + public void visitPacket(PlayerLeavePacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacketPlayerLeave'"); + } + } From 47dc35ebfa0cedbb92ad71ccf5b7d7657ae04a48 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 26 Jan 2025 14:54:46 +0100 Subject: [PATCH 5/7] more stable connexion --- .../java/gui/menu/ConnexionStatusView.java | 63 ++++++++++++++++--- app/src/main/java/gui/menu/MultiMenu.java | 1 + .../main/java/gui/menu/MultiPlayerView.java | 2 - app/src/main/java/network/client/Client.java | 6 ++ .../java/network/client/ClientConnexion.java | 1 + app/src/main/java/network/server/Server.java | 1 + .../java/network/server/ServerConnexion.java | 2 +- 7 files changed, 64 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/gui/menu/ConnexionStatusView.java b/app/src/main/java/gui/menu/ConnexionStatusView.java index 82cb12f..0182797 100644 --- a/app/src/main/java/gui/menu/ConnexionStatusView.java +++ b/app/src/main/java/gui/menu/ConnexionStatusView.java @@ -12,30 +12,68 @@ public class ConnexionStatusView extends BaseView { private Client client; private Server server; - public ConnexionStatusView(StateMachine stateMachine, String address, short port) throws UnknownHostException, IOException { - this(stateMachine, null, new Client(address, port)); + private String displayText = "Connecting ..."; + + public ConnexionStatusView(StateMachine stateMachine, String address, short port) + throws UnknownHostException, IOException { + super(stateMachine); + Thread t = new Thread(() -> { + try { + this.client = new Client(address, port); + bindListeners(); + } catch (IOException e) { + e.printStackTrace(); + onDisconnect(); + } + }); + t.start(); } public ConnexionStatusView(StateMachine stateMachine, short port) throws UnknownHostException, IOException { - this(stateMachine, new Server(port), new Client("localhost", port)); + super(stateMachine); + Thread t = new Thread(() -> { + try { + this.server = new Server(port); + this.client = new Client("localhost", port); + bindListeners(); + } catch (IOException e) { + e.printStackTrace(); + onDisconnect(); + } + }); + t.start(); + } + + private void bindListeners() { + this.client.onConnect.connect(this::onConnect); + this.client.onClosed.connect(this::onLeave); + this.client.onDisconnect.connect(this::onDisconnect); } private ConnexionStatusView(StateMachine stateMachine, Server server, Client client) { super(stateMachine); this.client = client; - this.client.onConnect.connect(this::onConnect); - this.client.onClosed.connect(this::onLeave); this.server = server; } public void onConnect() { - // System.out.println("Connecté"); this.stateMachine.pushState(new MultiPlayerView(stateMachine, client)); } + public void onDisconnect() { + if (client != null) { + String reason = client.getDisconnectReason(); + if (reason == null) + displayText = "Le serveur a fermé la connexion !"; + else + displayText = "Vous avez été déconnecté ! Raison : " + client.getDisconnectReason(); + } else { + displayText = "La connexion a échoué !"; + } + + } + public void onLeave() { - // System.out.println("Quitté !"); - this.client.onDisconnect.clear(); this.client = null; // on passe le menu de la connexion this.closeMenu(); @@ -43,7 +81,14 @@ public class ConnexionStatusView extends BaseView { @Override public void render() { - ImGui.text("Connecting ..."); + ImGui.text(displayText); + renderReturnButton(); + } + + @Override + public void closeMenu() { + super.closeMenu(); + cleanResources(); } @Override diff --git a/app/src/main/java/gui/menu/MultiMenu.java b/app/src/main/java/gui/menu/MultiMenu.java index 090f629..7b5dc86 100644 --- a/app/src/main/java/gui/menu/MultiMenu.java +++ b/app/src/main/java/gui/menu/MultiMenu.java @@ -14,6 +14,7 @@ public class MultiMenu extends BaseView { public MultiMenu(StateMachine stateMachine) { super(stateMachine); + address.resize(20); } private void renderCreate() { diff --git a/app/src/main/java/gui/menu/MultiPlayerView.java b/app/src/main/java/gui/menu/MultiPlayerView.java index a4d3e83..ec25b82 100644 --- a/app/src/main/java/gui/menu/MultiPlayerView.java +++ b/app/src/main/java/gui/menu/MultiPlayerView.java @@ -20,9 +20,7 @@ public class MultiPlayerView extends BaseView { } public void onDisconnect() { - // System.out.println("ohohohohohohoho"); this.stateMachine.popState(); - this.client.onDisconnect.clear(); } @Override diff --git a/app/src/main/java/network/client/Client.java b/app/src/main/java/network/client/Client.java index a6d8efc..6cdaa4b 100644 --- a/app/src/main/java/network/client/Client.java +++ b/app/src/main/java/network/client/Client.java @@ -16,6 +16,8 @@ public class Client { public final Signal onDisconnect = new Signal(); public final Signal onClosed = new Signal(); + String disconnectReason = null; + public Client(String address, short port) throws UnknownHostException, IOException { this.clientConnection = new ClientConnexion(address, port, this); this.game = new Game(); @@ -39,6 +41,10 @@ public class Client { return game; } + public String getDisconnectReason() { + return disconnectReason; + } + public void forceDisconnect() { this.onClosed.emit(); stop(); diff --git a/app/src/main/java/network/client/ClientConnexion.java b/app/src/main/java/network/client/ClientConnexion.java index 07ca721..ca8d6c5 100644 --- a/app/src/main/java/network/client/ClientConnexion.java +++ b/app/src/main/java/network/client/ClientConnexion.java @@ -45,6 +45,7 @@ public class ClientConnexion extends Connexion { @Override public void visitPacket(DisconnectPacket packet) { + this.client.disconnectReason = packet.getReason(); close(); } diff --git a/app/src/main/java/network/server/Server.java b/app/src/main/java/network/server/Server.java index a8d8765..18f0b4d 100644 --- a/app/src/main/java/network/server/Server.java +++ b/app/src/main/java/network/server/Server.java @@ -49,6 +49,7 @@ public class Server { this.acceptThread.cancel(); this.logicThread.cancel(); for (ServerConnexion connexion : this.connexions) { + connexion.nukeConnection(); connexion.close(); } } diff --git a/app/src/main/java/network/server/ServerConnexion.java b/app/src/main/java/network/server/ServerConnexion.java index a4eb568..a393408 100644 --- a/app/src/main/java/network/server/ServerConnexion.java +++ b/app/src/main/java/network/server/ServerConnexion.java @@ -33,7 +33,7 @@ public class ServerConnexion extends Connexion { public void nukeConnection() { if (player != null) { - sendPacket(new DisconnectPacket("Server stopped")); + sendPacket(new DisconnectPacket("Le serveur a été fermé !")); this.server.broadcastPacket(new PlayerLeavePacket(player.getId())); this.server.getGame().removePlayer(player.getId()); } From 6658b0e8845c2ce2583efc15b3bb081b79de587d Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 26 Jan 2025 18:22:20 +0100 Subject: [PATCH 6/7] show player names --- .../java/gui/menu/ConnexionStatusView.java | 2 +- .../main/java/gui/menu/MultiPlayerView.java | 28 ++++++++++++++++--- app/src/main/java/gui/menu/StateMachine.java | 1 + app/src/main/java/network/client/Client.java | 6 +++- 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/gui/menu/ConnexionStatusView.java b/app/src/main/java/gui/menu/ConnexionStatusView.java index 0182797..13f527f 100644 --- a/app/src/main/java/gui/menu/ConnexionStatusView.java +++ b/app/src/main/java/gui/menu/ConnexionStatusView.java @@ -57,7 +57,7 @@ public class ConnexionStatusView extends BaseView { } public void onConnect() { - this.stateMachine.pushState(new MultiPlayerView(stateMachine, client)); + this.stateMachine.pushState(new MultiPlayerView(stateMachine, client, server)); } public void onDisconnect() { diff --git a/app/src/main/java/gui/menu/MultiPlayerView.java b/app/src/main/java/gui/menu/MultiPlayerView.java index ec25b82..37846ca 100644 --- a/app/src/main/java/gui/menu/MultiPlayerView.java +++ b/app/src/main/java/gui/menu/MultiPlayerView.java @@ -1,15 +1,19 @@ package gui.menu; +import game.Player; import imgui.ImGui; import network.client.Client; +import network.server.Server; public class MultiPlayerView extends BaseView { - - private final Client client; - public MultiPlayerView(StateMachine stateMachine, Client client) { + private final Client client; + private final Server server; + + public MultiPlayerView(StateMachine stateMachine, Client client, Server server) { super(stateMachine); this.client = client; + this.server = server; this.client.onDisconnect.connect(this::onDisconnect); } @@ -23,9 +27,25 @@ public class MultiPlayerView extends BaseView { this.stateMachine.popState(); } + public void renderGameStatus() { + if (this.server == null) { + ImGui.text("En attente de l'administrateur du serveur ..."); + } else { + if (ImGui.button("Démarrer")) { + // start the game + } + } + } + @Override public void render() { - ImGui.text("Tema le gameplay"); + ImGui.text("Joueurs :"); + { + for (Player player : this.client.getGame().getPlayers().values()) { + ImGui.bulletText(player.getPseudo()); + } + } + renderGameStatus(); } } diff --git a/app/src/main/java/gui/menu/StateMachine.java b/app/src/main/java/gui/menu/StateMachine.java index 81ea005..63000c4 100644 --- a/app/src/main/java/gui/menu/StateMachine.java +++ b/app/src/main/java/gui/menu/StateMachine.java @@ -45,6 +45,7 @@ public class StateMachine { | ImGuiWindowFlags.NoSavedSettings | ImGuiWindowFlags.NoBackground); menus.get(menus.size() - 1).render(); ImGui.end(); + // ImGui.showDemoWindow(); checkEscape(); } diff --git a/app/src/main/java/network/client/Client.java b/app/src/main/java/network/client/Client.java index 6cdaa4b..10f5ec8 100644 --- a/app/src/main/java/network/client/Client.java +++ b/app/src/main/java/network/client/Client.java @@ -2,6 +2,7 @@ package network.client; import java.io.IOException; import java.net.UnknownHostException; +import java.util.Random; import common.Signal; import game.Game; @@ -15,13 +16,16 @@ public class Client { public final Signal onConnect = new Signal(); public final Signal onDisconnect = new Signal(); public final Signal onClosed = new Signal(); + public final Signal onGameStarted = new Signal(); String disconnectReason = null; public Client(String address, short port) throws UnknownHostException, IOException { this.clientConnection = new ClientConnexion(address, port, this); this.game = new Game(); - login("Player2" + Math.random()); + // temp + Random r = new Random(); + login("Player" + r.nextInt()); } public void login(String pseudo) { From df07f11a9cc44ba4cf3d6a9833b36d3b4e4466aa Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 26 Jan 2025 18:53:45 +0100 Subject: [PATCH 7/7] basic multiplayer --- app/src/main/java/game/Game.java | 22 +++++++++++ app/src/main/java/gui/SudokuRenderer.java | 37 +++++++++--------- app/src/main/java/gui/menu/BaseView.java | 8 +++- .../java/gui/menu/MultiPlayerDokuView.java | 38 +++++++++++++++++++ .../main/java/gui/menu/MultiPlayerView.java | 7 +++- .../java/network/client/ClientConnexion.java | 8 ++++ .../java/network/protocol/PacketVisitor.java | 2 + .../main/java/network/protocol/Packets.java | 2 +- .../protocol/packets/StartGamePacket.java | 26 +++++++++++++ app/src/main/java/network/server/Server.java | 8 ++++ .../java/network/server/ServerConnexion.java | 11 ++++++ 11 files changed, 149 insertions(+), 20 deletions(-) create mode 100644 app/src/main/java/gui/menu/MultiPlayerDokuView.java create mode 100644 app/src/main/java/network/protocol/packets/StartGamePacket.java diff --git a/app/src/main/java/game/Game.java b/app/src/main/java/game/Game.java index e3aaa82..691ddb7 100644 --- a/app/src/main/java/game/Game.java +++ b/app/src/main/java/game/Game.java @@ -3,12 +3,21 @@ package game; import java.util.HashMap; import java.util.Map; +import sudoku.MultiDoku; + public class Game { + public static enum GameState { + GameNotStarted, GameGoing, GameEnd + } + private final Map players; + private GameState gameState; + private MultiDoku doku; public Game() { this.players = new HashMap<>(); + this.gameState = GameState.GameNotStarted; } public Player getPlayerById(int id) { @@ -27,4 +36,17 @@ public class Game { return players; } + public void startGame(MultiDoku doku) { + this.doku = doku; + this.gameState = GameState.GameGoing; + } + + public GameState getGameState() { + return gameState; + } + + public MultiDoku getDoku() { + return doku; + } + } diff --git a/app/src/main/java/gui/SudokuRenderer.java b/app/src/main/java/gui/SudokuRenderer.java index bb3f131..0087714 100644 --- a/app/src/main/java/gui/SudokuRenderer.java +++ b/app/src/main/java/gui/SudokuRenderer.java @@ -12,36 +12,41 @@ import imgui.flag.ImGuiCol; import imgui.flag.ImGuiStyleVar; import sudoku.Block; import sudoku.Cell; +import sudoku.MultiDoku; import sudoku.Sudoku; public class SudokuRenderer { - private final Sudoku sudoku; + private final MultiDoku doku; + private Sudoku currentSudoku; private int currentIndex = -1; private final Map colorPalette; - public SudokuRenderer(Sudoku sudoku) { - this.sudoku = sudoku; - this.colorPalette = new HashMap<>(); - initColors(); + public SudokuRenderer(MultiDoku doku) { + this.doku = doku; + this.currentSudoku = doku.getSubGrid(0); + this.colorPalette = initColors(); } - private void initColors() { - List colors = ColorGenerator.greatPalette(sudoku.getSize()); + private Map initColors() { + List colors = ColorGenerator.greatPalette(currentSudoku.getSize()); + Map colorPalette = new HashMap<>(); int index = 0; - for (Block block : sudoku.getBlocks()) { + for (Block block : currentSudoku.getBlocks()) { colorPalette.put(block, colors.get(index)); index++; } + return colorPalette; } private void renderPopup() { if (ImGui.beginPopup("editPopup")) { - for (int i = 1; i < sudoku.getSize() + 1; i++) { - if (i % (int) (Math.sqrt(sudoku.getSize())) != 1) + for (int i = 1; i < currentSudoku.getSize() + 1; i++) { + if (i % (int) (Math.sqrt(currentSudoku.getSize())) != 1) ImGui.sameLine(); if (ImGui.button(Integer.toString(i), new ImVec2(50, 50))) { - this.sudoku.setCellSymbol(currentIndex % sudoku.getSize(), currentIndex / sudoku.getSize(), i - 1); + this.currentSudoku.setCellSymbol(currentIndex % currentSudoku.getSize(), + currentIndex / currentSudoku.getSize(), i - 1); ImGui.closeCurrentPopup(); } } @@ -50,13 +55,12 @@ public class SudokuRenderer { } public void render() { - ImGui.begin("Sudoku Window"); - for (int y = 0; y < sudoku.getSize(); y++) { - for (int x = 0; x < sudoku.getSize(); x++) { + for (int y = 0; y < currentSudoku.getSize(); y++) { + for (int x = 0; x < currentSudoku.getSize(); x++) { if (x > 0) ImGui.sameLine(); - int index = y * sudoku.getSize() + x; - Cell cell = sudoku.getCell(x, y); + int index = y * currentSudoku.getSize() + x; + Cell cell = currentSudoku.getCell(x, y); int symbol = cell.getSymbolIndex(); Color blockColor = colorPalette.get(cell.getBlock()); ImGui.pushStyleVar(ImGuiStyleVar.SelectableTextAlign, new ImVec2(0.5f, 0.5f)); @@ -73,7 +77,6 @@ public class SudokuRenderer { } } renderPopup(); - ImGui.end(); } } diff --git a/app/src/main/java/gui/menu/BaseView.java b/app/src/main/java/gui/menu/BaseView.java index de5c16d..7da67ce 100644 --- a/app/src/main/java/gui/menu/BaseView.java +++ b/app/src/main/java/gui/menu/BaseView.java @@ -14,8 +14,14 @@ public abstract class BaseView { public void cleanResources() {} + public void closeMenu(int count) { + for (int i = 0; i < count; i++) { + this.stateMachine.popState(); + } + } + public void closeMenu() { - this.stateMachine.popState(); + closeMenu(1); } protected void renderReturnButton() { diff --git a/app/src/main/java/gui/menu/MultiPlayerDokuView.java b/app/src/main/java/gui/menu/MultiPlayerDokuView.java new file mode 100644 index 0000000..f6d999b --- /dev/null +++ b/app/src/main/java/gui/menu/MultiPlayerDokuView.java @@ -0,0 +1,38 @@ +package gui.menu; + +import gui.SudokuRenderer; +import imgui.ImGui; +import network.client.Client; +import network.server.Server; +import sudoku.MultiDoku; + +public class MultiPlayerDokuView extends BaseView{ + + private final Client client; + private final Server server; + private final SudokuRenderer sudokuRenderer; + + public MultiPlayerDokuView(StateMachine stateMachine, Client client, Server server) { + super(stateMachine); + this.client = client; + this.server = server; + this.sudokuRenderer = new SudokuRenderer(this.client.getGame().getDoku()); + this.client.onDisconnect.connect(this::onDisconnect); + } + + public void onDisconnect() { + if (server == null) { + closeMenu(); + } + } + + @Override + public void render() { + this.sudokuRenderer.render(); + if (ImGui.button("Quitter")) { + this.client.stop(); + this.closeMenu(3); + } + } + +} diff --git a/app/src/main/java/gui/menu/MultiPlayerView.java b/app/src/main/java/gui/menu/MultiPlayerView.java index 37846ca..82cd19f 100644 --- a/app/src/main/java/gui/menu/MultiPlayerView.java +++ b/app/src/main/java/gui/menu/MultiPlayerView.java @@ -4,6 +4,8 @@ import game.Player; import imgui.ImGui; import network.client.Client; import network.server.Server; +import sudoku.MultiDoku; +import sudoku.SudokuFactory; public class MultiPlayerView extends BaseView { @@ -15,6 +17,7 @@ public class MultiPlayerView extends BaseView { this.client = client; this.server = server; this.client.onDisconnect.connect(this::onDisconnect); + this.client.onGameStarted.connect(() -> this.stateMachine.pushState(new MultiPlayerDokuView(stateMachine, client, server))); } @Override @@ -32,7 +35,9 @@ public class MultiPlayerView extends BaseView { ImGui.text("En attente de l'administrateur du serveur ..."); } else { if (ImGui.button("Démarrer")) { - // start the game + // temp + MultiDoku doku = SudokuFactory.createBasicEmptySquareSudoku(5); + this.server.startGame(doku); } } } diff --git a/app/src/main/java/network/client/ClientConnexion.java b/app/src/main/java/network/client/ClientConnexion.java index ca8d6c5..6e6fe87 100644 --- a/app/src/main/java/network/client/ClientConnexion.java +++ b/app/src/main/java/network/client/ClientConnexion.java @@ -12,6 +12,8 @@ import network.protocol.packets.KeepAlivePacket; import network.protocol.packets.LoginPacket; import network.protocol.packets.PlayerJoinPacket; import network.protocol.packets.PlayerLeavePacket; +import network.protocol.packets.StartGamePacket; +import sudoku.io.SudokuSerializer; public class ClientConnexion extends Connexion { @@ -65,4 +67,10 @@ public class ClientConnexion extends Connexion { this.client.getGame().removePlayer(packet.getPlayer()); } + @Override + public void visitPacket(StartGamePacket packet) { + this.client.getGame().startGame(SudokuSerializer.deserializeSudoku(packet.getSerializedSudoku())); + this.client.onGameStarted.emit(); + } + } diff --git a/app/src/main/java/network/protocol/PacketVisitor.java b/app/src/main/java/network/protocol/PacketVisitor.java index f57e0bf..582a4f3 100644 --- a/app/src/main/java/network/protocol/PacketVisitor.java +++ b/app/src/main/java/network/protocol/PacketVisitor.java @@ -6,6 +6,7 @@ import network.protocol.packets.KeepAlivePacket; import network.protocol.packets.LoginPacket; import network.protocol.packets.PlayerJoinPacket; import network.protocol.packets.PlayerLeavePacket; +import network.protocol.packets.StartGamePacket; public interface PacketVisitor { @@ -19,5 +20,6 @@ public interface PacketVisitor { void visitPacket(LoginPacket packet); void visitPacket(PlayerJoinPacket packet); void visitPacket(PlayerLeavePacket packet); + void visitPacket(StartGamePacket packet); } diff --git a/app/src/main/java/network/protocol/Packets.java b/app/src/main/java/network/protocol/Packets.java index 27b5162..9355877 100644 --- a/app/src/main/java/network/protocol/Packets.java +++ b/app/src/main/java/network/protocol/Packets.java @@ -2,6 +2,6 @@ package network.protocol; public enum Packets { - ConnectionInfo, KeepAlive, Disconnect, Login, PlayerJoin, PlayerLeave + ConnectionInfo, KeepAlive, Disconnect, Login, PlayerJoin, PlayerLeave, StartGame } diff --git a/app/src/main/java/network/protocol/packets/StartGamePacket.java b/app/src/main/java/network/protocol/packets/StartGamePacket.java new file mode 100644 index 0000000..c8e0ae8 --- /dev/null +++ b/app/src/main/java/network/protocol/packets/StartGamePacket.java @@ -0,0 +1,26 @@ +package network.protocol.packets; + +import network.protocol.Packet; +import network.protocol.PacketVisitor; +import network.protocol.Packets; + +public class StartGamePacket extends Packet { + + static private final long serialVersionUID = Packets.StartGame.ordinal(); + + private final String serializedSudoku; + + public StartGamePacket(String serializedSudoku) { + this.serializedSudoku = serializedSudoku; + } + + public String getSerializedSudoku() { + return serializedSudoku; + } + + @Override + public void accept(PacketVisitor packetVisitor) { + packetVisitor.visitPacket(this); + } + +} diff --git a/app/src/main/java/network/server/Server.java b/app/src/main/java/network/server/Server.java index 18f0b4d..c82ad19 100644 --- a/app/src/main/java/network/server/Server.java +++ b/app/src/main/java/network/server/Server.java @@ -8,6 +8,9 @@ import java.util.List; import game.Game; import game.Player; import network.protocol.Packet; +import network.protocol.packets.StartGamePacket; +import sudoku.MultiDoku; +import sudoku.io.SudokuSerializer; public class Server { @@ -65,4 +68,9 @@ public class Server { return game; } + public void startGame(MultiDoku doku) { + this.game.startGame(doku); + broadcastPacket(new StartGamePacket(SudokuSerializer.serializeSudoku(doku))); + } + } diff --git a/app/src/main/java/network/server/ServerConnexion.java b/app/src/main/java/network/server/ServerConnexion.java index a393408..eaf79c2 100644 --- a/app/src/main/java/network/server/ServerConnexion.java +++ b/app/src/main/java/network/server/ServerConnexion.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.net.Socket; import game.Player; +import game.Game.GameState; import network.Connexion; import network.protocol.packets.ConnexionInfoPacket; import network.protocol.packets.DisconnectPacket; @@ -11,6 +12,8 @@ import network.protocol.packets.KeepAlivePacket; import network.protocol.packets.LoginPacket; import network.protocol.packets.PlayerJoinPacket; import network.protocol.packets.PlayerLeavePacket; +import network.protocol.packets.StartGamePacket; +import sudoku.io.SudokuSerializer; public class ServerConnexion extends Connexion { @@ -56,6 +59,9 @@ public class ServerConnexion extends Connexion { } this.server.broadcastPacket(new PlayerJoinPacket(player)); sendPacket(new ConnexionInfoPacket(player.getId())); + if (this.server.getGame().getGameState() == GameState.GameGoing) { + sendPacket(new StartGamePacket(SudokuSerializer.serializeSudoku(this.server.getGame().getDoku()))); + } } @Override @@ -91,4 +97,9 @@ public class ServerConnexion extends Connexion { throw new UnsupportedOperationException("Unimplemented method 'visitPacketPlayerLeave'"); } + @Override + public void visitPacket(StartGamePacket packet) { + throw new UnsupportedOperationException("Unimplemented method 'visitPacketStartGame'"); + } + }