GameClientBase.java (3566B) download
1package nl.isygameclient.network;
2
3import java.io.BufferedReader;
4import java.io.IOException;
5import java.io.InputStreamReader;
6import java.io.OutputStream;
7import java.net.Socket;
8import java.util.Arrays;
9import java.util.LinkedList;
10
11public abstract class GameClientBase extends Socket {
12 private final OutputStream outputStream;
13 private final BufferedReader inputBuffer;
14
15 private LinkedList<Event> eventQueue = new LinkedList<>();
16 private LinkedList<String> eventLineQueue = new LinkedList<>();
17
18 public GameClientBase(String host, int port) throws IOException {
19 super(host, port);
20 outputStream = getOutputStream();
21 inputBuffer = new BufferedReader(new InputStreamReader(getInputStream()));
22
23 try {
24 Thread.sleep(100);
25 while (inputBuffer.ready()) {
26 inputBuffer.readLine();
27 Thread.sleep(100);
28 }
29 } catch (InterruptedException exc) {
30 throw new GameClientException("socket initiation failed: " + exc.getMessage());
31 }
32 }
33
34 public void send(String command, String... arguments) throws IOException {
35 var requestBuilder = new StringBuilder(command);
36 for (var argument : arguments) {
37 requestBuilder.append(' ');
38 requestBuilder.append(argument);
39 }
40
41 requestBuilder.append('\n');
42 outputStream.write(requestBuilder.toString().getBytes());
43
44 String response;
45 for (;;) {
46 response = inputBuffer.readLine();
47 if (response.startsWith("ERR "))
48 throw new GameClientException(response.substring(4));
49 else if (response.startsWith("SVR ")) {
50 eventLineQueue.add(response);
51 continue;
52 } else if (response.equals("OK"))
53 break;
54 throw new GameClientException("invalid server response: '" + response + "'");
55 }
56 }
57
58 public Event event(EventType... target) throws IOException {
59 return event(1, true, target);
60 }
61
62 public Event event(double timeout, EventType... target) throws IOException {
63 return event(timeout, true, target);
64 }
65
66 public Event event(double timeout, boolean consume, EventType... target) throws IOException {
67 var targetList = Arrays.asList(target);
68 if (!eventQueue.isEmpty()) {
69 if (target == null)
70 return eventQueue.poll();
71
72 for (int i = 0; i < eventQueue.size(); i++) {
73 if (targetList.contains(eventQueue.get(i).type))
74 return consume ? eventQueue.remove(i) : eventQueue.get(i);
75 }
76 }
77
78 long start = System.currentTimeMillis();
79 Event result;
80 String line;
81
82 do {
83 if (eventLineQueue.isEmpty()) {
84 try {
85 Thread.sleep(100);
86 if (!inputBuffer.ready())
87 continue;
88 line = inputBuffer.readLine();
89 } catch (InterruptedException exc) {
90 throw new GameClientException("event-pulling interrupted");
91 }
92 } else {
93 line = eventLineQueue.poll();
94 }
95
96 if (!line.startsWith("SVR "))
97 throw new GameClientException("invalid server response: '" + line + "'");
98
99
100 result = null;
101 for (var evt : EventType.values()) {
102 if (line.startsWith(evt.identifier, 4)) {
103 result = new Event(evt, new EventParser(line.substring(evt.identifier.length() + 4)).parseData());
104 break;
105 }
106 }
107
108 if (result == null)
109 throw new GameClientException("invalid server response: unknown event '" + line + "'");
110
111
112 if (target.length == 0 || target.length > 0 && targetList.contains(result.type)) {
113 if (!consume)
114 eventQueue.push(result);
115 return result;
116 }
117
118 eventQueue.push(result);
119 } while (timeout == -1 || System.currentTimeMillis() - start < timeout * 1000);
120
121 return null;
122 }
123
124 @Override
125 public void close() throws IOException {
126 outputStream.write("logout\n".getBytes());
127 super.close();
128 }
129}