bugfixes in server and cli-client
This commit is contained in:
@@ -25,7 +25,14 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static picocli.CommandLine.*;
|
||||
|
||||
@Command
|
||||
public class Client extends TimeoutContext<ClientState, Client> implements Runnable {
|
||||
@Option(names = "-v")
|
||||
@Getter
|
||||
private boolean verbose;
|
||||
|
||||
private LineReader reader;
|
||||
|
||||
@Getter
|
||||
@@ -39,7 +46,7 @@ public class Client extends TimeoutContext<ClientState, Client> implements Runna
|
||||
private CommandSpec spec;
|
||||
|
||||
public static void main(String[] args) {
|
||||
new Client().run();
|
||||
new CommandLine(new Client()).execute(args);
|
||||
}
|
||||
|
||||
public Client() {
|
||||
@@ -126,6 +133,9 @@ public class Client extends TimeoutContext<ClientState, Client> implements Runna
|
||||
}
|
||||
|
||||
public void onMessage(ServerMessage message) {
|
||||
if (verbose) {
|
||||
println(message.toString());
|
||||
}
|
||||
execute(s -> s.onMessage(this, message));
|
||||
}
|
||||
|
||||
@@ -239,7 +249,7 @@ public class Client extends TimeoutContext<ClientState, Client> implements Runna
|
||||
Exception exception = exceptionRef.get();
|
||||
if (exception == null) {
|
||||
Object result;
|
||||
CommandLine.ParseResult parseResult = commandLine.getParseResult();
|
||||
ParseResult parseResult = commandLine.getParseResult();
|
||||
if (parseResult.subcommand() != null) {
|
||||
CommandLine sub = parseResult.subcommand().commandSpec().commandLine();
|
||||
result = sub.getExecutionResult();
|
||||
|
@@ -1,15 +1,12 @@
|
||||
package eu.jonahbauer.wizard.client.cli.commands;
|
||||
|
||||
import eu.jonahbauer.wizard.client.cli.Client;
|
||||
import eu.jonahbauer.wizard.client.cli.state.AwaitingAcknowledgement;
|
||||
import eu.jonahbauer.wizard.client.cli.state.Game;
|
||||
import eu.jonahbauer.wizard.client.cli.state.Menu;
|
||||
import eu.jonahbauer.wizard.common.messages.client.InteractionMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.player.JuggleMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.player.PickTrumpMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.player.PlayCardMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.player.PredictMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.server.NackMessage;
|
||||
import eu.jonahbauer.wizard.common.model.Card;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -21,60 +18,41 @@ import static picocli.CommandLine.*;
|
||||
@Command(name = "\b", subcommands = {HelpCommand.class, QuitCommand.class, ShowCommand.class})
|
||||
public class GameCommand {
|
||||
private final Client client;
|
||||
private final Game game;
|
||||
|
||||
public GameCommand(Client client, Game game) {
|
||||
public GameCommand(Client client) {
|
||||
this.client = client;
|
||||
this.game = game;
|
||||
}
|
||||
|
||||
@Command(name = "play")
|
||||
public AwaitingAcknowledgement play(
|
||||
public void play(
|
||||
@Parameters(index = "0", paramLabel = "<card>", completionCandidates = HandCompletion.class) Card card
|
||||
) {
|
||||
this.client.send(new InteractionMessage(new PlayCardMessage(card)));
|
||||
return awaitAcknowledgement();
|
||||
this.client.waitForReady();
|
||||
}
|
||||
|
||||
@Command(name = "predict")
|
||||
public AwaitingAcknowledgement predict(
|
||||
public void predict(
|
||||
@Parameters(index = "0", paramLabel = "<prediction>") int prediction
|
||||
) {
|
||||
this.client.send(new InteractionMessage(new PredictMessage(prediction)));
|
||||
return awaitAcknowledgement();
|
||||
this.client.waitForReady();
|
||||
}
|
||||
|
||||
@Command(name = "trump")
|
||||
public AwaitingAcknowledgement trump(
|
||||
public void trump(
|
||||
@Parameters(index = "0", paramLabel = "<suit>") Card.Suit suit
|
||||
) {
|
||||
this.client.send(new InteractionMessage(new PickTrumpMessage(suit)));
|
||||
return awaitAcknowledgement();
|
||||
this.client.waitForReady();
|
||||
}
|
||||
|
||||
@Command(name = "juggle")
|
||||
public AwaitingAcknowledgement juggle(
|
||||
public void juggle(
|
||||
@Parameters(index = "0", paramLabel = "<card>", completionCandidates = JuggleCompletion.class) Card card
|
||||
) {
|
||||
this.client.send(new InteractionMessage(new JuggleMessage(card)));
|
||||
return awaitAcknowledgement();
|
||||
}
|
||||
|
||||
private AwaitingAcknowledgement awaitAcknowledgement() {
|
||||
return new AwaitingAcknowledgement(
|
||||
() -> game,
|
||||
message -> {
|
||||
if (message instanceof NackMessage nack) {
|
||||
int code = nack.getCode();
|
||||
if (code == NackMessage.ILLEGAL_ARGUMENT || code == NackMessage.ILLEGAL_STATE) {
|
||||
client.println("Error: " + nack.getMessage());
|
||||
return game;
|
||||
}
|
||||
}
|
||||
client.println("Fatal: Unexpected message " + message + ". Returning to menu.");
|
||||
return new Menu();
|
||||
}
|
||||
);
|
||||
this.client.waitForReady();
|
||||
}
|
||||
|
||||
public static class HandCompletion implements Iterable<String> {
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package eu.jonahbauer.wizard.client.cli.commands;
|
||||
|
||||
import eu.jonahbauer.wizard.client.cli.Client;
|
||||
import eu.jonahbauer.wizard.client.cli.state.AwaitingAcknowledgement;
|
||||
import eu.jonahbauer.wizard.client.cli.state.AwaitingJoinLobby;
|
||||
import eu.jonahbauer.wizard.client.cli.state.Session;
|
||||
import eu.jonahbauer.wizard.common.messages.client.LeaveSessionMessage;
|
||||
@@ -20,13 +19,12 @@ public class SessionCommand {
|
||||
}
|
||||
|
||||
@Command(name = "ready")
|
||||
public AwaitingAcknowledgement ready(
|
||||
public void ready(
|
||||
@Parameters(index = "0", paramLabel = "<ready>", defaultValue = "true") boolean ready
|
||||
) {
|
||||
session.setNextReady(ready);
|
||||
client.send(new ReadyMessage(ready));
|
||||
return new AwaitingAcknowledgement(
|
||||
() -> new Session(session.getSelf(), session.getSession(), ready, session.getPlayers())
|
||||
);
|
||||
client.waitForReady();
|
||||
}
|
||||
|
||||
@Command(name = "leave", description = "Leaves the current session and returns to the lobby")
|
||||
|
@@ -1,43 +0,0 @@
|
||||
package eu.jonahbauer.wizard.client.cli.state;
|
||||
|
||||
import eu.jonahbauer.wizard.client.cli.Client;
|
||||
import eu.jonahbauer.wizard.common.messages.server.AckMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.server.Response;
|
||||
import eu.jonahbauer.wizard.common.messages.server.ServerMessage;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class AwaitingAcknowledgement extends Awaiting {
|
||||
private final Supplier<ClientState> success;
|
||||
private final Function<ServerMessage, ClientState> failure;
|
||||
|
||||
public AwaitingAcknowledgement(Supplier<ClientState> success, Function<ServerMessage, ClientState> failure) {
|
||||
this.success = success;
|
||||
this.failure = failure;
|
||||
}
|
||||
|
||||
public AwaitingAcknowledgement(Supplier<ClientState> success) {
|
||||
this.success = success;
|
||||
this.failure = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ClientState> onEnter(Client client) {
|
||||
client.println("Waiting for acknowledgment...");
|
||||
return super.onEnter(client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ClientState> onMessage(Client client, ServerMessage message) {
|
||||
if (message instanceof AckMessage) {
|
||||
return Optional.of(success.get());
|
||||
} else if (failure != null) {
|
||||
return Optional.of(failure.apply(message));
|
||||
} else {
|
||||
return super.onMessage(client, message);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,9 +1,7 @@
|
||||
package eu.jonahbauer.wizard.client.cli.state;
|
||||
|
||||
import eu.jonahbauer.wizard.client.cli.Client;
|
||||
import eu.jonahbauer.wizard.common.messages.server.NackMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.server.ServerMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.server.SessionJoinedMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.server.*;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -28,6 +26,9 @@ public final class AwaitingJoinSession extends Awaiting {
|
||||
default -> { return super.onMessage(client, message); }
|
||||
}
|
||||
return Optional.of(new AwaitingJoinLobby());
|
||||
} else if (message instanceof SessionModifiedMessage || message instanceof SessionRemovedMessage) {
|
||||
// drop
|
||||
return Optional.empty();
|
||||
} else {
|
||||
return super.onMessage(client, message);
|
||||
}
|
||||
|
@@ -31,6 +31,9 @@ public abstract class BaseState implements ClientState {
|
||||
protected static Optional<ClientState> unexpectedMessage(Client client, ServerMessage message) {
|
||||
// return to menu on unexpected message
|
||||
client.println("Fatal: Unexpected message " + message + ". Returning to menu.");
|
||||
if (client.isVerbose()) {
|
||||
new Exception().printStackTrace();
|
||||
}
|
||||
return Optional.of(new Menu());
|
||||
}
|
||||
}
|
||||
|
@@ -5,7 +5,9 @@ import eu.jonahbauer.wizard.client.cli.commands.GameCommand;
|
||||
import eu.jonahbauer.wizard.client.cli.util.Pair;
|
||||
import eu.jonahbauer.wizard.common.messages.data.PlayerData;
|
||||
import eu.jonahbauer.wizard.common.messages.observer.*;
|
||||
import eu.jonahbauer.wizard.common.messages.server.AckMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.server.GameMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.server.NackMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.server.ServerMessage;
|
||||
import eu.jonahbauer.wizard.common.model.Card;
|
||||
import lombok.Getter;
|
||||
@@ -149,6 +151,18 @@ public final class Game extends BaseState {
|
||||
throw new AssertionError("Unknown observer message " + observerMessage.getClass().getSimpleName() + "");
|
||||
}
|
||||
return Optional.empty();
|
||||
} else if (message instanceof NackMessage nack) {
|
||||
int code = nack.getCode();
|
||||
if (code == NackMessage.ILLEGAL_ARGUMENT || code == NackMessage.ILLEGAL_STATE) {
|
||||
client.println("Error: " + nack.getMessage());
|
||||
client.ready();
|
||||
return Optional.empty();
|
||||
} else {
|
||||
return unexpectedMessage(client, message);
|
||||
}
|
||||
} else if (message instanceof AckMessage) {
|
||||
client.ready();
|
||||
return Optional.empty();
|
||||
} else {
|
||||
return unexpectedMessage(client, message);
|
||||
}
|
||||
|
@@ -23,7 +23,9 @@ public final class Menu extends BaseState {
|
||||
|
||||
@Override
|
||||
public Optional<ClientState> onMessage(Client client, ServerMessage message) {
|
||||
throw new AssertionError("Received a ServerMessage while not connected.");
|
||||
// it is possible that there are messages still queued after
|
||||
// returning to the menu as a result of a previous message
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -5,6 +5,7 @@ import eu.jonahbauer.wizard.client.cli.commands.SessionCommand;
|
||||
import eu.jonahbauer.wizard.common.messages.data.PlayerData;
|
||||
import eu.jonahbauer.wizard.common.messages.server.*;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import picocli.CommandLine.Model.CommandSpec;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -19,9 +20,12 @@ public final class Session extends BaseState {
|
||||
|
||||
private final UUID self;
|
||||
private final UUID session;
|
||||
private final boolean ready;
|
||||
private final Map<UUID, PlayerData> players = new HashMap<>();
|
||||
|
||||
private boolean ready;
|
||||
@Setter
|
||||
private Boolean nextReady;
|
||||
|
||||
public Session(SessionJoinedMessage joined) {
|
||||
this.self = joined.getPlayer();
|
||||
this.session = joined.getSession();
|
||||
@@ -68,6 +72,16 @@ public final class Session extends BaseState {
|
||||
session,
|
||||
players.values().stream().collect(Collectors.toMap(PlayerData::getUuid, PlayerData::getName))
|
||||
));
|
||||
} else if (nextReady != null && message instanceof NackMessage nack) {
|
||||
client.println("Error: " + nack.getMessage());
|
||||
nextReady = null;
|
||||
client.ready();
|
||||
return Optional.empty();
|
||||
} else if (nextReady != null && message instanceof AckMessage) {
|
||||
ready = nextReady;
|
||||
nextReady = null;
|
||||
client.ready();
|
||||
return Optional.empty();
|
||||
} else {
|
||||
return unexpectedMessage(client, message);
|
||||
}
|
||||
|
Reference in New Issue
Block a user