save/load buffers and client-pointer and more optimisation
This commit is contained in:
parent
fb9436c47e
commit
7f195ccdc4
5 changed files with 197 additions and 62 deletions
25
pixelwar/src/de/paws/pixelwar/Drawable.java
Normal file
25
pixelwar/src/de/paws/pixelwar/Drawable.java
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
package de.paws.pixelwar;
|
||||||
|
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
|
||||||
|
public abstract class Drawable {
|
||||||
|
|
||||||
|
private boolean alive = true;
|
||||||
|
|
||||||
|
public final boolean isAlive() {
|
||||||
|
return alive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setAlive(final boolean state) {
|
||||||
|
alive = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick(final long dt) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void draw(final Graphics2D g);
|
||||||
|
|
||||||
|
}
|
||||||
46
pixelwar/src/de/paws/pixelwar/Label.java
Normal file
46
pixelwar/src/de/paws/pixelwar/Label.java
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
package de.paws.pixelwar;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
|
||||||
|
public class Label extends Drawable {
|
||||||
|
|
||||||
|
public static boolean show = true;
|
||||||
|
|
||||||
|
float x = 0;
|
||||||
|
float y = 0;
|
||||||
|
int x2 = 0;
|
||||||
|
int y2 = 0;
|
||||||
|
String text = "";
|
||||||
|
|
||||||
|
public String getText() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setText(final String text) {
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPos(final int x, final int y) {
|
||||||
|
x2 = x;
|
||||||
|
y2 = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick(final long dt) {
|
||||||
|
x += ((x2 - x) * dt * 0.0001);
|
||||||
|
y += ((y2 - y) * dt * 0.0001);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(final Graphics2D g) {
|
||||||
|
if (!show) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
g.setColor(Color.WHITE);
|
||||||
|
g.drawString(text, (int) x, (int) y);
|
||||||
|
g.drawLine((int) x, (int) y, x2, y2);
|
||||||
|
g.drawOval(x2 - 5, y2 - 5, 10, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -11,20 +11,28 @@ import java.awt.event.ComponentEvent;
|
||||||
import java.awt.event.ComponentListener;
|
import java.awt.event.ComponentListener;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.awt.event.KeyListener;
|
import java.awt.event.KeyListener;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.awt.event.MouseMotionListener;
|
||||||
import java.awt.image.BufferStrategy;
|
import java.awt.image.BufferStrategy;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
|
|
||||||
public class NetCanvas implements ComponentListener, KeyListener {
|
public class NetCanvas implements ComponentListener, KeyListener,
|
||||||
private volatile BufferedImage drawBuffer;
|
MouseMotionListener {
|
||||||
private volatile BufferedImage overlayBuffer;
|
private volatile BufferedImage pxBuffer;
|
||||||
private volatile BufferedImage paintBuffer;
|
private volatile BufferStrategy strategy;
|
||||||
|
|
||||||
private BufferStrategy strategy;
|
|
||||||
private final Thread refresher;
|
private final Thread refresher;
|
||||||
private final JFrame frame;
|
private final JFrame frame;
|
||||||
private final Canvas canvas;
|
private final Canvas canvas;
|
||||||
|
private final List<Drawable> drawables = new ArrayList<>();
|
||||||
|
private long lastDraw;
|
||||||
|
|
||||||
public NetCanvas() {
|
public NetCanvas() {
|
||||||
frame = new JFrame();
|
frame = new JFrame();
|
||||||
|
|
@ -33,6 +41,7 @@ public class NetCanvas implements ComponentListener, KeyListener {
|
||||||
|
|
||||||
frame.addComponentListener(this);
|
frame.addComponentListener(this);
|
||||||
canvas.addKeyListener(this);
|
canvas.addKeyListener(this);
|
||||||
|
canvas.addMouseMotionListener(this);
|
||||||
|
|
||||||
canvas.setSize(800, 600);
|
canvas.setSize(800, 600);
|
||||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
|
@ -44,20 +53,36 @@ public class NetCanvas implements ComponentListener, KeyListener {
|
||||||
frame.pack();
|
frame.pack();
|
||||||
frame.setVisible(true);
|
frame.setVisible(true);
|
||||||
|
|
||||||
|
canvas.createBufferStrategy(2);
|
||||||
|
strategy = canvas.getBufferStrategy();
|
||||||
|
|
||||||
refresher = new Thread(new Runnable() {
|
refresher = new Thread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
lastDraw = System.currentTimeMillis() - 1;
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
draw();
|
final long d1 = System.currentTimeMillis();
|
||||||
Thread.sleep(1000 / 30);
|
draw(d1 - lastDraw);
|
||||||
|
final long d2 = System.currentTimeMillis();
|
||||||
|
lastDraw = d1;
|
||||||
|
Thread.sleep(Math.max(1, (1000 / 30) - (d2 - d1)));
|
||||||
}
|
}
|
||||||
} catch (final InterruptedException e) {
|
} catch (final InterruptedException e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
refresher.start();
|
refresher.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveAs(final File file) throws IOException {
|
||||||
|
ImageIO.write(pxBuffer, "png", file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadFrom(final File file) throws IOException {
|
||||||
|
final BufferedImage img = ImageIO.read(file);
|
||||||
|
resizeBuffer(img.getWidth(), img.getHeight());
|
||||||
|
blit(img, pxBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void blit(final BufferedImage source, final BufferedImage target) {
|
private void blit(final BufferedImage source, final BufferedImage target) {
|
||||||
|
|
@ -70,9 +95,9 @@ public class NetCanvas implements ComponentListener, KeyListener {
|
||||||
BufferedImage newBuffer;
|
BufferedImage newBuffer;
|
||||||
int mw = w, mh = h;
|
int mw = w, mh = h;
|
||||||
|
|
||||||
if (drawBuffer != null) {
|
if (pxBuffer != null) {
|
||||||
mw = Math.max(w, drawBuffer.getWidth());
|
mw = Math.max(w, pxBuffer.getWidth());
|
||||||
mh = Math.max(h, drawBuffer.getHeight());
|
mh = Math.max(h, pxBuffer.getHeight());
|
||||||
if (mw > w && mh > h) {
|
if (mw > w && mh > h) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -80,51 +105,50 @@ public class NetCanvas implements ComponentListener, KeyListener {
|
||||||
|
|
||||||
newBuffer = frame.getGraphicsConfiguration().createCompatibleImage(w,
|
newBuffer = frame.getGraphicsConfiguration().createCompatibleImage(w,
|
||||||
h, Transparency.OPAQUE);
|
h, Transparency.OPAQUE);
|
||||||
if (drawBuffer != null) {
|
if (pxBuffer != null) {
|
||||||
blit(drawBuffer, newBuffer);
|
blit(pxBuffer, newBuffer);
|
||||||
}
|
}
|
||||||
drawBuffer = newBuffer;
|
pxBuffer = newBuffer;
|
||||||
|
|
||||||
overlayBuffer = frame.getGraphicsConfiguration().createCompatibleImage(
|
frame.getGraphicsConfiguration().createCompatibleImage(w, h,
|
||||||
w, h, Transparency.TRANSLUCENT);
|
Transparency.OPAQUE);
|
||||||
|
|
||||||
paintBuffer = frame.getGraphicsConfiguration().createCompatibleImage(w,
|
|
||||||
h, Transparency.OPAQUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawOverlay() {
|
private void drawOverlay(final Graphics2D g, final long dt) {
|
||||||
final Graphics2D g = overlayBuffer.createGraphics();
|
|
||||||
g.setComposite(AlphaComposite.Clear);
|
|
||||||
g.fillRect(0, 0, overlayBuffer.getWidth(), overlayBuffer.getHeight());
|
|
||||||
g.setComposite(AlphaComposite.SrcOver);
|
g.setComposite(AlphaComposite.SrcOver);
|
||||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
|
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
|
||||||
RenderingHints.VALUE_ANTIALIAS_ON);
|
RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
g.drawString(String.format("Pixelflut"), 2, 10);
|
g.drawString(String.format("Pixelflut FPS:%.2f", 1000.0 / dt), 2, 10);
|
||||||
g.dispose();
|
|
||||||
|
synchronized (drawables) {
|
||||||
|
final Iterator<Drawable> i = drawables.iterator();
|
||||||
|
while (i.hasNext()) {
|
||||||
|
final Drawable d = i.next();
|
||||||
|
if (d.isAlive()) {
|
||||||
|
d.tick(dt);
|
||||||
|
d.draw(g);
|
||||||
|
} else {
|
||||||
|
d.dispose();
|
||||||
|
i.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized public void draw() {
|
synchronized public void draw(final long dt) {
|
||||||
if (!frame.isVisible()) {
|
if (!frame.isVisible()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
drawOverlay();
|
final Graphics2D g = (Graphics2D) strategy.getDrawGraphics();
|
||||||
// Prepare composite buffer
|
g.drawImage(pxBuffer, 0, 0, null);
|
||||||
final Graphics2D g = paintBuffer.createGraphics();
|
drawOverlay(g, dt);
|
||||||
g.drawImage(drawBuffer, 0, 0, null);
|
|
||||||
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
|
|
||||||
g.drawImage(overlayBuffer, 0, 0, null);
|
|
||||||
g.dispose();
|
g.dispose();
|
||||||
|
|
||||||
// Blit into double buffer
|
|
||||||
final Graphics g2 = strategy.getDrawGraphics();
|
|
||||||
g2.drawImage(paintBuffer, 0, 0, null);
|
|
||||||
g2.dispose();
|
|
||||||
strategy.show();
|
strategy.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPixel(final int x, final int y, final int argb) {
|
public void setPixel(final int x, final int y, final int argb) {
|
||||||
// Below this values 8bit color channels are nulled.
|
// Below this values 8bit color channels are nulled.
|
||||||
final BufferedImage img = drawBuffer;
|
final BufferedImage img = pxBuffer;
|
||||||
|
|
||||||
if (x >= 0 && x < img.getWidth() && y >= 0 && y < img.getHeight()) {
|
if (x >= 0 && x < img.getWidth() && y >= 0 && y < img.getHeight()) {
|
||||||
final int alpha = (argb >>> 24) % 256;
|
final int alpha = (argb >>> 24) % 256;
|
||||||
|
|
@ -157,7 +181,7 @@ public class NetCanvas implements ComponentListener, KeyListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPixel(final int x, final int y) {
|
public int getPixel(final int x, final int y) {
|
||||||
final BufferedImage img = drawBuffer;
|
final BufferedImage img = pxBuffer;
|
||||||
if (x >= 0 && x < img.getWidth() && y >= 0 && y < img.getHeight()) {
|
if (x >= 0 && x < img.getWidth() && y >= 0 && y < img.getHeight()) {
|
||||||
return img.getRGB(x, y) & 0x00ffffff;
|
return img.getRGB(x, y) & 0x00ffffff;
|
||||||
}
|
}
|
||||||
|
|
@ -165,23 +189,31 @@ public class NetCanvas implements ComponentListener, KeyListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getWidth() {
|
public int getWidth() {
|
||||||
return drawBuffer.getWidth();
|
return pxBuffer.getWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getHeight() {
|
public int getHeight() {
|
||||||
return drawBuffer.getHeight();
|
return pxBuffer.getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void keyReleased(final KeyEvent e) {
|
public void keyReleased(final KeyEvent e) {
|
||||||
if (e.getKeyChar() == 'c') {
|
if (e.getKeyChar() == 'c') {
|
||||||
final Graphics g = drawBuffer.getGraphics();
|
final Graphics g = pxBuffer.getGraphics();
|
||||||
g.setColor(Color.BLACK);
|
g.setColor(Color.BLACK);
|
||||||
g.fillRect(0, 0, drawBuffer.getWidth(), drawBuffer.getHeight());
|
g.fillRect(0, 0, pxBuffer.getWidth(), pxBuffer.getHeight());
|
||||||
g.dispose();
|
g.dispose();
|
||||||
} else if (e.getKeyChar() == 'q'
|
} else if (e.getKeyChar() == 'q'
|
||||||
|| e.getKeyCode() == KeyEvent.VK_ESCAPE) {
|
|| e.getKeyCode() == KeyEvent.VK_ESCAPE) {
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
|
} else if (e.getKeyChar() == 'l') {
|
||||||
|
Label.show = !Label.show;
|
||||||
|
} else if (e.getKeyChar() == 's') {
|
||||||
|
try {
|
||||||
|
saveAs(new File("/tmp/canvas.png"));
|
||||||
|
} catch (final IOException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -212,4 +244,26 @@ public class NetCanvas implements ComponentListener, KeyListener {
|
||||||
public void componentHidden(final ComponentEvent e) {
|
public void componentHidden(final ComponentEvent e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseDragged(final MouseEvent e) {
|
||||||
|
// System.err.println(e.getPoint());
|
||||||
|
// setPixel(e.getX(), e.getY(), 0xffffffff);
|
||||||
|
final Graphics2D g = (Graphics2D) pxBuffer.getGraphics();
|
||||||
|
g.setColor(Color.MAGENTA);
|
||||||
|
g.fillOval(e.getX() - 50, e.getY() - 50, 100, 100);
|
||||||
|
g.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseMoved(final MouseEvent e) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addDrawable(final Label label) {
|
||||||
|
synchronized (drawables) {
|
||||||
|
drawables.add(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package de.paws.pixelwar;
|
||||||
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.SimpleChannelInboundHandler;
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
import io.netty.handler.traffic.TrafficCounter;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
@ -24,14 +23,10 @@ public class PixelClientHandler extends SimpleChannelInboundHandler<String> {
|
||||||
private final Set<String> subscriptions = new HashSet<>();
|
private final Set<String> subscriptions = new HashSet<>();
|
||||||
private final Map<String, CommandHandler> handlers = new HashMap<>();
|
private final Map<String, CommandHandler> handlers = new HashMap<>();
|
||||||
|
|
||||||
private long connectedTime;
|
private Label label;
|
||||||
private long pixelCount = 0;
|
|
||||||
private long missedMessages = 0;
|
|
||||||
|
|
||||||
public PixelClientHandler(final NetCanvas canvas) {
|
public PixelClientHandler(final NetCanvas canvas) {
|
||||||
this.canvas = canvas;
|
this.canvas = canvas;
|
||||||
final TrafficCounter tc = new TrafficCounter(null, null, null,
|
|
||||||
connectedTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void installHandler(final String command,
|
public void installHandler(final String command,
|
||||||
|
|
@ -42,7 +37,9 @@ public class PixelClientHandler extends SimpleChannelInboundHandler<String> {
|
||||||
@Override
|
@Override
|
||||||
public void channelActive(final ChannelHandlerContext ctx) throws Exception {
|
public void channelActive(final ChannelHandlerContext ctx) throws Exception {
|
||||||
super.channelActive(ctx);
|
super.channelActive(ctx);
|
||||||
connectedTime = System.currentTimeMillis();
|
label = new Label();
|
||||||
|
label.setText(ctx.channel().remoteAddress().toString());
|
||||||
|
canvas.addDrawable(label);
|
||||||
channelContext = ctx;
|
channelContext = ctx;
|
||||||
synchronized (clients) {
|
synchronized (clients) {
|
||||||
clients.add(this);
|
clients.add(this);
|
||||||
|
|
@ -53,17 +50,17 @@ public class PixelClientHandler extends SimpleChannelInboundHandler<String> {
|
||||||
public void channelInactive(final ChannelHandlerContext ctx)
|
public void channelInactive(final ChannelHandlerContext ctx)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
super.channelActive(ctx);
|
super.channelActive(ctx);
|
||||||
final long passed = System.currentTimeMillis() - connectedTime;
|
|
||||||
synchronized (clients) {
|
synchronized (clients) {
|
||||||
clients.remove(this);
|
clients.remove(this);
|
||||||
}
|
}
|
||||||
|
label.setAlive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeIfPossible(final String str) {
|
public void writeIfPossible(final String str) {
|
||||||
if (channelContext.channel().isWritable()) {
|
if (channelContext.channel().isWritable()) {
|
||||||
channelContext.write(str + "\n");
|
channelContext.write(str + "\n");
|
||||||
|
channelContext.flush();
|
||||||
} else {
|
} else {
|
||||||
missedMessages++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -145,7 +142,7 @@ public class PixelClientHandler extends SimpleChannelInboundHandler<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handle_PUB(final ChannelHandlerContext ctx, final String data) {
|
private void handle_PUB(final ChannelHandlerContext ctx, final String data) {
|
||||||
final String[] parts = data.split(" ", 1);
|
final String[] parts = data.split(" ", 2);
|
||||||
if (parts.length != 2) {
|
if (parts.length != 2) {
|
||||||
error("Usage: PUB <channel> <message>");
|
error("Usage: PUB <channel> <message>");
|
||||||
return;
|
return;
|
||||||
|
|
@ -155,11 +152,9 @@ public class PixelClientHandler extends SimpleChannelInboundHandler<String> {
|
||||||
final String message = "PUB " + channel + " " + parts[1].trim();
|
final String message = "PUB " + channel + " " + parts[1].trim();
|
||||||
|
|
||||||
for (final PixelClientHandler c : clients) {
|
for (final PixelClientHandler c : clients) {
|
||||||
if (c != this) {
|
|
||||||
c.writeChannel(channel, message);
|
c.writeChannel(channel, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void handle_SIZE(final ChannelHandlerContext ctx, final String data) {
|
private void handle_SIZE(final ChannelHandlerContext ctx, final String data) {
|
||||||
if (data.length() > 0) {
|
if (data.length() > 0) {
|
||||||
|
|
@ -172,7 +167,6 @@ public class PixelClientHandler extends SimpleChannelInboundHandler<String> {
|
||||||
private void handle_PX(final ChannelHandlerContext ctx, final String data) {
|
private void handle_PX(final ChannelHandlerContext ctx, final String data) {
|
||||||
final String[] args = data.split(" ");
|
final String[] args = data.split(" ");
|
||||||
try {
|
try {
|
||||||
pixelCount++;
|
|
||||||
if (args.length == 2) {
|
if (args.length == 2) {
|
||||||
final int x = Integer.parseInt(args[0]);
|
final int x = Integer.parseInt(args[0]);
|
||||||
final int y = Integer.parseInt(args[1]);
|
final int y = Integer.parseInt(args[1]);
|
||||||
|
|
@ -185,6 +179,7 @@ public class PixelClientHandler extends SimpleChannelInboundHandler<String> {
|
||||||
if (args[2].length() == 6) {
|
if (args[2].length() == 6) {
|
||||||
color += 0xff000000;
|
color += 0xff000000;
|
||||||
}
|
}
|
||||||
|
label.setPos(x, y);
|
||||||
canvas.setPixel(x, y, color);
|
canvas.setPixel(x, y, color);
|
||||||
} else {
|
} else {
|
||||||
error("Usage: PX x y [rrggbb[aa]]");
|
error("Usage: PX x y [rrggbb[aa]]");
|
||||||
|
|
|
||||||
|
|
@ -17,17 +17,26 @@ import io.netty.handler.codec.string.StringEncoder;
|
||||||
import io.netty.handler.logging.LogLevel;
|
import io.netty.handler.logging.LogLevel;
|
||||||
import io.netty.handler.logging.LoggingHandler;
|
import io.netty.handler.logging.LoggingHandler;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
public class PixelServer extends ChannelHandlerAdapter {
|
public class PixelServer extends ChannelHandlerAdapter {
|
||||||
|
|
||||||
private final NetCanvas canvas;
|
private final NetCanvas canvas;
|
||||||
private final int port;
|
private final int port;
|
||||||
|
private final File savefile = new File("/tmp/canvas.png");
|
||||||
|
|
||||||
public PixelServer(final int port) {
|
public PixelServer(final int port) throws IOException {
|
||||||
this.port = port;
|
this.port = port;
|
||||||
canvas = new NetCanvas();
|
canvas = new NetCanvas();
|
||||||
|
if (savefile.exists()) {
|
||||||
|
canvas.loadFrom(savefile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() throws InterruptedException {
|
public void run() throws InterruptedException, UnknownHostException {
|
||||||
final EventLoopGroup bossGroup = new NioEventLoopGroup(1);
|
final EventLoopGroup bossGroup = new NioEventLoopGroup(1);
|
||||||
final EventLoopGroup workerGroup = new NioEventLoopGroup();
|
final EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||||
try {
|
try {
|
||||||
|
|
@ -48,14 +57,14 @@ public class PixelServer extends ChannelHandlerAdapter {
|
||||||
128, Delimiters.lineDelimiter()));
|
128, Delimiters.lineDelimiter()));
|
||||||
p.addLast("decoder", new StringDecoder());
|
p.addLast("decoder", new StringDecoder());
|
||||||
p.addLast("encoder", new StringEncoder());
|
p.addLast("encoder", new StringEncoder());
|
||||||
|
|
||||||
// and then business logic.
|
// and then business logic.
|
||||||
p.addLast("handler", new PixelClientHandler(canvas));
|
p.addLast("handler", new PixelClientHandler(canvas));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Start the server.
|
// Start the server.
|
||||||
final ChannelFuture f = b.bind(port).sync();
|
final ChannelFuture f = b.bind(
|
||||||
|
new InetSocketAddress("0.0.0.0", port)).sync();
|
||||||
|
|
||||||
// Wait until the server socket is closed.
|
// Wait until the server socket is closed.
|
||||||
f.channel().closeFuture().sync();
|
f.channel().closeFuture().sync();
|
||||||
|
|
@ -63,10 +72,16 @@ public class PixelServer extends ChannelHandlerAdapter {
|
||||||
// Shut down all event loops to terminate all threads.
|
// Shut down all event loops to terminate all threads.
|
||||||
bossGroup.shutdownGracefully();
|
bossGroup.shutdownGracefully();
|
||||||
workerGroup.shutdownGracefully();
|
workerGroup.shutdownGracefully();
|
||||||
|
try {
|
||||||
|
canvas.saveAs(savefile);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(final String[] args) throws InterruptedException {
|
public static void main(final String[] args) throws InterruptedException,
|
||||||
|
IOException {
|
||||||
new PixelServer(8080).run();
|
new PixelServer(8080).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue