Skip to content

Commit b794e0b

Browse files
committed
feat: extract player functionality of LobbyClient
1 parent d27c1bc commit b794e0b

File tree

8 files changed

+163
-151
lines changed

8 files changed

+163
-151
lines changed

player/src/main/sc/player2021/Starter.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33
import jargs.gnu.CmdLineParser;
44
import org.slf4j.Logger;
55
import org.slf4j.LoggerFactory;
6-
import sc.player2021.logic.Logic;
7-
import sc.player.PlayerClient;
6+
import sc.api.plugins.IGamePlugin;
7+
import sc.networking.clients.LobbyClient;
88
import sc.player.IGameHandler;
9+
import sc.player.IPlayerClient;
10+
import sc.player2021.logic.Logic;
911
import sc.shared.SharedConfiguration;
1012

1113
import java.io.File;
14+
import java.io.IOException;
1215

1316
/**
1417
* Hauptklasse des Clients, die über Konsolenargumente gesteuert werden kann.
@@ -17,18 +20,18 @@
1720
public class Starter {
1821
private static final Logger logger = LoggerFactory.getLogger(Starter.class);
1922

20-
public Starter(String host, int port, String reservation, String roomId) {
23+
public Starter(String host, int port, String reservation, String roomId) throws IOException {
2124
// Strategie zuweisen
2225
IGameHandler logic = new Logic();
23-
PlayerClient client = new PlayerClient(host, port, logic);
26+
IPlayerClient client = new LobbyClient(host, port).asPlayer(logic);
2427

2528
// einem Spiel beitreten
2629
if (reservation != null && !reservation.isEmpty()) {
27-
client.joinPreparedGame(reservation);
30+
client.joinGameWithReservation(reservation);
2831
} else if (roomId != null) {
2932
client.joinGameRoom(roomId);
3033
} else {
31-
client.joinAnyGame();
34+
client.joinGame(IGamePlugin.loadPluginId());
3235
}
3336
}
3437

player/src/main/sc/player2021/logic/Logic.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@
22

33
import org.slf4j.Logger;
44
import org.slf4j.LoggerFactory;
5-
import sc.api.plugins.TwoPlayerGameState;
6-
import sc.framework.plugins.Player;
5+
import sc.api.plugins.IGameState;
76
import sc.player.IGameHandler;
87
import sc.plugin2022.GameState;
98
import sc.plugin2022.Move;
109
import sc.shared.GameResult;
1110

12-
import java.util.ArrayList;
1311
import java.util.List;
1412

1513
/**
@@ -25,7 +23,7 @@ public class Logic implements IGameHandler {
2523
/** Aktueller Spielstatus. */
2624
private GameState gameState;
2725

28-
public void onGameOver(GameResult data, String errorMessage) {
26+
public void onGameOver(GameResult data) {
2927
log.info("Das Spiel ist beendet, Ergebnis: {}", data);
3028
}
3129

@@ -42,9 +40,13 @@ public Move calculateMove() {
4240
}
4341

4442
@Override
45-
public void onUpdate(TwoPlayerGameState gameState) {
43+
public void onUpdate(IGameState gameState) {
4644
this.gameState = (GameState) gameState;
4745
log.info("Zug: {} Dran: {}", gameState.getTurn(), gameState.getCurrentTeam());
4846
}
4947

48+
@Override
49+
public void onError(String error) {
50+
log.warn("Fehler: {}", error);
51+
}
5052
}
Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
package sc.player
22

3+
import sc.api.plugins.IGameState
34
import sc.api.plugins.IMove
4-
import sc.api.plugins.TwoPlayerGameState
5-
import sc.framework.plugins.Player
65
import sc.shared.GameResult
76

87
/**
@@ -13,17 +12,15 @@ import sc.shared.GameResult
1312
interface IGameHandler {
1413

1514
/** Wird aufgerufen, wenn sich das Spielbrett ändert. */
16-
fun onUpdate(gameState: TwoPlayerGameState)
15+
fun onUpdate(gameState: IGameState)
1716

1817
/** Wird aufgerufen, um die Zuganfrage des Servers zu beantworten. */
1918
fun calculateMove(): IMove
2019

21-
/**
22-
* Wird aufgerufen, wenn das Spiel beendet ist.
23-
*
24-
* @param data Das Spielergebnis
25-
* @param errorMessage Eventuelle Fehlernachricht
26-
*/
27-
fun onGameOver(data: GameResult, errorMessage: String?)
20+
/** Wird aufgerufen, wenn das Spiel beendet ist. */
21+
fun onGameOver(data: GameResult)
22+
23+
/** Wird aufgerufen, wenn der Server einen Fehler meldet*/
24+
fun onError(error: String)
2825

2926
}
Lines changed: 31 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,51 @@
11
package sc.player
22

