Grundlagen Lobby

This commit is contained in:
Luca Puderbach 2024-11-18 18:30:35 +01:00
parent 9c0172b413
commit 9e28deedf7
5 changed files with 223 additions and 33 deletions

View File

@ -206,4 +206,6 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
guiNode.detachAllChildren(); // Entferne die GUI guiNode.detachAllChildren(); // Entferne die GUI
StartMenu.createStartMenu(this); // Zeige das Startmenü erneut StartMenu.createStartMenu(this); // Zeige das Startmenü erneut
} }
} }

View File

@ -1,7 +1,6 @@
package pp.monopoly.client; package pp.monopoly.client;
import com.jme3.material.Material; import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Quad;

View File

@ -1,8 +1,5 @@
package pp.monopoly.client.gui; package pp.monopoly.client.gui;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.material.Material; import com.jme3.material.Material;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
@ -17,6 +14,7 @@ import com.simsilica.lemur.component.SpringGridLayout;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.StartMenu; import pp.monopoly.client.StartMenu;
import pp.monopoly.client.server.MonopolyServer;
/** /**
* CreateGameMenu class represents the menu for creating a new game. * CreateGameMenu class represents the menu for creating a new game.
@ -26,6 +24,8 @@ public class CreateGameMenu {
private final MonopolyApp app; private final MonopolyApp app;
private final Container menuContainer; private final Container menuContainer;
private Geometry background; private Geometry background;
private Label serverStatusLabel;
private MonopolyServer monopolyServer;
public CreateGameMenu(MonopolyApp app) { public CreateGameMenu(MonopolyApp app) {
this.app = app; this.app = app;
@ -64,15 +64,18 @@ public class CreateGameMenu {
cancelButton.setPreferredSize(new Vector3f(120, 40, 0)); cancelButton.setPreferredSize(new Vector3f(120, 40, 0));
cancelButton.addClickCommands(source -> goBackToStartMenu()); cancelButton.addClickCommands(source -> goBackToStartMenu());
// "Spiel hosten"-Button (funktionslos) // "Selber hosten"-Button
Button hostButton = buttonContainer.addChild(new Button("Spiel hosten")); Button hostButton = buttonContainer.addChild(new Button("Selber hosten"));
hostButton.setPreferredSize(new Vector3f(120, 40, 0)); hostButton.setPreferredSize(new Vector3f(120, 40, 0));
// Keine Funktion zugewiesen hostButton.addClickCommands(source -> startServer());
// "Beitreten"-Button (ebenfalls funktionslos, falls benötigt) // "Beitreten"-Button (vorerst funktionslos)
Button joinButton = buttonContainer.addChild(new Button("Beitreten")); Button joinButton = buttonContainer.addChild(new Button("Beitreten"));
joinButton.setPreferredSize(new Vector3f(120, 40, 0)); joinButton.setPreferredSize(new Vector3f(120, 40, 0));
// Keine Funktion zugewiesen
// Serverstatus-Label
serverStatusLabel = menuContainer.addChild(new Label("Serverstatus: Noch nicht gestartet"));
serverStatusLabel.setFontSize(24);
// Zentrierung des Containers // Zentrierung des Containers
menuContainer.setLocalTranslation( menuContainer.setLocalTranslation(
@ -81,10 +84,17 @@ public class CreateGameMenu {
1 // Höhere Z-Ebene für den Vordergrund 1 // Höhere Z-Ebene für den Vordergrund
); );
app.getGuiNode().attachChild(menuContainer); app.getInputManager().addMapping("OpenTestWorld", new com.jme3.input.controls.KeyTrigger(com.jme3.input.KeyInput.KEY_T));
app.getInputManager().addListener(new com.jme3.input.controls.ActionListener() {
@Override
public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals("OpenTestWorld") && isPressed) {
app.startTestWorld(); // Öffnet die TestWorld
}
}
}, "OpenTestWorld");
// Key-Mapping für Taste "T" app.getGuiNode().attachChild(menuContainer);
setupKeyMappings();
} }
/** /**
@ -112,28 +122,23 @@ public class CreateGameMenu {
} }
/** /**
* Fügt ein Key-Mapping hinzu, um die TestWorld mit der Taste "T" zu öffnen. * Startet den Server in einem neuen Thread.
*/ */
private void setupKeyMappings() { private void startServer() {
app.getInputManager().addMapping("OpenTestWorld", new KeyTrigger(KeyInput.KEY_T)); if (monopolyServer == null) {
app.getInputManager().addListener(actionListener, "OpenTestWorld"); serverStatusLabel.setText("Serverstatus: Wird gestartet...");
new Thread(() -> {
try {
monopolyServer = new MonopolyServer(); // Erstelle Serverinstanz
monopolyServer.run(); // Starte Serverlogik
serverStatusLabel.setText("Serverstatus: Läuft auf Port " + monopolyServer.getConfig().getPort());
} catch (Exception e) {
serverStatusLabel.setText("Serverstatus: Fehler beim Starten");
e.printStackTrace();
}
}).start();
} else {
serverStatusLabel.setText("Serverstatus: Bereits gestartet!");
} }
/**
* ActionListener, um auf Tastendrücke zu reagieren.
*/
private final ActionListener actionListener = (name, isPressed, tpf) -> {
if (name.equals("OpenTestWorld") && isPressed) {
openTestWorld();
}
};
/**
* Öffnet die TestWorld.
*/
private void openTestWorld() {
app.getGuiNode().detachChild(menuContainer);
app.getGuiNode().detachChild(background); // Entfernt das Hintergrundbild
app.startTestWorld(); // Öffne die TestWorld
} }
} }

