mirror of
https://github.com/2OOP/pism.git
synced 2026-02-04 10:54:51 +00:00
Server in working state, can be merged with working branch.
This commit is contained in:
committed by
Bas Antonius de Jong
parent
a9e63b3fcc
commit
c76b7a800e
1
.gitignore
vendored
1
.gitignore
vendored
@@ -100,4 +100,5 @@ build
|
||||
##############################
|
||||
newgamesver-release-V1.jar
|
||||
server.properties
|
||||
gameserver.log.*
|
||||
gameserver.log
|
||||
1
.idea/dictionaries/project.xml
generated
1
.idea/dictionaries/project.xml
generated
@@ -5,6 +5,7 @@
|
||||
<w>clid</w>
|
||||
<w>dcompile</w>
|
||||
<w>errorprone</w>
|
||||
<w>flushnl</w>
|
||||
<w>gamelist</w>
|
||||
<w>playerlist</w>
|
||||
<w>tictactoe</w>
|
||||
|
||||
@@ -33,7 +33,7 @@ public class LocalTicTacToe { // TODO: Implement runnable
|
||||
|
||||
private boolean isLocal;
|
||||
private String gameId;
|
||||
private long connectionId = -1;
|
||||
private long clientId = -1;
|
||||
private String serverId = null;
|
||||
|
||||
private boolean[] isAiPlayer = new boolean[2];
|
||||
@@ -210,13 +210,13 @@ public class LocalTicTacToe { // TODO: Implement runnable
|
||||
}
|
||||
|
||||
private void receiveMessageAction(NetworkEvents.ReceivedMessage receivedMessage) {
|
||||
if (receivedMessage.ConnectionId() != this.connectionId) {
|
||||
if (receivedMessage.clientId() != this.clientId) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
logger.info(
|
||||
"Received message from {}: {}", this.connectionId, receivedMessage.message());
|
||||
"Received message from {}: {}", this.clientId, receivedMessage.message());
|
||||
this.receivedQueue.put(receivedMessage.message());
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("Error waiting for received Message", e);
|
||||
@@ -224,7 +224,7 @@ public class LocalTicTacToe { // TODO: Implement runnable
|
||||
}
|
||||
|
||||
private void sendCommand(String... args) {
|
||||
new EventFlow().addPostEvent(NetworkEvents.SendCommand.class, this.connectionId, args).asyncPostEvent();
|
||||
new EventFlow().addPostEvent(NetworkEvents.SendCommand.class, this.clientId, args).asyncPostEvent();
|
||||
}
|
||||
|
||||
// private void endListeners() {
|
||||
|
||||
@@ -11,6 +11,8 @@ import io.netty.handler.codec.string.StringEncoder;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.toop.framework.eventbus.EventFlow;
|
||||
import org.toop.framework.networking.events.NetworkEvents;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -18,6 +20,8 @@ public class NetworkingClient {
|
||||
private static final Logger logger = LogManager.getLogger(NetworkingClient.class);
|
||||
|
||||
private long connectionId;
|
||||
private String host;
|
||||
private int port;
|
||||
private Channel channel;
|
||||
private NetworkingGameClientHandler handler;
|
||||
|
||||
@@ -47,13 +51,23 @@ public class NetworkingClient {
|
||||
});
|
||||
ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
|
||||
this.channel = channelFuture.channel();
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to create networking client instance", e);
|
||||
}
|
||||
}
|
||||
|
||||
public NetworkingGameClientHandler getHandler() {
|
||||
return handler;
|
||||
return this.handler;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return this.host;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
public void setConnectionId(long connectionId) {
|
||||
@@ -83,55 +97,14 @@ public class NetworkingClient {
|
||||
}
|
||||
}
|
||||
|
||||
public void login(String username) {
|
||||
this.writeAndFlush("login " + username + "\n");
|
||||
}
|
||||
|
||||
public void logout() {
|
||||
this.writeAndFlush("logout\n");
|
||||
}
|
||||
|
||||
public void sendMove(int move) {
|
||||
this.writeAndFlush("move " + move + "\n"); // append \n so server receives a full line
|
||||
}
|
||||
|
||||
public void getGamelist() {
|
||||
this.writeAndFlush("get gamelist\n");
|
||||
}
|
||||
|
||||
public void getPlayerlist() {
|
||||
this.writeAndFlush("get playerlist\n");
|
||||
}
|
||||
|
||||
public void subscribe(String gameType) {
|
||||
this.writeAndFlush("subscribe " + gameType + "\n");
|
||||
}
|
||||
|
||||
public void forfeit() {
|
||||
this.writeAndFlush("forfeit\n");
|
||||
}
|
||||
|
||||
public void challenge(String playerName, String gameType) {
|
||||
this.writeAndFlush("challenge " + playerName + " " + gameType + "\n");
|
||||
}
|
||||
|
||||
public void acceptChallenge(String challengeNumber) {
|
||||
this.writeAndFlush("challenge accept " + challengeNumber + "\n");
|
||||
}
|
||||
|
||||
public void sendChatMessage(String message) {
|
||||
this.writeAndFlush("message " + "\"" + message + "\"" + "\n");
|
||||
}
|
||||
|
||||
public void help(String command) {
|
||||
this.writeAndFlush("help " + command + "\n");
|
||||
}
|
||||
|
||||
public void closeConnection() {
|
||||
if (this.channel != null && this.channel.isActive()) {
|
||||
this.channel.close().addListener(future -> {
|
||||
if (future.isSuccess()) {
|
||||
logger.info("Connection {} closed successfully", this.channel.remoteAddress());
|
||||
new EventFlow()
|
||||
.addPostEvent(new NetworkEvents.ClosedConnection(this.connectionId))
|
||||
.asyncPostEvent();
|
||||
} else {
|
||||
logger.error("Error closing connection {}. Error: {}",
|
||||
this.channel.remoteAddress(),
|
||||
|
||||
@@ -2,7 +2,6 @@ package org.toop.framework.networking;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -23,9 +22,22 @@ public class NetworkingClientManager {
|
||||
new EventFlow()
|
||||
.listen(this::handleStartClient)
|
||||
.listen(this::handleCommand)
|
||||
.listen(this::handleSendLogin)
|
||||
.listen(this::handleSendLogout)
|
||||
.listen(this::handleSendGetPlayerlist)
|
||||
.listen(this::handleSendGetGamelist)
|
||||
.listen(this::handleSendSubscribe)
|
||||
.listen(this::handleSendMove)
|
||||
.listen(this::handleSendChallenge)
|
||||
.listen(this::handleSendAcceptChallenge)
|
||||
.listen(this::handleSendForfeit)
|
||||
.listen(this::handleSendMessage)
|
||||
.listen(this::handleSendHelp)
|
||||
.listen(this::handleSendHelpForCommand)
|
||||
.listen(this::handleCloseClient)
|
||||
.listen(this::getAllConnections)
|
||||
.listen(this::shutdownAll);
|
||||
.listen(this::handleChangeClientHost)
|
||||
.listen(this::handleGetAllConnections)
|
||||
.listen(this::handleShutdownAll);
|
||||
logger.info("NetworkingClientManager initialized");
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to initialize the client manager", e);
|
||||
@@ -43,13 +55,30 @@ public class NetworkingClientManager {
|
||||
connectionId);
|
||||
client.setConnectionId(connectionId);
|
||||
this.networkClients.put(connectionId, client);
|
||||
logger.info("New client started successfully for {}:{}", ip, port);
|
||||
} catch (Exception e) {
|
||||
logger.error(e);
|
||||
}
|
||||
logger.info("Client {} started", connectionId);
|
||||
return connectionId;
|
||||
}
|
||||
|
||||
private long startClientRequest(String ip, int port, long clientId) {
|
||||
try { // With EventFlow
|
||||
NetworkingClient client = new NetworkingClient(
|
||||
() -> new NetworkingGameClientHandler(clientId),
|
||||
ip,
|
||||
port,
|
||||
clientId);
|
||||
client.setConnectionId(clientId);
|
||||
this.networkClients.replace(clientId, client);
|
||||
logger.info("New client started successfully for {}:{}, replaced: {}", ip, port, clientId);
|
||||
} catch (Exception e) {
|
||||
logger.error(e);
|
||||
}
|
||||
logger.info("Client {} started", clientId);
|
||||
return clientId;
|
||||
}
|
||||
|
||||
private void handleStartClient(NetworkEvents.StartClient event) {
|
||||
long id = this.startClientRequest(event.ip(), event.port());
|
||||
new Thread(() -> {
|
||||
@@ -67,54 +96,96 @@ public class NetworkingClientManager {
|
||||
private void handleCommand(
|
||||
NetworkEvents.SendCommand
|
||||
event) { // TODO: Move this to ServerConnection class, keep it internal.
|
||||
NetworkingClient client = this.networkClients.get(event.connectionId());
|
||||
logger.info("Preparing to send command: {} to server: {}", event.args(), client.getId());
|
||||
NetworkingClient client = this.networkClients.get(event.clientId());
|
||||
String args = String.join(" ", event.args());
|
||||
client.writeAndFlushnl(args);
|
||||
sendCommand(client, args);
|
||||
}
|
||||
|
||||
private void handleSendLogin(NetworkEvents.SendLogin event) {
|
||||
NetworkingClient client = this.networkClients.get(event.clientId());
|
||||
sendCommand(client, String.format("LOGIN %s", event.username()));
|
||||
}
|
||||
|
||||
private void handleSendLogout(NetworkEvents.SendLogout event) {
|
||||
NetworkingClient client = this.networkClients.get(event.clientId());
|
||||
sendCommand(client, "LOGOUT");
|
||||
}
|
||||
|
||||
private void handleSendGetPlayerlist(NetworkEvents.SendGetPlayerlist event) {
|
||||
NetworkingClient client = this.networkClients.get(event.clientId());
|
||||
sendCommand(client, "GET PLAYERLIST");
|
||||
}
|
||||
|
||||
private void handleSendGetGamelist(NetworkEvents.SendGetGamelist event) {
|
||||
NetworkingClient client = this.networkClients.get(event.clientId());
|
||||
sendCommand(client, "GET GAMELIST");
|
||||
}
|
||||
|
||||
private void handleSendSubscribe(NetworkEvents.SendSubscribe event) {
|
||||
NetworkingClient client = this.networkClients.get(event.clientId());
|
||||
sendCommand(client, String.format("SUBSCRIBE %s", event.gameType()));
|
||||
}
|
||||
|
||||
private void handleSendMove(NetworkEvents.SendMove event) {
|
||||
NetworkingClient client = this.networkClients.get(event.clientId());
|
||||
sendCommand(client, String.format("MOVE %d", event.moveNumber()));
|
||||
}
|
||||
|
||||
private void handleSendChallenge(NetworkEvents.SendChallenge event) {
|
||||
NetworkingClient client = this.networkClients.get(event.clientId());
|
||||
sendCommand(client, String.format("CHALLENGE %s %s", event.usernameToChallenge(), event.gameType()));
|
||||
}
|
||||
|
||||
private void handleSendAcceptChallenge(NetworkEvents.SendAcceptChallenge event) {
|
||||
NetworkingClient client = this.networkClients.get(event.clientId());
|
||||
sendCommand(client, String.format("CHALLENGE ACCEPT %d", event.challengeId()));
|
||||
}
|
||||
|
||||
private void handleSendForfeit(NetworkEvents.SendForfeit event) {
|
||||
NetworkingClient client = this.networkClients.get(event.clientId());
|
||||
sendCommand(client, "FORFEIT");
|
||||
}
|
||||
|
||||
private void handleSendMessage(NetworkEvents.SendMessage event) {
|
||||
NetworkingClient client = this.networkClients.get(event.clientId());
|
||||
sendCommand(client, String.format("MESSAGE %s", event.message()));
|
||||
}
|
||||
|
||||
private void handleSendHelp(NetworkEvents.SendHelp event) {
|
||||
NetworkingClient client = this.networkClients.get(event.clientId());
|
||||
sendCommand(client, "HELP");
|
||||
}
|
||||
|
||||
private void handleSendHelpForCommand(NetworkEvents.SendHelpForCommand event) {
|
||||
NetworkingClient client = this.networkClients.get(event.clientId());
|
||||
sendCommand(client, String.format("HELP %s", event.command()));
|
||||
}
|
||||
|
||||
private void sendCommand(NetworkingClient client, String command) {
|
||||
logger.info("Preparing to send command: {} to server: {}:{}. clientId: {}",
|
||||
command.trim(), client.getHost(), client.getPort(), client.getId());
|
||||
client.writeAndFlushnl(command);
|
||||
}
|
||||
|
||||
private void handleChangeClientHost(NetworkEvents.ChangeClientHost event) {
|
||||
NetworkingClient client = this.networkClients.get(event.clientId());
|
||||
client.closeConnection();
|
||||
startClientRequest(event.ip(), event.port(), event.clientId());
|
||||
}
|
||||
|
||||
private void handleCloseClient(NetworkEvents.CloseClient event) {
|
||||
NetworkingClient client = this.networkClients.get(event.connectionId());
|
||||
NetworkingClient client = this.networkClients.get(event.clientId());
|
||||
client.closeConnection(); // TODO: Check if not blocking, what if error, mb not remove?
|
||||
this.networkClients.remove(event.connectionId());
|
||||
logger.info("Client {} closed successfully.", event.connectionId());
|
||||
this.networkClients.remove(event.clientId());
|
||||
logger.info("Client {} closed successfully.", event.clientId());
|
||||
}
|
||||
|
||||
// private void handleReconnect(Events.ServerEvents.Reconnect event) {
|
||||
// NetworkingClient client = this.networkClients.get(event.connectionId());
|
||||
// if (client != null) {
|
||||
// try {
|
||||
// client;
|
||||
// logger.info("Server {} reconnected", event.connectionId());
|
||||
// } catch (Exception e) {
|
||||
// logger.error("Server {} failed to reconnect", event.connectionId(), e);
|
||||
// GlobalEventBus.post(new Events.ServerEvents.CouldNotConnect(event.connectionId()));
|
||||
// }
|
||||
// }
|
||||
// } // TODO: Reconnect on disconnect
|
||||
|
||||
// private void handleChangeConnection(Events.ServerEvents.ChangeConnection event) {
|
||||
// ServerConnection serverConnection = this.serverConnections.get(event.connectionId());
|
||||
// if (serverConnection != null) {
|
||||
// try {
|
||||
// serverConnection.connect(event.ip(), event.port());
|
||||
// logger.info("Server {} changed connection to {}:{}", event.connectionId(),
|
||||
// event.ip(), event.port());
|
||||
// } catch (Exception e) {
|
||||
// logger.error("Server {} failed to change connection", event.connectionId(),
|
||||
// e);
|
||||
// GlobalEventBus.post(new
|
||||
// Events.ServerEvents.CouldNotConnect(event.connectionId()));
|
||||
// }
|
||||
// }
|
||||
// } TODO
|
||||
|
||||
private void getAllConnections(NetworkEvents.RequestsAllClients request) {
|
||||
private void handleGetAllConnections(NetworkEvents.RequestsAllClients request) {
|
||||
List<NetworkingClient> a = new ArrayList<>(this.networkClients.values());
|
||||
request.future().complete(a);
|
||||
}
|
||||
|
||||
public void shutdownAll(NetworkEvents.ForceCloseAllClients request) {
|
||||
public void handleShutdownAll(NetworkEvents.ForceCloseAllClients request) {
|
||||
this.networkClients.values().forEach(NetworkingClient::closeConnection);
|
||||
this.networkClients.clear();
|
||||
logger.info("All servers shut down");
|
||||
|
||||
@@ -2,13 +2,11 @@ package org.toop.framework.networking;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import jdk.jfr.Event;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.toop.framework.eventbus.EventFlow;
|
||||
import org.toop.framework.networking.events.NetworkEvents;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -44,25 +42,149 @@ public class NetworkingGameClientHandler extends ChannelInboundHandlerAdapter {
|
||||
}
|
||||
|
||||
private void parseServerReturn(String rec) {
|
||||
if (rec.toLowerCase().contains("playerlist")) {
|
||||
playerListHandler(rec);
|
||||
} else if (rec.toLowerCase().contains("close")) {
|
||||
|
||||
} else {}
|
||||
String recSrvRemoved = rec.substring("SVR ".length());
|
||||
Pattern gamePattern = Pattern.compile("GAME (\\w+)", Pattern.CASE_INSENSITIVE);
|
||||
Matcher gameMatch = gamePattern.matcher(recSrvRemoved);
|
||||
|
||||
if (gameMatch.find()) {
|
||||
switch(gameMatch.group(1)) {
|
||||
case "YOURTURN": gameYourTurnHandler(recSrvRemoved); return;
|
||||
case "MOVE": gameMoveHandler(recSrvRemoved); return;
|
||||
case "MATCH": gameMatchHandler(recSrvRemoved); return;
|
||||
case "CHALLENGE": gameChallengeHandler(recSrvRemoved); return;
|
||||
case "WIN",
|
||||
"DRAW",
|
||||
"LOSE": gameWinConditionHandler(recSrvRemoved); return;
|
||||
default: return;
|
||||
}
|
||||
} else {
|
||||
|
||||
Pattern getPattern = Pattern.compile("(\\w+)", Pattern.CASE_INSENSITIVE);
|
||||
Matcher getMatch = getPattern.matcher(recSrvRemoved);
|
||||
|
||||
if (getMatch.find()) {
|
||||
switch(getMatch.group(1)) {
|
||||
case "PLAYERLIST": playerlistHandler(recSrvRemoved); return;
|
||||
case "GAMELIST": gamelistHandler(recSrvRemoved); return;
|
||||
case "HELP": helpHandler(recSrvRemoved); return;
|
||||
default: return;
|
||||
}
|
||||
} else {
|
||||
return; // TODO: Should be an error.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void playerListHandler(String rec) {
|
||||
Pattern pattern = Pattern.compile("\"([^\"]+)\"");
|
||||
String[] players = pattern.matcher(rec)
|
||||
private void gameMoveHandler(String rec) {
|
||||
String[] msg = Pattern
|
||||
.compile("(?:player|details|move):\\s*\"?([^\",}]+)\"?", Pattern.CASE_INSENSITIVE)
|
||||
.matcher(rec)
|
||||
.results()
|
||||
.map(m -> m.group(1))
|
||||
.map(m -> m.group(1).trim())
|
||||
.toArray(String[]::new);
|
||||
|
||||
new EventFlow()
|
||||
.addPostEvent(new NetworkEvents.PlayerListResponse(this.connectionId, players))
|
||||
.addPostEvent(new NetworkEvents.GameMoveResponse(this.connectionId, msg[0], msg[1], msg[2]))
|
||||
.asyncPostEvent();
|
||||
}
|
||||
|
||||
private void gameWinConditionHandler(String rec) {
|
||||
String condition = Pattern
|
||||
.compile("\\b(win|draw|lose)\\b", Pattern.CASE_INSENSITIVE)
|
||||
.matcher(rec)
|
||||
.results()
|
||||
.toString()
|
||||
.trim();
|
||||
|
||||
new EventFlow()
|
||||
.addPostEvent(new NetworkEvents.GameResultResponse(this.connectionId, condition))
|
||||
.asyncPostEvent();
|
||||
}
|
||||
|
||||
private void gameChallengeHandler(String rec) {
|
||||
boolean isCancelled = rec.toLowerCase().startsWith("challenge accepted");
|
||||
try {
|
||||
String[] msg = Pattern
|
||||
.compile("(?:CHALLENGER|GAMETYPE|CHALLENGENUMBER):\\s*\"?(.*?)\"?\\s*(?:,|})")
|
||||
.matcher(rec)
|
||||
.results()
|
||||
.map(m -> m.group().trim())
|
||||
.toArray(String[]::new);
|
||||
|
||||
if (isCancelled) new EventFlow()
|
||||
.addPostEvent(new NetworkEvents.ChallengeCancelledResponse(this.connectionId, msg[0]))
|
||||
.asyncPostEvent();
|
||||
else new EventFlow()
|
||||
.addPostEvent(new NetworkEvents.ChallengeResponse(this.connectionId, msg[0], msg[1], msg[2]))
|
||||
.asyncPostEvent();
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
logger.error("Array out of bounds for: {}", rec, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void gameMatchHandler(String rec) {
|
||||
try {
|
||||
String[] msg = Pattern
|
||||
.compile("\"([^\"]*)\"")
|
||||
.matcher(rec)
|
||||
.results()
|
||||
.map(m -> m.group(1).trim())
|
||||
.toArray(String[]::new);
|
||||
|
||||
// [0] playerToMove, [1] gameType, [2] opponent
|
||||
new EventFlow()
|
||||
.addPostEvent(new NetworkEvents.GameMatchResponse(this.connectionId, msg[0], msg[1], msg[2]))
|
||||
.asyncPostEvent();
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
logger.error("Array out of bounds for: {}", rec, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void gameYourTurnHandler(String rec) {
|
||||
String msg = Pattern
|
||||
.compile("TURNMESSAGE:\\s*\"([^\"]*)\"")
|
||||
.matcher(rec)
|
||||
.results()
|
||||
.toString()
|
||||
.trim();
|
||||
|
||||
new EventFlow()
|
||||
.addPostEvent(new NetworkEvents.YourTurnResponse(this.connectionId, msg))
|
||||
.asyncPostEvent();
|
||||
}
|
||||
|
||||
private void playerlistHandler(String rec) {
|
||||
String[] players = Pattern
|
||||
.compile("\"([^\"]+)\"")
|
||||
.matcher(rec)
|
||||
.results()
|
||||
.map(m -> m.group(1).trim())
|
||||
.toArray(String[]::new);
|
||||
|
||||
new EventFlow()
|
||||
.addPostEvent(new NetworkEvents.PlayerlistResponse(this.connectionId, players))
|
||||
.asyncPostEvent();
|
||||
}
|
||||
|
||||
private void gamelistHandler(String rec) {
|
||||
String[] gameTypes = Pattern
|
||||
.compile("\"([^\"]+)\"")
|
||||
.matcher(rec)
|
||||
.results()
|
||||
.map(m -> m.group(1).trim())
|
||||
.toArray(String[]::new);
|
||||
|
||||
new EventFlow()
|
||||
.addPostEvent(new NetworkEvents.GamelistResponse(this.connectionId, gameTypes))
|
||||
.asyncPostEvent();
|
||||
}
|
||||
|
||||
private void helpHandler(String rec) {
|
||||
logger.info(rec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
logger.error(cause.getMessage(), cause);
|
||||
|
||||
@@ -13,93 +13,107 @@ import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* A collection of networking-related event records for use with the {@link org.toop.framework.eventbus.GlobalEventBus}.
|
||||
* <p>
|
||||
* This class defines all the events that can be posted or listened to in the networking subsystem.
|
||||
* Events are separated into those with unique IDs (EventWithSnowflake) and those without (EventWithoutSnowflake).
|
||||
* </p>
|
||||
*/
|
||||
public class NetworkEvents extends EventsBase {
|
||||
|
||||
/**
|
||||
* BLOCKING Requests all active connections. The result is returned via the provided
|
||||
* CompletableFuture.
|
||||
* Requests all active client connections.
|
||||
* <p>
|
||||
* This is a blocking event. The result will be delivered via the provided {@link CompletableFuture}.
|
||||
* </p>
|
||||
*
|
||||
* @param future List of all connections in string form.
|
||||
* @param future CompletableFuture to receive the list of active {@link NetworkingClient} instances.
|
||||
*/
|
||||
public record RequestsAllClients(CompletableFuture<List<NetworkingClient>> future) implements EventWithoutSnowflake {}
|
||||
|
||||
/** Forces closing all active connections immediately. */
|
||||
/** Forces all active client connections to close immediately. */
|
||||
public record ForceCloseAllClients() implements EventWithoutSnowflake {}
|
||||
|
||||
public record PlayerListResponse(long clientId, String[] playerlist) implements EventWithoutSnowflake {}
|
||||
/** Response indicating a challenge was cancelled. */
|
||||
public record ChallengeCancelledResponse(long clientId, String challengeId) implements EventWithoutSnowflake {}
|
||||
|
||||
public record CloseClient(long connectionId) implements EventWithoutSnowflake {}
|
||||
/** Response indicating a challenge was received. */
|
||||
public record ChallengeResponse(long clientId, String challengerName, String gameType, String challengeId)
|
||||
implements EventWithoutSnowflake {}
|
||||
|
||||
/** Response containing a list of players for a client. */
|
||||
public record PlayerlistResponse(long clientId, String[] playerlist) implements EventWithoutSnowflake {}
|
||||
|
||||
/** Response containing a list of games for a client. */
|
||||
public record GamelistResponse(long clientId, String[] gamelist) implements EventWithoutSnowflake {}
|
||||
|
||||
/** Response indicating a game match information for a client. */
|
||||
public record GameMatchResponse(long clientId, String playerToMove, String gameType, String opponent)
|
||||
implements EventWithoutSnowflake {}
|
||||
|
||||
/** Response indicating the result of a game. */
|
||||
public record GameResultResponse(long clientId, String condition) implements EventWithoutSnowflake {}
|
||||
|
||||
/** Response indicating a game move occurred. */
|
||||
public record GameMoveResponse(long clientId, String player, String details, String move)
|
||||
implements EventWithoutSnowflake {}
|
||||
|
||||
/** Response indicating it is the player's turn. */
|
||||
public record YourTurnResponse(long clientId, String message) implements EventWithoutSnowflake {}
|
||||
|
||||
/** Request to send login credentials for a client. */
|
||||
public record SendLogin(long clientId, String username) implements EventWithoutSnowflake {}
|
||||
|
||||
/** Request to log out a client. */
|
||||
public record SendLogout(long clientId) implements EventWithoutSnowflake {}
|
||||
|
||||
/** Request to retrieve the player list for a client. */
|
||||
public record SendGetPlayerlist(long clientId) implements EventWithoutSnowflake {}
|
||||
|
||||
/** Request to retrieve the game list for a client. */
|
||||
public record SendGetGamelist(long clientId) implements EventWithoutSnowflake {}
|
||||
|
||||
/** Request to subscribe a client to a game type. */
|
||||
public record SendSubscribe(long clientId, String gameType) implements EventWithoutSnowflake {}
|
||||
|
||||
/** Request to make a move in a game. */
|
||||
public record SendMove(long clientId, short moveNumber) implements EventWithoutSnowflake {}
|
||||
|
||||
/** Request to challenge another player. */
|
||||
public record SendChallenge(long clientId, String usernameToChallenge, String gameType)
|
||||
implements EventWithoutSnowflake {}
|
||||
|
||||
/** Request to accept a challenge. */
|
||||
public record SendAcceptChallenge(long clientId, int challengeId) implements EventWithoutSnowflake {}
|
||||
|
||||
/** Request to forfeit a game. */
|
||||
public record SendForfeit(long clientId) implements EventWithoutSnowflake {}
|
||||
|
||||
/** Request to send a message from a client. */
|
||||
public record SendMessage(long clientId, String message) implements EventWithoutSnowflake {}
|
||||
|
||||
/** Request to display help to a client. */
|
||||
public record SendHelp(long clientId) implements EventWithoutSnowflake {}
|
||||
|
||||
/** Request to display help for a specific command. */
|
||||
public record SendHelpForCommand(long clientId, String command) implements EventWithoutSnowflake {}
|
||||
|
||||
/** Request to close a specific client connection. */
|
||||
public record CloseClient(long clientId) implements EventWithoutSnowflake {}
|
||||
|
||||
/**
|
||||
* Event to start a new client connection to a server.
|
||||
* Event to start a new client connection.
|
||||
* <p>
|
||||
* This event is typically posted to the {@code GlobalEventBus} to initiate the creation of
|
||||
* a client connection, and carries all information needed to establish that connection:
|
||||
* <br>
|
||||
* - A factory for creating the Netty handler that will manage the connection
|
||||
* <br>
|
||||
* - The server's IP address and port
|
||||
* <br>
|
||||
* - A unique event identifier for correlation with follow-up events
|
||||
* Carries IP, port, and a unique event ID for correlation with responses.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The {@link #eventSnowflake()} allows callers to correlate the {@code StartClient} event
|
||||
* with subsequent success/failure events. For example, a {@code StartClientSuccess}
|
||||
* or {@code StartClientFailure} event may carry the same {@code eventId}.
|
||||
* </p>
|
||||
*
|
||||
* @param ip The IP address of the server to connect to.
|
||||
* @param port The port number of the server to connect to.
|
||||
* @param eventSnowflake A unique identifier for this event, typically injected
|
||||
* automatically by the {@link org.toop.framework.eventbus.EventFlow}.
|
||||
* @param ip Server IP address.
|
||||
* @param port Server port.
|
||||
* @param eventSnowflake Unique event identifier for correlation.
|
||||
*/
|
||||
public record StartClient(
|
||||
String ip,
|
||||
int port,
|
||||
long eventSnowflake
|
||||
) implements EventWithSnowflake {
|
||||
public record StartClient(String ip, int port, long eventSnowflake) implements EventWithSnowflake {
|
||||
|
||||
/**
|
||||
* Returns a map representation of this event, where keys are record component names
|
||||
* and values are their corresponding values. Useful for generic logging, debugging,
|
||||
* or serializing events without hardcoding field names.
|
||||
*
|
||||
* @return a {@code Map<String, Object>} containing field names and values
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> result() {
|
||||
return Stream.of(this.getClass().getRecordComponents())
|
||||
.collect(Collectors.toMap(
|
||||
RecordComponent::getName,
|
||||
rc -> {
|
||||
try {
|
||||
return rc.getAccessor().invoke(this);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique event identifier used for correlating this event.
|
||||
*
|
||||
* @return the event ID string
|
||||
*/
|
||||
@Override
|
||||
public long eventSnowflake() {
|
||||
return this.eventSnowflake;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param clientId The ID of the client to be used in requests.
|
||||
* @param eventSnowflake The eventID used in checking if event is for you.
|
||||
*/
|
||||
public record StartClientResponse(long clientId, long eventSnowflake)
|
||||
implements EventWithSnowflake {
|
||||
@Override
|
||||
public Map<String, Object> result() {
|
||||
return Stream.of(this.getClass().getRecordComponents())
|
||||
@@ -122,52 +136,67 @@ public class NetworkEvents extends EventsBase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Response confirming a client was started.
|
||||
*
|
||||
* @param clientId The ID of the client that received the response.
|
||||
* @param clientId The client ID assigned to the new connection.
|
||||
* @param eventSnowflake Event ID used for correlation.
|
||||
*/
|
||||
public record StartClientResponse(long clientId, long eventSnowflake) implements EventWithSnowflake {
|
||||
@Override
|
||||
public Map<String, Object> result() {
|
||||
return Stream.of(this.getClass().getRecordComponents())
|
||||
.collect(Collectors.toMap(
|
||||
RecordComponent::getName,
|
||||
rc -> {
|
||||
try {
|
||||
return rc.getAccessor().invoke(this);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long eventSnowflake() {
|
||||
return this.eventSnowflake;
|
||||
}
|
||||
}
|
||||
|
||||
/** Generic server response. */
|
||||
public record ServerResponse(long clientId) implements EventWithoutSnowflake {}
|
||||
|
||||
/**
|
||||
* Triggers sending a command to a server.
|
||||
* Request to send a command to a server.
|
||||
*
|
||||
* @param connectionId The UUID of the connection to send the command on.
|
||||
* @param clientId The client connection ID.
|
||||
* @param args The command arguments.
|
||||
*/
|
||||
public record SendCommand(long connectionId, String... args) implements EventWithoutSnowflake {}
|
||||
/**
|
||||
* Triggers reconnecting to a previous address.
|
||||
*
|
||||
* @param connectionId The identifier of the connection being reconnected.
|
||||
*/
|
||||
public record Reconnect(long connectionId) implements EventWithoutSnowflake {}
|
||||
public record SendCommand(long clientId, String... args) implements EventWithoutSnowflake {}
|
||||
|
||||
/** WIP (Not working) Request to reconnect a client to a previous address. */
|
||||
public record Reconnect(long clientId) implements EventWithoutSnowflake {}
|
||||
|
||||
/**
|
||||
* Triggers when the server client receives a message.
|
||||
* Response triggered when a message is received from a server.
|
||||
*
|
||||
* @param ConnectionId The snowflake id of the connection that received the message.
|
||||
* @param message The message received.
|
||||
* @param clientId The connection ID that received the message.
|
||||
* @param message The message content.
|
||||
*/
|
||||
public record ReceivedMessage(long ConnectionId, String message) implements EventWithoutSnowflake {}
|
||||
public record ReceivedMessage(long clientId, String message) implements EventWithoutSnowflake {}
|
||||
|
||||
/**
|
||||
* Triggers changing connection to a new address.
|
||||
* Request to change a client connection to a new server.
|
||||
*
|
||||
* @param connectionId The identifier of the connection being changed.
|
||||
* @param ip The new IP address.
|
||||
* @param port The new port.
|
||||
* @param clientId The client connection ID.
|
||||
* @param ip The new server IP.
|
||||
* @param port The new server port.
|
||||
*/
|
||||
public record ChangeClient(long connectionId, String ip, int port) implements EventWithoutSnowflake {}
|
||||
public record ChangeClientHost(long clientId, String ip, int port) implements EventWithoutSnowflake {}
|
||||
|
||||
/** WIP (Not working) Response indicating that the client could not connect. */
|
||||
public record CouldNotConnect(long clientId) implements EventWithoutSnowflake {}
|
||||
|
||||
/**
|
||||
* Triggers when the server couldn't connect to the desired address.
|
||||
*
|
||||
* @param connectionId The identifier of the connection that failed.
|
||||
*/
|
||||
public record CouldNotConnect(long connectionId) implements EventWithoutSnowflake {}
|
||||
|
||||
/** WIP Triggers when a connection closes. */
|
||||
public record ClosedConnection() implements EventWithoutSnowflake {}
|
||||
|
||||
/** Event indicating a client connection was closed. */
|
||||
public record ClosedConnection(long clientId) implements EventWithoutSnowflake {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user