View | Details | Raw Unified | Return to bug 51181
Collapse All | Expand All

(-)webapps/examples/WEB-INF/classes/websocket/snake/SnakeWebSocketServlet.java (-4 / +5 lines)
Lines 101-106 Link Here
101
                CharBuffer response = CharBuffer.wrap(message);
101
                CharBuffer response = CharBuffer.wrap(message);
102
                connection.getWsOutbound().writeTextMessage(response);
102
                connection.getWsOutbound().writeTextMessage(response);
103
            } catch (IOException ignore) {
103
            } catch (IOException ignore) {
104
                // Ignore
104
            }
105
            }
105
        }
106
        }
106
    }
107
    }
Lines 196-208 Link Here
196
        @Override
197
        @Override
197
        protected void onTextMessage(CharBuffer charBuffer) throws IOException {
198
        protected void onTextMessage(CharBuffer charBuffer) throws IOException {
198
            String message = charBuffer.toString();
199
            String message = charBuffer.toString();
199
            if ("left".equals(message)) {
200
            if ("west".equals(message)) {
200
                snake.setDirection(Direction.WEST);
201
                snake.setDirection(Direction.WEST);
201
            } else if ("up".equals(message)) {
202
            } else if ("north".equals(message)) {
202
                snake.setDirection(Direction.NORTH);
203
                snake.setDirection(Direction.NORTH);
203
            } else if ("right".equals(message)) {
204
            } else if ("east".equals(message)) {
204
                snake.setDirection(Direction.EAST);
205
                snake.setDirection(Direction.EAST);
205
            } else if ("down".equals(message)) {
206
            } else if ("south".equals(message)) {
206
                snake.setDirection(Direction.SOUTH);
207
                snake.setDirection(Direction.SOUTH);
207
            }
208
            }
208
        }
209
        }
(-)webapps/examples/websocket/snake.html (-9 / +19 lines)
Lines 67-72 Link Here
67
        Game.socket = null;
67
        Game.socket = null;
68
        Game.nextFrame = null;
68
        Game.nextFrame = null;
69
        Game.interval = null;
69
        Game.interval = null;
70
        Game.direction = 'none';
70
        Game.gridSize = 10;
71
        Game.gridSize = 10;
71
72
72
        function Snake() {
73
        function Snake() {
Lines 94-117 Link Here
94
                if (code > 36 && code < 41) {
95
                if (code > 36 && code < 41) {
95
                    switch (code) {
96
                    switch (code) {
96
                        case 37:
97
                        case 37:
97
                            Game.socket.send('left');
98
                            if (Game.direction != 'east') Game.setDirection('west');
98
                            break;
99
                            break;
99
                        case 38:
100
                        case 38:
100
                            Game.socket.send('up');
101
                            if (Game.direction != 'south') Game.setDirection('north');
101
                            break;
102
                            break;
102
                        case 39:
103
                        case 39:
103
                            Game.socket.send('right');
104
                            if (Game.direction != 'west') Game.setDirection('east');
104
                            break;
105
                            break;
105
                        case 40:
106
                        case 40:
106
                            Game.socket.send('down');
107
                            if (Game.direction != 'north') Game.setDirection('south');
107
                            break;
108
                            break;
108
                    }
109
                    }
109
                    Console.log('Sent: keyCode ' + code);
110
                }
110
                }
111
            }, false);
111
            }, false);
112
            Game.connect('ws://' + window.location.host + '/examples/websocket/snake');
112
            Game.connect('ws://' + window.location.host + '/examples/websocket/snake');
113
        };
113
        };
114
114
115
        Game.setDirection  = function(direction) {
116
            Game.direction = direction;
117
            Game.socket.send(direction);
118
            Console.log('Sent: Direction ' + direction);
119
        };