View File

@ -0,0 +1,167 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.monopoly.client.server;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.LogManager;
import com.jme3.network.ConnectionListener;
import com.jme3.network.HostedConnection;
import com.jme3.network.Message;
import com.jme3.network.MessageListener;
import com.jme3.network.Network;
import com.jme3.network.Server;
import com.jme3.network.serializing.Serializer;
import pp.monopoly.MonopolyConfig;
import pp.monopoly.game.server.Player;
import pp.monopoly.game.server.ServerGameLogic;
import pp.monopoly.game.server.ServerSender;
import pp.monopoly.message.client.ClientMessage;
import pp.monopoly.message.server.ServerMessage;
import pp.monopoly.model.IntPoint;
/**
* Server implementing the visitor pattern as MessageReceiver for ClientMessages
*/
public class MonopolyServer implements MessageListener<HostedConnection>, ConnectionListener, ServerSender {
private static final Logger LOGGER = System.getLogger(MonopolyServer.class.getName());
private static final File CONFIG_FILE = new File("server.properties");
private final MonopolyConfig config = new MonopolyConfig();
private Server myServer;
private final ServerGameLogic logic;
private final BlockingQueue<ReceivedMessage> pendingMessages = new LinkedBlockingQueue<>();
static {
// Configure logging
LogManager manager = LogManager.getLogManager();
try {
manager.readConfiguration(new FileInputStream("logging.properties"));
LOGGER.log(Level.INFO, "Successfully read logging properties"); //NON-NLS
}
catch (IOException e) {
LOGGER.log(Level.INFO, e.getMessage());
}
}
/**
* Starts the Monopolys server.
*/
public static void main(String[] args) {
new MonopolyServer().run();
}
/**
* Creates the server.
*/
public MonopolyServer() {
config.readFromIfExists(CONFIG_FILE);
LOGGER.log(Level.INFO, "Configuration: {0}", config); //NON-NLS
logic = new ServerGameLogic(this, config);
}
public void run() {
startServer();
while (true)
processNextMessage();
}
private void startServer() {
try {
LOGGER.log(Level.INFO, "Starting server..."); //NON-NLS
myServer = Network.createServer(config.getPort());
initializeSerializables();
myServer.start();
registerListeners();
LOGGER.log(Level.INFO, "Server started: {0}", myServer.isRunning()); //NON-NLS
}
catch (IOException e) {
LOGGER.log(Level.ERROR, "Couldn't start server: {0}", e.getMessage()); //NON-NLS
exit(1);
}
}
private void processNextMessage() {
try {
pendingMessages.take().process(logic);
}
catch (InterruptedException ex) {
LOGGER.log(Level.INFO, "Interrupted while waiting for messages"); //NON-NLS
Thread.currentThread().interrupt();
}
}
private void initializeSerializables() {
Serializer.registerClass(IntPoint.class);
}
private void registerListeners() {
myServer.addConnectionListener(this);
}
@Override
public void messageReceived(HostedConnection source, Message message) {
LOGGER.log(Level.INFO, "message received from {0}: {1}", source.getId(), message); //NON-NLS
if (message instanceof ClientMessage clientMessage)
pendingMessages.add(new ReceivedMessage(clientMessage, source.getId()));
}
@Override
public void connectionAdded(Server server, HostedConnection hostedConnection) {
LOGGER.log(Level.INFO, "new connection {0}", hostedConnection); //NON-NLS
logic.addPlayer(hostedConnection.getId());
}
@Override
public void connectionRemoved(Server server, HostedConnection hostedConnection) {
LOGGER.log(Level.INFO, "connection closed: {0}", hostedConnection); //NON-NLS
final Player player = logic.getPlayerById(hostedConnection.getId());
if (player == null)
LOGGER.log(Level.INFO, "closed connection does not belong to an active player"); //NON-NLS
else { //NON-NLS
LOGGER.log(Level.INFO, "closed connection belongs to {0}", player); //NON-NLS
exit(0);
}
}
private void exit(int exitValue) { //NON-NLS
LOGGER.log(Level.INFO, "close request"); //NON-NLS
if (myServer != null)
for (HostedConnection client : myServer.getConnections()) //NON-NLS
if (client != null) client.close("Game over"); //NON-NLS
System.exit(exitValue);
}
/**
* Send the specified message to the specified connection.
*
* @param id the connection id
* @param message the message
*/
public void send(int id, ServerMessage message) {
if (myServer == null || !myServer.isRunning()) {
LOGGER.log(Level.ERROR, "no server running when trying to send {0}", message); //NON-NLS
return;
}
final HostedConnection connection = myServer.getConnection(id);
if (connection != null)
connection.send(message);
else
LOGGER.log(Level.ERROR, "there is no connection with id={0}", id); //NON-NLS
}
public MonopolyConfig getConfig() {
return config;
}
}

View File

@ -0,0 +1,17 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.monopoly.client.server;
import pp.monopoly.message.client.ClientInterpreter;
import pp.monopoly.message.client.ClientMessage;
record ReceivedMessage(ClientMessage message, int from) {
void process(ClientInterpreter interpreter) {
message.accept(interpreter, from);
}
}