hanze/game-client

src/main/java/nl/isygameclient/network/GameClientBase.java in modern-design
Repositories | Summary | Log | Files

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}