3-
import org.slf4j.LoggerFactory
4-
import sc.api.plugins.*
53
import sc.framework.plugins.protocol.MoveRequest
6-
import sc.networking.clients.AbstractLobbyClientListener
7-
import sc.networking.clients.LobbyClient
4+
import sc.networking.clients.IClient
5+
import sc.protocol.requests.JoinGameRequest
6+
import sc.protocol.requests.JoinPreparedRoomRequest
7+
import sc.protocol.requests.JoinRoomRequest
88
import sc.protocol.room.ErrorMessage
9+
import sc.protocol.room.MementoMessage
910
import sc.protocol.room.RoomMessage
1011
import sc.shared.GameResult
11-
import java.net.ConnectException
12-
import kotlin.system.exitProcess
12+
import java.util.function.Function
13+
14+
interface IPlayerClient {
15+
fun joinGameWithReservation(reservation: String)
16+
fun joinGameRoom(roomId: String)
17+
/** Join any game with the appropriate [gameType]. */
18+
fun joinGame(gameType: String)
19+
}
1320

1421
/**
15-
* Eine Implementation des [AbstractLobbyClientListener],
16-
* um die Server-Kommunikation mit der Logik der Spieler zu verbinden.
22+
* Verbindet die Server-Kommunikation mit der Logik der Spieler.
1723
*/
1824
class PlayerClient(
19-
host: String,
20-
port: Int,
25+
private val client: IClient,
2126
private val handler: IGameHandler,
22-
): AbstractLobbyClientListener() {
23-
companion object {
24-
private val logger = LoggerFactory.getLogger(PlayerClient::class.java)
25-
}
26-
27-
var isGameOver = false
28-
29-
/** The lobby client that connects to the room. Stops on connection failure. */
30-
private val client: LobbyClient = try {
31-
LobbyClient(host, port)
32-
} catch (e: ConnectException) {
33-
logger.error("Could not connect to Server: ${e.message}")
34-
exitProcess(1)
35-
}
36-
37-
/** Storage for the reason of a rule violation, if any occurs. */
38-
var error: String? = null
39-
private set
40-
41-
/** Current room of the player. */
42-
private lateinit var roomId: String
43-
44-
/** Called for any new message sent to the game room, e.g., move requests. */
45-
override fun onRoomMessage(roomId: String, data: RoomMessage) {
46-
this.roomId = roomId
47-
when (data) {
48-
is MoveRequest -> sendMove(handler.calculateMove())
49-
is ErrorMessage -> {
50-
logger.debug("onError: Client $this received error ${data.message} in $roomId")
51-
this.error = data.message
52-
}
27+
): Function<RoomMessage, RoomMessage?>, IPlayerClient {
28+
29+
override fun apply(msg: RoomMessage): RoomMessage? {
30+
when (msg) {
31+
is MoveRequest -> return handler.calculateMove()
32+
is MementoMessage -> handler.onUpdate(msg.state)
33+
is GameResult -> handler.onGameOver(msg)
34+
is ErrorMessage -> handler.onError(msg.logMessage)
5335
}
36+
return null
5437
}
5538

56-
/** Sends the selected move to the server. */
57-
fun sendMove(move: IMove) =
58-
client.sendMessageToRoom(roomId, move)
59-
60-
/**
61-
* Called when game state has been received.
62-
* Happens after a client made a move.
63-
*/
64-
override fun onNewState(roomId: String, state: IGameState) {
65-
val gameState = state as TwoPlayerGameState
66-
logger.debug("$this got a new state $gameState")
67-
handler.onUpdate(gameState)
68-
}
69-
70-
/** Start the LobbyClient [client] and listen to it. */
71-
private fun start() {
72-
client.start()
73-
client.addListener(this)
74-
}
75-
76-
/** [start] and join any game with the appropriate [gameType]. */
77-
fun joinAnyGame() {
78-
start()
79-
client.joinGame(IGamePlugin.loadPluginId())
80-
}
81-
82-
fun joinPreparedGame(reservation: String) {
83-
start()
84-
client.joinGameWithReservation(reservation)
85-
}
86-
87-
fun joinGameRoom(roomId: String) {
88-
start()
89-
client.joinGameRoom(roomId)
39+
override fun joinGameWithReservation(reservation: String) {
40+
client.send(JoinPreparedRoomRequest(reservation))
9041
}
9142

92-
override fun onGameLeft(roomId: String) {
93-
logger.info("$this: Got game left in room $roomId")
94-
client.stop()
43+
override fun joinGameRoom(roomId: String) {
44+
client.send(JoinRoomRequest(roomId))
9545
}
9646

97-
override fun onGameOver(roomId: String, data: GameResult) {
98-
logger.info("$this: Game over with result $data")
99-
isGameOver = true
100-
handler.onGameOver(data, error)
47+
/** Join any game with the appropriate [gameType]. */
48+
override fun joinGame(gameType: String) {
49+
client.send(JoinGameRequest(gameType))
10150
}
10251
}

sdk/src/server-api/sc/networking/clients/LobbyClient.java

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
import org.slf4j.Logger;
44
import org.slf4j.LoggerFactory;
55
import sc.api.plugins.IGameState;
6-
import sc.framework.plugins.Player;
6+
import sc.player.IGameHandler;
7+
import sc.player.IPlayerClient;
8+
import sc.player.PlayerClient;
79
import sc.protocol.ProtocolPacket;
810
import sc.protocol.RemovedFromGame;
911
import sc.protocol.ResponsePacket;
@@ -18,6 +20,7 @@
1820
import java.util.List;
1921
import java.util.Map;
2022
import java.util.function.Consumer;
23+
import java.util.function.Function;
2124

2225
/**
2326
* This class is used to handle all communication with a server.
@@ -32,13 +35,42 @@ public final class LobbyClient extends XStreamClient implements IPollsHistory {
3235
private final List<ILobbyClientListener> listeners = new ArrayList<>();
3336
private final List<IHistoryListener> historyListeners = new ArrayList<>();
3437

35-
private final Map<String, Consumer<ObservableRoomMessage>> roomObservers = new HashMap<>();
38+
private Function<RoomMessage, RoomMessage> player = null;
3639
private Consumer<ResponsePacket> administrativeListener = null;
40+
private final Map<String, Consumer<ObservableRoomMessage>> roomObservers = new HashMap<>();
3741

3842
public LobbyClient(String host, int port) throws IOException {
3943
super(createTcpNetwork(host, port));
4044
}
4145

46+
/** Request authentication on server with a listener.
47+
* @return an AdminClient to send authorised requests */
48+
public AdminClient authenticate(String password, Consumer<ResponsePacket> consumer) {
49+
start();
50+
if(administrativeListener != null)
51+
logger.warn("Re-authentication replaces {}", administrativeListener);
52+
administrativeListener = consumer;
53+
send(new AuthenticateRequest(password));
54+
return new AdminClient(this);
55+
}
56+
57+
58+
/** Sets observer to observe messages in the given room.
59+
* Whether administrative messages are received depends on authentication,
60+
* which has to be done separately. */
61+
public void observeRoom(String roomId, Consumer<ObservableRoomMessage> observer) {
62+
roomObservers.put(roomId, observer);
63+
}
64+
65+
/** Sets this client up to play a game utilizing the handler.
66+
* @return a PlayerClient to join a room as Player. */
67+
public IPlayerClient asPlayer(IGameHandler handler) {
68+
start();
69+
PlayerClient client = new PlayerClient(this, handler);
70+
player = client;
71+
return client;
72+
}
73+
4274
@Override
4375
protected final void onObject(ProtocolPacket message) {
4476
if(message instanceof ResponsePacket && administrativeListener != null)
@@ -47,6 +79,12 @@ protected final void onObject(ProtocolPacket message) {
4779
RoomPacket packet = (RoomPacket) message;
4880
String roomId = packet.getRoomId();
4981
RoomMessage data = packet.getData();
82+
if(player != null) {
83+
// TODO run this in a background thread
84+
RoomMessage response = player.apply(data);
85+
if(response != null)
86+
sendMessageToRoom(roomId, response);
87+
}
5088
if(data instanceof ObservableRoomMessage) {
5189
roomObservers.getOrDefault(roomId, (m) -> {}).accept((ObservableRoomMessage) data);
5290
if (data instanceof MementoMessage) {
@@ -86,6 +124,13 @@ protected final void onObject(ProtocolPacket message) {
86124
}
87125
}
88126

127+
public void sendMessageToRoom(String roomId, RoomMessage o) {
128+
send(new RoomPacket(roomId, o));
129+
}
130+
131+
// TODO The following functions are obsolete
132+
// and will be removed once all tests are migrated to the new style
133+
89134
private void onGameOver(String roomId, GameResult data) {
90135
logger.info("Received game result: {}", data);
91136
for (IHistoryListener listener : this.historyListeners) {
@@ -127,15 +172,6 @@ public void authenticate(String password) {
127172
send(new AuthenticateRequest(password));
128173
}
129174

130-
public AdminClient authenticate(String password, Consumer<ResponsePacket> consumer) {
131-
start();
132-
if(administrativeListener != null)
133-
logger.warn("Re-authentication replaces {}", administrativeListener);
134-
administrativeListener = consumer;
135-
send(new AuthenticateRequest(password));
136-
return new AdminClient(this);
137-
}
138-
139175
protected void onCustomObject(Object o) {
140176
logger.warn("Couldn't process message {}.", o);
141177
}
@@ -155,10 +191,6 @@ protected void onRoomMessage(String roomId, RoomMessage data) {
155191
}
156192
}
157193

158-
public void sendMessageToRoom(String roomId, RoomMessage o) {
159-
send(new RoomPacket(roomId, o));
160-
}
161-
162194
public void joinGameWithReservation(String reservation) {
163195
send(new JoinPreparedRoomRequest(reservation));
164196
}
@@ -190,13 +222,6 @@ public ObservingClient observe(String roomId, boolean isPaused) {
190222
return observer;
191223
}
192224

193-
/** Sets observer to observe messages in the given room.
194-
* Whether administrative messages are received depends on authentication,
195-
* which has to be done separately. */
196-
public void observeRoom(String roomId, Consumer<ObservableRoomMessage> observer) {
197-
roomObservers.put(roomId, observer);
198-
}
199-
200225
@Override
201226
public void addListener(IHistoryListener listener) {
202227
this.historyListeners.add(listener);

0 commit comments

Comments
 (0)