120
115
        Game.startGameLoop = function() {
121
        Game.startGameLoop = function() {
116
            if (window.webkitRequestAnimationFrame) {
122
            if (window.webkitRequestAnimationFrame) {
117
                Game.nextFrame = function () {
123
                Game.nextFrame = function () {
Lines 156-162 Link Here
156
162
157
        Game.removeSnake = function(id) {
163
        Game.removeSnake = function(id) {
158
            Game.entities[id] = null;
164
            Game.entities[id] = null;
159
            delete Game.entities[id]; // force GC
165
            // Force GC.
166
            delete Game.entities[id];
160
        };
167
        };
161
168
162
        Game.run = (function() {
169
        Game.run = (function() {
Lines 184-195 Link Here
184
            }
191
            }
185
192
186
            Game.socket.onopen = function () {
193
            Game.socket.onopen = function () {
187
                // Socket initialised.. start the game loop
194
                // Socket open.. start the game loop.
188
                Console.log('Info: WebSocket connection opened.');
195
                Console.log('Info: WebSocket connection opened.');
189
                Console.log('Info: Press an arrow key to begin.');
196
                Console.log('Info: Press an arrow key to begin.');
190
                Game.startGameLoop();
197
                Game.startGameLoop();
191
                setInterval(function() {
198
                setInterval(function() {
192
                    Game.socket.send('ping'); // prevent server read timeout
199
                    // Prevent server read timeout.
200
                    Game.socket.send('ping');
193
                }, 5000);
201
                }, 5000);
194
            };
202
            };
195
203
Lines 199-205 Link Here
199
            };
207
            };
200
208
201
            Game.socket.onmessage = function (message) {
209
            Game.socket.onmessage = function (message) {
202
                var packet = eval('(' + message.data + ')'); // Consider using json lib to parse data.
210
                // _Potential_ security hole, consider using json lib to parse data in production.
211
                var packet = eval('(' + message.data + ')');
203
                switch (packet.type) {
212
                switch (packet.type) {
204
                    case 'update':
213
                    case 'update':
205
                        for (var i = 0; i < packet.data.length; i++) {
214
                        for (var i = 0; i < packet.data.length; i++) {
Lines 216-221 Link Here
216
                        break;
225
                        break;
217
                    case 'dead':
226
                    case 'dead':
218
                        Console.log('Info: Your snake is dead, bad luck!');
227
                        Console.log('Info: Your snake is dead, bad luck!');
228
                        Game.direction = 'none';
219
                        break;
229
                        break;
220
                    case 'kill':
230
                    case 'kill':
221
                        Console.log('Info: Head shot!');
231
                        Console.log('Info: Head shot!');
(-)webapps/examples/WEB-INF/classes/websocket/snake/Snake.java (-46 / +38 lines)
Lines 16-39 Link Here
16
 */
16
 */
17
package websocket.snake;
17
package websocket.snake;
18
18
19
import org.apache.catalina.websocket.WsOutbound;
20
19
import java.io.IOException;
21
import java.io.IOException;
20
import java.nio.CharBuffer;
22
import java.nio.CharBuffer;
21
import java.util.ArrayDeque;
23
import java.util.ArrayDeque;
22
import java.util.Collection;
24
import java.util.Collection;
23
import java.util.Deque;
25
import java.util.Deque;
24
import java.util.Iterator;
25
26
26
import org.apache.catalina.websocket.WsOutbound;
27
28
public class Snake {
27
public class Snake {
29
28
30
    private static final int DEFAULT_LENGTH = 6;
29
    private static final int DEFAULT_LENGTH = 5;
31
30
32
    private final int id;
31
    private final int id;
33
    private final WsOutbound outbound;
32
    private final WsOutbound outbound;
34
33
35
    private Direction direction;
34
    private Direction direction;
36
    private Deque<Location> locations = new ArrayDeque<Location>();
35
    private int length = DEFAULT_LENGTH;
36
    private Location head;
37
    private Deque<Location> tail = new ArrayDeque<Location>();
37
    private String hexColor;
38
    private String hexColor;
38
39
39
    public Snake(int id, WsOutbound outbound) {
40
    public Snake(int id, WsOutbound outbound) {
Lines 45-58 Link Here
45
46
46
    private void resetState() {
47
    private void resetState() {
47
        this.direction = Direction.NONE;
48
        this.direction = Direction.NONE;
48
        this.locations.clear();
49
        this.head = SnakeWebSocketServlet.getRandomLocation();
49
        Location startLocation = SnakeWebSocketServlet.getRandomLocation();
50
        this.tail.clear();
50
        for (int i = 0; i < DEFAULT_LENGTH; i++) {
51
        this.length = DEFAULT_LENGTH;
51
            locations.add(startLocation);
52
        }
52
    }
53
    }
54
53
55
    private void kill() {
54
    private synchronized void kill() {
56
        resetState();
55
        resetState();
57
        try {
56
        try {
58
            CharBuffer response = CharBuffer.wrap("{'type': 'dead'}");
57
            CharBuffer response = CharBuffer.wrap("{'type': 'dead'}");
Lines 62-69 Link Here
62
        }
61
        }
63
    }
62
    }
64
63
65
    private void reward() {
64
    private synchronized void reward() {
66
        grow();
65
        length++;
67
        try {
66
        try {
68
            CharBuffer response = CharBuffer.wrap("{'type': 'kill'}");
67
            CharBuffer response = CharBuffer.wrap("{'type': 'kill'}");
69
            outbound.writeTextMessage(response);
68
            outbound.writeTextMessage(response);
Lines 73-80 Link Here
73
    }
72
    }
74
73
75
    public synchronized void update(Collection<Snake> snakes) {
74
    public synchronized void update(Collection<Snake> snakes) {
76
        Location firstLocation = locations.getFirst();
75
        Location nextLocation = head.getAdjacentLocation(direction);
77
        Location nextLocation = firstLocation.getAdjacentLocation(direction);
78
        if (nextLocation.x >= SnakeWebSocketServlet.PLAYFIELD_WIDTH) {
76
        if (nextLocation.x >= SnakeWebSocketServlet.PLAYFIELD_WIDTH) {
79
            nextLocation.x = 0;
77
            nextLocation.x = 0;
80
        }
78
        }
Lines 87-129 Link Here
87
        if (nextLocation.y < 0) {
85
        if (nextLocation.y < 0) {
88
            nextLocation.y = SnakeWebSocketServlet.PLAYFIELD_HEIGHT;
86
            nextLocation.y = SnakeWebSocketServlet.PLAYFIELD_HEIGHT;
89
        }
87
        }
90
        locations.addFirst(nextLocation);
88
        if (direction != Direction.NONE) {
91
        locations.removeLast();
89
            tail.addFirst(head);
90
            if (tail.size() > length) {
91
                tail.removeLast();
92
            }
93
            head = nextLocation;
94
        }
92
95
93
        for (Snake snake : snakes) {
96
        for (Snake snake : snakes) {
94
            if (snake.getId() != getId() &&
97
            if (snake.getTail().contains(head)) {
95
                    colliding(snake.getHeadLocation())) {
98
                kill();
96
                snake.kill();
99
                if (id != snake.id) {
97
                reward();
100
                    snake.reward();
98
            }
101
                }
99
        }
102
            }
100
    }
103
        }
101
102
    private void grow() {
103
        Location lastLocation = locations.getLast();
104
        Location newLocation = new Location(lastLocation.x, lastLocation.y);
105
        locations.add(newLocation);
106
    }
104
    }
107
105
108
    private boolean colliding(Location location) {
106
    public synchronized Collection<Location> getTail() {
109
        return direction != Direction.NONE && locations.contains(location);
107
        return tail;
110
    }
108
    }
111
109
112
    public void setDirection(Direction direction) {
110
    public synchronized void setDirection(Direction direction) {
113
        this.direction = direction;
111
        this.direction = direction;
114
    }
112
    }
115
113
116
    public synchronized String getLocationsJson() {
114
    public synchronized String getLocationsJson() {
117
        StringBuilder sb = new StringBuilder();
115
        StringBuilder sb = new StringBuilder();
118
        for (Iterator<Location> iterator = locations.iterator();
116
        sb.append(String.format("{x: %d, y: %d}",
119
                iterator.hasNext();) {
120
            Location location = iterator.next();
121
            sb.append(String.format("{x: %d, y: %d}",
122
                    Integer.valueOf(location.x), Integer.valueOf(location.y)));
117
                Integer.valueOf(head.x), Integer.valueOf(head.y)));
123
            if (iterator.hasNext()) {
118
        for (Location location : tail) {
124
                sb.append(',');
119
            sb.append(',');
120
            sb.append(String.format("{x: %d, y: %d}",
121
                    Integer.valueOf(location.x), Integer.valueOf(location.y)));
125
            }
122
        }
126
        }
127
        return String.format("{'id':%d,'body':[%s]}",
123
        return String.format("{'id':%d,'body':[%s]}",
128
                Integer.valueOf(id), sb.toString());
124
                Integer.valueOf(id), sb.toString());
129
    }
125
    }
Lines 134-142 Link Here
134
130
135
    public String getHexColor() {
131
    public String getHexColor() {
136
        return hexColor;
132
        return hexColor;
137
    }
138
139
    public synchronized Location getHeadLocation() {
140
        return locations.getFirst();
141
    }
133
    }
142
}
134
}

Return to bug 51181