From d9523e9229313d75bd6575dd7b6b39480e14596d Mon Sep 17 00:00:00 2001 From: Vasily Date: Thu, 10 Nov 2016 17:53:32 +0300 Subject: [PATCH] Added ability to position visual stuff as "absolute", i.e. in coordinates equal to screen pixels Currently only Python client supports this --- clients/python/MyStrategy.py | 3 + clients/python/debug_client.py | 37 ++++- .../plugins/LocalTestRendererListener.java | 153 +++++++++++------- 3 files changed, 127 insertions(+), 66 deletions(-) diff --git a/clients/python/MyStrategy.py b/clients/python/MyStrategy.py index 44d3fb9..23b6741 100644 --- a/clients/python/MyStrategy.py +++ b/clients/python/MyStrategy.py @@ -28,3 +28,6 @@ def move(self, me, world, game, move): with debug.post() as dbg: for w in world.wizards: dbg.text(w.x, w.y, '%s (%s)' % ([player.name for player in world.players if player.id == w.owner_player_id][0], w.level), (0, 1, 0)) + + with debug.abs() as dbg: + dbg.text(500, 500, 'HELLO ABS WORLD', (1, 0, 0)) diff --git a/clients/python/debug_client.py b/clients/python/debug_client.py index 597dde3..c268703 100644 --- a/clients/python/debug_client.py +++ b/clients/python/debug_client.py @@ -4,6 +4,13 @@ import socket import collections +import time +import errno + +try: + xrange +except NameError: + xrange = range Color = collections.namedtuple('Color', 'r g b') @@ -14,13 +21,23 @@ class DebugClient(object): DEFAULT_HOST = '127.0.0.1' DEFAULT_PORT = 13579 - MODE_PRE, MODE_POST, MODE_UNKNOWN = 'pre post unknown'.split() - BEGINS = {MODE_PRE: 'begin pre\n', MODE_POST: 'begin post\n'} - ENDS = {MODE_PRE: 'end pre\n', MODE_POST: 'end post\n'} + MODE_PRE, MODE_POST, MODE_ABS, MODE_UNKNOWN = 'pre post abs unknown'.split() + BEGINS = {MODE_PRE: 'begin pre\n', MODE_POST: 'begin post\n', MODE_ABS: 'begin abs\n'} + ENDS = {MODE_PRE: 'end pre\n', MODE_POST: 'end post\n', MODE_ABS: 'end abs\n'} def __init__(self, host=None, port=None): self.socket = socket.socket() self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True) - self.socket.connect((host or self.DEFAULT_HOST, port or self.DEFAULT_PORT)) + for _ in xrange(20): + try: + self.socket.connect((host or self.DEFAULT_HOST, port or self.DEFAULT_PORT)) + except socket.error as ex: + if ex.errno == errno.WSAECONNREFUSED: + time.sleep(0.1) + continue + raise + else: + break + self.mode = self.MODE_UNKNOWN self.last_sync_tick = None self.reader = self.__buffered_reader() @@ -43,6 +60,16 @@ def post(self): self.mode = self.MODE_POST return self + def abs(self): + ''' + Method to create an absolutely positioned drawing context, that is, to draw things that + should be drawn *after* the field is drawn by local runner (i.e. they will appear + "above" the field) and coordinates used are based on the view window, not the field + ''' + assert self.mode == self.MODE_UNKNOWN + self.mode = self.MODE_ABS + return self + def __enter__(self): self.start() return self @@ -52,7 +79,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): def start(self): ''' - Starts sending messages to specified queue (pre- or post-). + Starts sending messages to specified queue. Note: previous value in the queue will be cleaned up on the server ''' assert self.mode in self.BEGINS diff --git a/local-runner/plugins/LocalTestRendererListener.java b/local-runner/plugins/LocalTestRendererListener.java index 5439fba..692d70a 100644 --- a/local-runner/plugins/LocalTestRendererListener.java +++ b/local-runner/plugins/LocalTestRendererListener.java @@ -101,32 +101,37 @@ else if (type.equals(TEXT)) color = new Color(r, g, b); } - public void draw(Graphics graphics, LocalTestRendererListener listner) + public void draw(Graphics graphics, LocalTestRendererListener listner, boolean useAbsCoords) { if (type == UNKNOWN) return; graphics.setColor(color); - if (type.equals(CIRCLE)) listner.drawCircle(x1, y1, x2); - if (type.equals(FILL_CIRCLE)) listner.fillCircle(x1, y1, x2); - if (type.equals(RECT)) listner.drawRect(x1, y1, x2 - x1, y2 - y1); - if (type.equals(FILL_RECT)) listner.fillRect(x1, y1, x2 - x1, y2 - y1); - if (type.equals(LINE)) listner.drawLine(x1, y1, x2, y2); - if (type.equals(TEXT)) listner.showText(x1, y1, text); + if (type.equals(CIRCLE)) listner.drawCircle(x1, y1, x2, useAbsCoords); + if (type.equals(FILL_CIRCLE)) listner.fillCircle(x1, y1, x2, useAbsCoords); + if (type.equals(RECT)) listner.drawRect(x1, y1, x2 - x1, y2 - y1, useAbsCoords); + if (type.equals(FILL_RECT)) listner.fillRect(x1, y1, x2 - x1, y2 - y1, useAbsCoords); + if (type.equals(LINE)) listner.drawLine(x1, y1, x2, y2, useAbsCoords); + if (type.equals(TEXT)) listner.showText(x1, y1, text, useAbsCoords); } } + + enum TargetQueue {PRE, POST, ABS, NONE}; + private final class ThreadListener extends Thread { public static final String BEGIN_PRE = "begin pre"; public static final String END_PRE = "end pre"; public static final String BEGIN_POST = "begin post"; public static final String END_POST = "end post"; + public static final String BEGIN_ABS = "begin abs"; + public static final String END_ABS = "end abs"; public static final String SYNC = "sync"; public static final String ACKNOWLEDGE = "ack"; private static final int BUFFER_SIZE_BYTES = 1 << 20; - + private ServerSocket socket; - private ArrayList messagesPre, messagesPost, lastMessagesPre, lastMessagesPost; - private int queue; + private ArrayList messagesPre, messagesPost, messagesAbs, lastMessagesPre, lastMessagesPost, lastMessagesAbs; + private TargetQueue queue; private Lock lock; private OutputStream outputStream; private OutputStreamWriter outputWriter; @@ -136,9 +141,12 @@ public ThreadListener(int port) throws IOException socket = new ServerSocket(port); messagesPre = new ArrayList(); messagesPost = new ArrayList(); + messagesAbs = new ArrayList(); lastMessagesPre = new ArrayList(); lastMessagesPost = new ArrayList(); - queue = 0; + lastMessagesAbs = new ArrayList(); + + queue = TargetQueue.NONE; lock = new ReentrantLock(); outputStream = null; outputWriter = null; @@ -193,11 +201,11 @@ else if (line.equals(BEGIN_PRE)) messagesPre = tmp; messagesPre.clear(); - queue = -1; + queue = TargetQueue.PRE; } else if (line.equals(END_PRE)) { - queue = 0; + queue = TargetQueue.NONE; } else if (line.equals(BEGIN_POST)) { @@ -207,13 +215,27 @@ else if (line.equals(BEGIN_POST)) messagesPost = tmp; messagesPost.clear(); - queue = 1; + queue = TargetQueue.POST; } else if (line.equals(END_POST)) { - queue = 0; + queue = TargetQueue.NONE; } - else if (queue != 0) + else if (line.equals(BEGIN_ABS)) + { + // swap lists + ArrayList tmp = lastMessagesAbs; + lastMessagesAbs = messagesAbs; + messagesAbs = tmp; + + messagesAbs.clear(); + queue = TargetQueue.ABS; + } + else if (line.equals(END_ABS)) + { + queue = TargetQueue.NONE; + } + else if (queue != TargetQueue.NONE) { Message msg = null; try @@ -226,14 +248,18 @@ else if (queue != 0) } if (msg != null) { - if (queue == 1) - { - messagesPost.add(msg); - } - else if (queue == -1) - { - messagesPre.add(msg); - } + switch (queue) + { + case POST: + messagesPost.add(msg); + break; + case PRE: + messagesPre.add(msg); + break; + case ABS: + messagesAbs.add(msg); + break; + } } } lock.unlock(); @@ -244,28 +270,30 @@ else if (queue == -1) reportException(e); } } - public void draw(Graphics graphics, LocalTestRendererListener listner, boolean isPre) + public void draw(Graphics graphics, LocalTestRendererListener listner, TargetQueue target) { ArrayList messages; lock.lock(); - if (isPre) - { - messages = lastMessagesPre; - } - else if (!isPre) - { - messages = lastMessagesPost; - } - else - { - lock.unlock(); - return; - } + switch (target) + { + case PRE: + messages = lastMessagesPre; + break; + case POST: + messages = lastMessagesPost; + break; + case ABS: + messages = lastMessagesAbs; + break; + default: + lock.unlock(); + return; + } Color oldColor = graphics.getColor(); for (int i = 0; i < messages.size(); i++) { - messages.get(i).draw(graphics, listner); + messages.get(i).draw(graphics, listner, target.equals(TargetQueue.ABS)); } lock.unlock(); graphics.setColor(oldColor); @@ -392,14 +420,17 @@ public void beforeDrawScene(Graphics graphics, World world, Game game, int canva reportException(e); } } - listener.draw(graphics, this, true); + listener.draw(graphics, this, TargetQueue.PRE); } } public void afterDrawScene(Graphics graphics, World world, Game game, int canvasWidth, int canvasHeight, double left, double top, double width, double height) { updateFields(graphics, world, game, canvasWidth, canvasHeight, left, top, width, height); - if (listener != null) listener.draw(graphics, this, false); + if (listener != null) { + listener.draw(graphics, this, TargetQueue.POST); + listener.draw(graphics, this, TargetQueue.ABS); + } } private void updateFields(Graphics graphics, World world, Game game, int canvasWidth, int canvasHeight, @@ -417,30 +448,30 @@ private void updateFields(Graphics graphics, World world, Game game, int canvasW this.height = height; } - private void drawLine(double x1, double y1, double x2, double y2) { - Point2I lineBegin = toCanvasPosition(x1, y1); - Point2I lineEnd = toCanvasPosition(x2, y2); + private void drawLine(double x1, double y1, double x2, double y2, boolean useAbsCoords) { + Point2I lineBegin = useAbsCoords ? new Point2I(x1, y1) : toCanvasPosition(x1, y1); + Point2I lineEnd = useAbsCoords ? new Point2I(x2, y2) : toCanvasPosition(x2, y2); graphics.drawLine(lineBegin.getX(), lineBegin.getY(), lineEnd.getX(), lineEnd.getY()); } - private void fillCircle(double centerX, double centerY, double radius) { - Point2I topLeft = toCanvasPosition(centerX - radius, centerY - radius); - Point2I size = toCanvasOffset(2.0D * radius, 2.0D * radius); + private void fillCircle(double centerX, double centerY, double radius, boolean useAbsCoords) { + Point2I topLeft = useAbsCoords ? new Point2I(centerX - radius, centerY - radius) : toCanvasPosition(centerX - radius, centerY - radius); + Point2I size = useAbsCoords ? new Point2I(2.0D * radius, 2.0D * radius) : toCanvasOffset(2.0D * radius, 2.0D * radius); graphics.fillOval(topLeft.getX(), topLeft.getY(), size.getX(), size.getY()); } - private void drawCircle(double centerX, double centerY, double radius) { - Point2I topLeft = toCanvasPosition(centerX - radius, centerY - radius); - Point2I size = toCanvasOffset(2.0D * radius, 2.0D * radius); + private void drawCircle(double centerX, double centerY, double radius, boolean useAbsCoords) { + Point2I topLeft = useAbsCoords ? new Point2I(centerX - radius, centerY - radius) : toCanvasPosition(centerX - radius, centerY - radius); + Point2I size = useAbsCoords ? new Point2I(2.0D * radius, 2.0D * radius) : toCanvasOffset(2.0D * radius, 2.0D * radius); graphics.drawOval(topLeft.getX(), topLeft.getY(), size.getX(), size.getY()); } - private void showText(double X, double Y, String text) + private void showText(double X, double Y, String text, boolean useAbsCoords) { - Point2I position = toCanvasPosition(X, Y); + Point2I position = useAbsCoords ? new Point2I(X, Y) : toCanvasPosition(X, Y); Font oldFont = graphics.getFont(); if (textFont == null) { @@ -465,32 +496,32 @@ private void drawArc(double centerX, double centerY, double radius, int startAng graphics.drawArc(topLeft.getX(), topLeft.getY(), size.getX(), size.getY(), startAngle, arcAngle); } - private void fillRect(double left, double top, double width, double height) { - Point2I topLeft = toCanvasPosition(left, top); - Point2I size = toCanvasOffset(width, height); + private void fillRect(double left, double top, double width, double height, boolean useAbsCoords) { + Point2I topLeft = useAbsCoords ? new Point2I(left, top) : toCanvasPosition(left, top); + Point2I size = useAbsCoords ? new Point2I(width, height) : toCanvasOffset(width, height); graphics.fillRect(topLeft.getX(), topLeft.getY(), size.getX(), size.getY()); } - private void drawRect(double left, double top, double width, double height) { - Point2I topLeft = toCanvasPosition(left, top); - Point2I size = toCanvasOffset(width, height); + private void drawRect(double left, double top, double width, double height, boolean useAbsCoords) { + Point2I topLeft = useAbsCoords ? new Point2I(left, top) : toCanvasPosition(left, top); + Point2I size = useAbsCoords ? new Point2I(width, height) : toCanvasOffset(width, height); graphics.drawRect(topLeft.getX(), topLeft.getY(), size.getX(), size.getY()); } - private void drawPolygon(Point2D... points) { + private void drawPolygon(boolean useAbsCoords, Point2D... points) { int pointCount = points.length; for (int pointIndex = 1; pointIndex < pointCount; ++pointIndex) { Point2D pointA = points[pointIndex]; Point2D pointB = points[pointIndex - 1]; - drawLine(pointA.getX(), pointA.getY(), pointB.getX(), pointB.getY()); + drawLine(pointA.getX(), pointA.getY(), pointB.getX(), pointB.getY(), useAbsCoords); } Point2D pointA = points[0]; Point2D pointB = points[pointCount - 1]; - drawLine(pointA.getX(), pointA.getY(), pointB.getX(), pointB.getY()); + drawLine(pointA.getX(), pointA.getY(), pointB.getX(), pointB.getY(), useAbsCoords); } private Point2I toCanvasOffset(double x, double y) {