Skip to content

Commit

Permalink
Added ability to position visual stuff as "absolute", i.e. in coordin…
Browse files Browse the repository at this point in the history
…ates equal to screen pixels

Currently only Python client supports this
  • Loading branch information
JustAMan committed Nov 10, 2016
1 parent 2db4660 commit d9523e9
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 66 deletions.
3 changes: 3 additions & 0 deletions clients/python/MyStrategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
37 changes: 32 additions & 5 deletions clients/python/debug_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')

Expand All @@ -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()
Expand All @@ -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
Expand All @@ -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
Expand Down
153 changes: 92 additions & 61 deletions local-runner/plugins/LocalTestRendererListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<Message> messagesPre, messagesPost, lastMessagesPre, lastMessagesPost;
private int queue;
private ArrayList<Message> messagesPre, messagesPost, messagesAbs, lastMessagesPre, lastMessagesPost, lastMessagesAbs;
private TargetQueue queue;
private Lock lock;
private OutputStream outputStream;
private OutputStreamWriter outputWriter;
Expand All @@ -136,9 +141,12 @@ public ThreadListener(int port) throws IOException
socket = new ServerSocket(port);
messagesPre = new ArrayList<Message>();
messagesPost = new ArrayList<Message>();
messagesAbs = new ArrayList<Message>();
lastMessagesPre = new ArrayList<Message>();
lastMessagesPost = new ArrayList<Message>();
queue = 0;
lastMessagesAbs = new ArrayList<Message>();

queue = TargetQueue.NONE;
lock = new ReentrantLock();
outputStream = null;
outputWriter = null;
Expand Down Expand Up @@ -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))
{
Expand All @@ -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<Message> 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
Expand All @@ -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();
Expand All @@ -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<Message> 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);
Expand Down Expand Up @@ -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,
Expand All @@ -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)
{
Expand All @@ -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) {
Expand Down

0 comments on commit d9523e9

Please sign in to comment.