Skip to content

Commit fb949ac

Browse files
committed
Implement sending and receiving of events/commands
1 parent be3f88d commit fb949ac

File tree

3 files changed

+101
-10
lines changed

3 files changed

+101
-10
lines changed

src/main/java/org/codegame/client/Api.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public class Api {
2424
private boolean tls;
2525
private String baseURL;
2626

27-
static Gson json = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
27+
public static Gson json = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
2828
.create();
2929

3030
public Api(String url) {
@@ -53,6 +53,10 @@ public GameInfo fetchInfo() throws IOException {
5353
return fetchJSON("/api/info", GameInfo.class);
5454
}
5555

56+
public static class GameConfigResponse<T> {
57+
public T config;
58+
}
59+
5660
public <T> T fetchGameConfig(String gameId, Class<T> configClass) throws IOException {
5761
GameConfigResponse<T> response = fetchJSON("/api/games/" + gameId,
5862
TypeToken.getParameterized(GameConfigResponse.class,

src/main/java/org/codegame/client/GameConfigResponse.java

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/main/java/org/codegame/client/GameSocket.java

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,34 @@
33
import java.io.IOException;
44
import java.net.http.WebSocket;
55
import java.util.HashMap;
6+
import java.util.UUID;
67
import java.util.concurrent.CountDownLatch;
78

8-
import org.codegame.client.Api.GameInfo;
9+
import com.google.gson.annotations.SerializedName;
10+
import com.google.gson.reflect.TypeToken;
911

1012
public class GameSocket {
13+
@FunctionalInterface
14+
public interface EventCallback<T> {
15+
void cb(T data);
16+
}
17+
18+
private class Callbacks<T> {
19+
Class<T> type;
20+
HashMap<String, EventCallback<T>> callbacks;
21+
22+
Callbacks(Class<T> type) {
23+
this.type = type;
24+
this.callbacks = new HashMap<>();
25+
}
26+
}
27+
1128
private Api api;
1229
private Session session = new Session();
1330
private WebSocket websocket;
1431
private HashMap<String, String> usernameCache = new HashMap<>();
32+
@SuppressWarnings("rawtypes")
33+
private HashMap<String, Callbacks> eventListeners = new HashMap<>();
1534
private CountDownLatch exitEvent = new CountDownLatch(1);
1635

1736
public GameSocket(String url) {
@@ -77,7 +96,7 @@ public void connect(String gameId) throws IOException {
7796
usernameCache = api.fetchPlayers(gameId);
7897
}
7998

80-
public void block() {
99+
public void listen() {
81100
try {
82101
exitEvent.await();
83102
} catch (InterruptedException e) {
@@ -87,7 +106,67 @@ public void block() {
87106

88107
public void close() {
89108
websocket.sendClose(WebSocket.NORMAL_CLOSURE, "Normal closure.");
90-
block();
109+
listen();
110+
}
111+
112+
public static class Event<T> {
113+
@SerializedName("name")
114+
String name;
115+
@SerializedName("data")
116+
T data;
117+
118+
public Event() {
119+
}
120+
121+
public Event(String name, T data) {
122+
this.name = name;
123+
this.data = data;
124+
}
125+
}
126+
127+
@SuppressWarnings("unchecked")
128+
public <T> String on(String eventName, Class<T> type, EventCallback<T> callback) {
129+
if (!eventListeners.containsKey(eventName))
130+
eventListeners.put(eventName, new Callbacks<>(type));
131+
132+
var id = UUID.randomUUID().toString();
133+
var callbacks = (Callbacks<T>) eventListeners.get(eventName);
134+
if (!callbacks.type.getTypeName().equals(type.getTypeName()))
135+
throw new IllegalArgumentException("Wrong event listener type.");
136+
callbacks.type = type;
137+
callbacks.callbacks.put(id, callback);
138+
return id;
139+
}
140+
141+
@SuppressWarnings("unchecked")
142+
public <T> String once(String eventName, Class<T> type, EventCallback<T> callback) {
143+
if (!eventListeners.containsKey(eventName))
144+
eventListeners.put(eventName, new Callbacks<>(type));
145+
146+
var id = UUID.randomUUID().toString();
147+
var callbacks = (Callbacks<T>) eventListeners.get(eventName);
148+
if (!callbacks.type.getTypeName().equals(type.getTypeName()))
149+
throw new IllegalArgumentException("Wrong event listener type.");
150+
callbacks.type = type;
151+
callbacks.callbacks.put(id, (data) -> {
152+
callback.cb(data);
153+
removeCallback(eventName, id);
154+
});
155+
return id;
156+
}
157+
158+
public <T> void send(String commandName, T data) {
159+
if (websocket == null || session.getPlayerId() == "")
160+
throw new IllegalStateException("The socket is not connected to a player.");
161+
Event<T> e = new Event<>(commandName, data);
162+
var json = Api.json.toJson(e, TypeToken.getParameterized(Event.class, data.getClass()).getType());
163+
websocket.sendText(json, true).join();
164+
}
165+
166+
public void removeCallback(String eventName, String id) {
167+
if (!eventListeners.containsKey(eventName))
168+
return;
169+
eventListeners.get(eventName).callbacks.remove(id);
91170
}
92171

93172
public Api getApi() {
@@ -98,8 +177,21 @@ public Session getSession() {
98177
return session;
99178
}
100179

180+
private class EventMessage {
181+
@SerializedName("name")
182+
String name;
183+
}
184+
185+
@SuppressWarnings({ "unchecked", "rawtypes" })
101186
private void onMessage(String message) {
102-
System.out.println("Received: " + message);
187+
var emptyEvent = Api.json.fromJson(message, EventMessage.class);
188+
if (!eventListeners.containsKey(emptyEvent.name))
189+
return;
190+
var callbacks = eventListeners.get(emptyEvent.name);
191+
Event event = Api.json.fromJson(message, TypeToken.getParameterized(Event.class, callbacks.type).getType());
192+
for (EventCallback cb : ((HashMap<String, EventCallback>) callbacks.callbacks).values()) {
193+
cb.cb(event.data);
194+
}
103195
}
104196

105197
private void onClose() {

0 commit comments

Comments
 (0)