├── src
├── messages
│ ├── pong.js
│ ├── eat.js
│ ├── end.js
│ ├── minimap.js
│ ├── position.js
│ ├── movement.js
│ ├── sector.js
│ ├── direction.js
│ ├── index.js
│ ├── food.js
│ ├── highscore.js
│ ├── initial.js
│ ├── leaderboard.js
│ └── snake.js
├── entities
│ ├── sector.js
│ ├── food.js
│ └── snake.js
└── utils
│ ├── math.js
│ └── message.js
├── .eslintrc.js
├── config
└── config.js
├── package.json
├── .gitignore
├── CONTRIBUTING.md
├── README.md
└── index.js
/src/messages/pong.js:
--------------------------------------------------------------------------------
1 | var message = require('../utils/message');
2 |
3 | var arr = new Uint8Array(3);
4 |
5 | message.writeInt8(2, arr, 'p'.charCodeAt(0));
6 |
7 | module.exports = arr;
8 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | 'extends': 'standard',
3 | 'plugins': [
4 | 'standard'
5 | ],
6 | 'rules': {
7 | 'semi': ['error', 'always'],
8 | 'indent': ['error', 4]
9 | }
10 | };
11 |
--------------------------------------------------------------------------------
/src/entities/sector.js:
--------------------------------------------------------------------------------
1 | module.exports = (function () {
2 | /*
3 | Section: Construction
4 | */
5 | function Sector (position, foods) {
6 | this.position = position;
7 | this.foods = foods;
8 | }
9 |
10 | return Sector;
11 | });
12 |
--------------------------------------------------------------------------------
/src/entities/food.js:
--------------------------------------------------------------------------------
1 | module.exports = (function () {
2 | /*
3 | Section: Construction
4 | */
5 | function Food (id, position, size, color) {
6 | this.id = id;
7 | this.position = position;
8 | this.size = size;
9 | this.color = color;
10 | }
11 |
12 | return Food;
13 | });
14 |
--------------------------------------------------------------------------------
/src/messages/eat.js:
--------------------------------------------------------------------------------
1 | var message = require('../utils/message');
2 |
3 | var type = 'h'.charCodeAt(0);
4 |
5 | exports.build = function (id, fam) {
6 | var arr = new Uint8Array(8);
7 | message.writeInt8(2, arr, type);
8 | message.writeInt16(3, arr, id);
9 | message.writeInt24(5, arr, fam);
10 | return arr;
11 | };
12 |
--------------------------------------------------------------------------------
/src/messages/end.js:
--------------------------------------------------------------------------------
1 | var message = require('../utils/message');
2 |
3 | exports.build = function (endNum) {
4 | var arr = new Uint8Array(4);
5 | message.writeInt8(2, arr, 'v'.charCodeAt(0));
6 | // 0-2; 0 is normal death, 1 is new highscore of the day, 2 is unknown
7 | message.writeInt8(3, arr, endNum);
8 |
9 | return arr;
10 | };
11 |
12 |
--------------------------------------------------------------------------------
/src/messages/minimap.js:
--------------------------------------------------------------------------------
1 | // TODO? unused for now
2 | // var message = require('../utils/message');
3 |
4 | var type = 'u'.charCodeAt(0);
5 | var exports = module.exports;
6 |
7 | exports.build = function (foods) {
8 | var arr = new Uint8Array(16);
9 | arr.set([0, 0, type, 244, 64, 201, 96, 200, 96, 200, 112, 200, 120, 6, 188, 127]);
10 | return arr;
11 | };
12 |
--------------------------------------------------------------------------------
/src/messages/position.js:
--------------------------------------------------------------------------------
1 | var message = require('../utils/message');
2 |
3 | var type = 'g'.charCodeAt(0);
4 |
5 | exports.build = function (id, snake) {
6 | var arr = new Uint8Array(9);
7 | message.writeInt8(2, arr, type);
8 | message.writeInt16(3, arr, id);
9 | message.writeInt16(5, arr, snake.body.x);
10 | message.writeInt16(7, arr, snake.body.y);
11 | return arr;
12 | };
13 |
--------------------------------------------------------------------------------
/config/config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | port: 8080,
3 | bots: 0, // Not Implemented
4 | maxConnections: 100,
5 | highscoreName: "How to change Highscore Msg",
6 | highscoreMsg: "Set this message in the config",
7 | food: 20000,
8 | foodColours: 8,
9 | foodSize: [15, 47],
10 | foodPerSpawn: 1000, // Not Implemented
11 | gameRadius: 21600,
12 | sectorSize: 480
13 | };
14 |
--------------------------------------------------------------------------------
/src/messages/movement.js:
--------------------------------------------------------------------------------
1 | var message = require('../utils/message');
2 |
3 | var type = 'G'.charCodeAt(0);
4 |
5 | exports.build = function (id, snake) {
6 | var arr = new Uint8Array(7);
7 | message.writeInt8(2, arr, type);
8 | message.writeInt16(3, arr, id);
9 | message.writeInt8(5, arr, snake.direction.x);
10 | message.writeInt8(6, arr, snake.direction.y);
11 | return arr;
12 | };
13 |
--------------------------------------------------------------------------------
/src/messages/sector.js:
--------------------------------------------------------------------------------
1 | var message = require('../utils/message');
2 |
3 | var type = 'W'.charCodeAt(0);
4 |
5 | exports.build = function (x, y) {
6 | var arr = new Uint8Array(8);
7 | var b = 0;
8 | b += message.writeInt8(b, arr, 0);
9 | b += message.writeInt8(b, arr, 0);
10 | b += message.writeInt8(b, arr, type);
11 | b += message.writeInt8(b, arr, x);
12 | b += message.writeInt8(b, arr, y);
13 | return arr;
14 | };
15 |
--------------------------------------------------------------------------------
/src/messages/direction.js:
--------------------------------------------------------------------------------
1 | var message = require('../utils/message');
2 |
3 | var type = 'e'.charCodeAt(0);
4 |
5 | exports.build = function (id, snake) {
6 | var arr = new Uint8Array(8);
7 | message.writeInt8(2, arr, type);
8 | message.writeInt16(3, arr, id);
9 | message.writeInt8(5, arr, snake.direction.angle * 256 / (2*Math.PI));
10 | message.writeInt8(6, arr, snake.direction.angle * 256 / (2*Math.PI));
11 | message.writeInt8(7, arr, snake.speed * 18);
12 | return arr;
13 | };
14 |
--------------------------------------------------------------------------------
/src/messages/index.js:
--------------------------------------------------------------------------------
1 | exports.direction = require('./direction');
2 | exports.position = require('./position');
3 | exports.movement = require('./movement');
4 | exports.initial = require('./initial');
5 | exports.pong = require('./pong');
6 | exports.leaderboard = require('./leaderboard');
7 | exports.snake = require('./snake');
8 | exports.highscore = require('./highscore');
9 | exports.food = require('./food');
10 | exports.sector = require('./sector');
11 | exports.minimap = require('./minimap');
12 | exports.eat = require('./eat');
13 | exports.end = require('./end');
14 |
--------------------------------------------------------------------------------
/src/messages/food.js:
--------------------------------------------------------------------------------
1 | var message = require('../utils/message');
2 |
3 | var type = 'F'.charCodeAt(0);
4 |
5 | exports.build = function (foods) {
6 | var arr = new Uint8Array(3 + (6 * foods.length));
7 | message.writeInt8(2, arr, type);
8 | var i = 0;
9 | while (i < foods.length) {
10 | var food = foods[i];
11 | message.writeInt8(3 + i * 6, arr, food.color);
12 | message.writeInt16(4 + i * 6, arr, food.position.x);
13 | message.writeInt16(6 + i * 6, arr, food.position.y);
14 | message.writeInt8(8 + i * 6, arr, food.size);
15 | i++;
16 | }
17 | return arr;
18 | };
19 |
--------------------------------------------------------------------------------
/src/utils/math.js:
--------------------------------------------------------------------------------
1 | var config = require('../../config/config.js');
2 |
3 | exports.randomInt = function (min, max) {
4 | return Math.floor(Math.random() * (max - min + 1)) + min;
5 | };
6 |
7 | exports.randomSpawnPoint = function () {
8 | return {
9 | x: exports.randomInt(5000 * 5, config['gameRadius'] * 5),
10 | y: exports.randomInt(5000 * 5, config['gameRadius'] * 5)
11 | };
12 | };
13 |
14 | exports.chunk = function (arr, chunkSize) {
15 | var R, i;
16 | R = [];
17 | i = 0;
18 | while (i < arr.length) {
19 | R.push(arr.slice(i, i + chunkSize));
20 | i += chunkSize;
21 | }
22 | return R;
23 | };
24 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Slither-Server",
3 | "description": "A Server for Slither.io",
4 | "version": "0.0.5",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/RowanHarley/Slither-Server"
8 | },
9 | "dependencies": {
10 | "chalk": "^1.1.3",
11 | "object-keys": "^1.0.9",
12 | "semver": "^5.1.0",
13 | "ws": "*"
14 | },
15 | "packageDependencies": {},
16 | "scripts": {
17 | "start": "node ./index.js",
18 | "lint": "eslint ./index.js ./config/**/*.js ./src/**/*.js"
19 | },
20 | "devDependencies": {
21 | "eslint": "^2.13.1",
22 | "eslint-config-standard": "^5.3.1",
23 | "eslint-plugin-standard": "^1.3.2",
24 | "standard": "^7.1.2"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # nyc test coverage
18 | .nyc_output
19 |
20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
21 | .grunt
22 |
23 | # node-waf configuration
24 | .lock-wscript
25 |
26 | # Compiled binary addons (http://nodejs.org/api/addons.html)
27 | build/Release
28 |
29 | # Dependency directories
30 | node_modules
31 | jspm_packages
32 |
33 | # Optional npm cache directory
34 | .npm
35 |
36 | # Optional REPL history
37 | .node_repl_history
38 |
39 | # Ignored files
40 | /README.md
41 |
--------------------------------------------------------------------------------
/src/messages/highscore.js:
--------------------------------------------------------------------------------
1 | var message = require('../utils/message');
2 |
3 | var type = 'm'.charCodeAt(0);
4 |
5 | exports.build = function (text, text2) {
6 | var arr, b;
7 | arr = new Uint8Array(10 + text.length + text2.length);
8 | // console.log(Math.floor(15 * (14.516542058039644 + 0.7810754645511785 / 0.9249846824962366 - 1) - 5) / 1);
9 | b = 0;
10 | b += message.writeInt8(b, arr, 0);
11 | b += message.writeInt8(b, arr, 0);
12 | b += message.writeInt8(b, arr, type);
13 | b += message.writeInt24(b, arr, 306);
14 | b += message.writeInt24(b, arr, 0.7810754645511785 * 16777215);
15 | b += message.writeInt8(b, arr, text.length);
16 | b += message.writeString(b, arr, text);
17 | b += message.writeString(b, arr, text2);
18 | return arr;
19 | };
20 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 | Contributions are appreciated in the form of pull requests. However, to maintain code readability and maintainability, some guidelines have been set. Please do what you can to make sure your code follows the guidelines. *Your pull request will likely be rejected if it does not merge these guidelines, so please read them carefully.*
3 |
4 | ### Style
5 | * Conditional/loop statements (`if`, `for`, `while`, etc.) should always use braces, and the opening brace should be placed on the same line as the statement.
6 | * There should be a space after a conditional/loop statement and before the condition, as well as a space after the condition and before the brace. Example:
7 | ```javacript
8 | // Good
9 | if (condition) {
10 | ...
11 | }
12 |
13 | // Bad
14 | if(condition) {
15 | ...
16 | }
17 |
18 | if(condition){
19 | ...
20 | }
21 | ```
22 | ***Always make sure the project is buildable before creating a pull request***
23 |
--------------------------------------------------------------------------------
/src/messages/initial.js:
--------------------------------------------------------------------------------
1 | var message = require('../utils/message.js');
2 |
3 | var config = require('../../config/config.js');
4 |
5 | var arr = new Uint8Array(26);
6 |
7 | var b = 0;
8 |
9 | b += message.writeInt8(b, arr, 0);
10 |
11 | b += message.writeInt8(b, arr, 0);
12 |
13 | b += message.writeInt8(b, arr, 'a'.charCodeAt(0));
14 |
15 | b += message.writeInt24(b, arr, config['gameRadius']);
16 |
17 | b += message.writeInt16(b, arr, 411);
18 |
19 | b += message.writeInt16(b, arr, config['sectorSize']);
20 |
21 | b += message.writeInt16(b, arr, 144);
22 |
23 | b += message.writeInt8(b, arr, 4.8 * 10);
24 |
25 | b += message.writeInt16(b, arr, 5.39 * 100);
26 |
27 | b += message.writeInt16(b, arr, 0.4 * 100);
28 |
29 | b += message.writeInt16(b, arr, 14 * 100);
30 |
31 | b += message.writeInt16(b, arr, 0.033 * 1e3);
32 |
33 | b += message.writeInt16(b, arr, 0.028 * 1e3);
34 |
35 | b += message.writeInt16(b, arr, 0.43 * 1e3);
36 |
37 | b += message.writeInt8(b, arr, 8);
38 |
39 | module.exports = arr;
40 |
--------------------------------------------------------------------------------
/src/messages/leaderboard.js:
--------------------------------------------------------------------------------
1 | var message = require('../utils/message');
2 |
3 | var math = require('../utils/math');
4 |
5 | var type = 'l'.charCodeAt(0);
6 |
7 | exports.build = function (rank, players, top) {
8 | var arr;
9 | var length = 0;
10 | for (var i = 0, len = top.length; i < len; i++) {
11 | var player = top[i];
12 | length += player.snake.name.length;
13 | }
14 | arr = new Uint8Array((8 + length) + (top.length * 7));
15 | var b = 0;
16 | b += message.writeInt8(b, arr, 0);
17 | b += message.writeInt8(b, arr, 0);
18 | b += message.writeInt8(b, arr, type);
19 | b += message.writeInt8(b, arr, rank > 10 ? 0 : rank);
20 | b += message.writeInt16(b, arr, rank);
21 | b += message.writeInt16(b, arr, players);
22 | i = 0;
23 | while (i < top.length) {
24 | b += message.writeInt16(b, arr, top[i].snake.sct);
25 | b += message.writeInt24(b, arr, top[i].snake.fam);
26 | b += message.writeInt8(b, arr, math.randomInt(0, 8));
27 | b += message.writeInt8(b, arr, top[i].snake.name.length);
28 | b += message.writeString(b, arr, top[i].snake.name);
29 | i++;
30 | }
31 | return arr;
32 | };
33 |
--------------------------------------------------------------------------------
/src/entities/snake.js:
--------------------------------------------------------------------------------
1 | module.exports = (function () {
2 | /*
3 | Section: Construction
4 | */
5 | function Snake (id, name, body, skin) {
6 | this.id = id;
7 | this.name = name;
8 | this.body = body;
9 | this.skin = skin;
10 | this.speed = 5.79;
11 | this.head = this.body; // This is why the snake dies when it reach's half way
12 | this.D = 5.69941607541398 / 2 / Math.PI * 16777215;
13 | this.X = this.D;
14 | this.length = 10;
15 | this.sct = 2;
16 | this.fam = 0 * 16777215;
17 | this.direction = {
18 | x: 1,
19 | y: 1,
20 | angle: ((0.033 * 1e3) * 0 * this.scang * this.spang)
21 | };
22 | this.parts = [];
23 | var i = 0;
24 | while (i < 20) {
25 | this.parts.push({
26 | x: i + 1,
27 | y: i + 2
28 | });
29 | i += 2;
30 | }
31 | this.sc = Math.min(6, 1 + (this.parts.length - 2) / 106.0);
32 | this.scang = 0.13 + 0.87 * Math.pow((7 - this.sc) / 6, 2);
33 | this.spang = Math.min(this.speed / (4.8 * 10), 1);
34 | }
35 | return Snake;
36 | })();
37 |
--------------------------------------------------------------------------------
/src/messages/snake.js:
--------------------------------------------------------------------------------
1 | var message = require('../utils/message.js');
2 | var type = 's'.charCodeAt(0);
3 |
4 | exports.build = function (snake) {
5 | var nameLength = snake.name.length;
6 | var part = snake.parts.length;
7 | var partsLength = part * 2;
8 | var arr = new Uint8Array(25 + nameLength + 6 + partsLength);
9 | var b = 0;
10 | b += message.writeInt8(b, arr, 0);
11 | b += message.writeInt8(b, arr, 0);
12 | b += message.writeInt8(b, arr, type);
13 | b += message.writeInt16(b, arr, snake.id);
14 | b += message.writeInt24(b, arr, snake.D);
15 | b += message.writeInt8(b, arr, 0);
16 | b += message.writeInt24(b, arr, snake.X);
17 | b += message.writeInt16(b, arr, snake.speed * 1E3);
18 | b += message.writeInt24(b, arr, 0);
19 | b += message.writeInt8(b, arr, snake.skin);
20 | b += message.writeInt24(b, arr, snake.body.x * 5);
21 | b += message.writeInt24(b, arr, snake.body.y * 5);
22 | b += message.writeInt8(b, arr, nameLength);
23 | b += message.writeString(b, arr, snake.name);
24 | b += message.writeInt24(b, arr, snake.head.x * 5);
25 | b += message.writeInt24(b, arr, snake.head.y * 5);
26 |
27 | prevX = snake.head.x;
28 | prevY = snake.head.y;
29 |
30 | var i = 0;
31 | while (i < snake.parts.length) {
32 | thisX = snake.parts[i].x;
33 | thisY = snake.parts[i].y;
34 | b += message.writeInt8(b, arr, (thisX-prevX)*2 + 127);
35 | b += message.writeInt8(b, arr, (thisY-prevY)*2 + 127);
36 | prevX = thisX;
37 | prevY = thisY;
38 | i++;
39 | }
40 | return arr;
41 | };
42 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Slither-Server
2 |
3 | ## Table of Contents
4 |
5 | - 1. [Aim](#aim)
6 | - 2. [How to Connect](#how-to-connect)
7 | - 3. [Roadmap](#roadmap)
8 | - 4. [Beta Version's](#beta-versions)
9 | - 5. [Contributions](#contributions)
10 |
11 |
12 |
13 | ## Aim
14 |
15 | The aim of this project is to make a server for Slither using Node.JS. It's currently at v0.0.5! If you'd like to help, please read the Contributions section
16 |
17 |
18 |
19 | ## How To Connect
20 |
21 | If you are having trouble connecting, please read the [wiki page](https://github.com/RowanHarley/Slither-Server/wiki/Connecting-To-The-Server).
22 |
23 |
24 |
25 | ## Roadmap
26 |
27 | For our full roadmap, visit our [wiki page](https://github.com/RowanHarley/Slither-Server/wiki/Roadmap).
28 | Some of the features we hope to add are:
29 |
30 | - [x] Full snake movement
31 | - [ ] Bots
32 | - [ ] Commands through Console
33 | - [ ] Multiple Server Support (Meaning you can have players play on different, smaller servers)
34 | - [ ] Ability to set (and save) highscores (You currently have to set them in the code)(Coming in 0.0.6)
35 | - [ ] ...
36 |
37 | If you have any suggestions, please feel free to comment them [here](https://github.com/RowanHarley/Slither-Server/issues/1)
38 |
39 |
40 |
41 | ## Beta Version's
42 |
43 | If you wish to try out the beta versions, go to the [Releases](https://github.com/RowanHarley/Slither-Server/releases) page and download any of the pre-releases. I'd recommend using 0.0.5 for better performance and less bugs!
44 |
45 |
46 |
47 |
48 | ## Contributions
49 |
50 | I appreciate any contributions given in the form of pull request's. For more details, read [CONTRIBUTING.md](https://github.com/RowanHarley/Slither-Server/blob/master/CONTRIBUTING.md)
51 |
--------------------------------------------------------------------------------
/src/utils/message.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | writeInt24: function (offset, data, number) {
3 | var byte1, byte2, byte3;
4 | number = Math.floor(number);
5 | if (number > 16777215) {
6 | throw new Error('Int24 out of bound');
7 | }
8 | byte1 = number >> 16 & 0xFF;
9 | byte2 = number >> 8 & 0xFF;
10 | byte3 = number & 0xFF;
11 | data[offset] = byte1;
12 | data[offset + 1] = byte2;
13 | data[offset + 2] = byte3;
14 | return 3;
15 | },
16 | writeInt16: function (offset, data, number) {
17 | var byte1, byte2;
18 | number = Math.floor(number);
19 | if (number > 65535) {
20 | throw new Error('Int16 out of bound. Current number: ' + number);
21 | }
22 | byte1 = number >> 8 & 0xFF;
23 | byte2 = number & 0xFF;
24 | data[offset] = byte1;
25 | data[offset + 1] = byte2;
26 | return 2;
27 | },
28 | writeInt8: function (offset, data, number) {
29 | var byte1;
30 | number = Math.floor(number);
31 | if (number > 255) {
32 | throw new Error('Int8 out of bound. Current Number: ' + number);
33 | }
34 | byte1 = number & 0xFF;
35 | data[offset] = byte1;
36 | return 1;
37 | },
38 | writeString: function (offset, data, string) {
39 | var i;
40 | i = 0;
41 | while (i < string.length) {
42 | this.writeInt8(offset + i, data, string.charCodeAt(i));
43 | i++;
44 | }
45 | return string.length;
46 | },
47 | readInt8: function (offset, data) {
48 | return data[offset];
49 | },
50 | readInt24: function (offset, data) {
51 | var byte1, byte2, byte3, int;
52 | byte1 = data[offset];
53 | byte2 = data[offset + 1];
54 | byte3 = data[offset + 2];
55 | int = byte1 << 16 | byte2 << 8 | byte3;
56 | return int;
57 | },
58 | readString: function (offset, data, length) {
59 | var i, string;
60 | string = '';
61 | i = offset;
62 | while (i < length) {
63 | string += String.fromCharCode(data[i]);
64 | i++;
65 | }
66 | return string;
67 | }
68 | };
69 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 |
2 | /*eslint-disable no-unused-vars */ // disabled some codes are stubs
3 |
4 | var config = require('./config/config.js');
5 | // var spawn = require("./src/spawn.js");
6 | var pkg = require('./package.json');
7 | var WebSocket = require('ws').Server;
8 | var Snake = require('./src/entities/snake');
9 | var Food = require('./src/entities/food');
10 | var sector = require('./src/entities/sector');
11 | var messages = require('./src/messages');
12 | var message = require('./src/utils/message');
13 | var math = require('./src/utils/math');
14 |
15 | var loopInterval = 230;
16 | var counter = 0;
17 | var clients = [];
18 | var foods = [];
19 | var sectors = []; // Development Code
20 | var botCount = 0;
21 | var highscoreName = config["highscoreName"];
22 | var highscoreMessage = config["highscoreMsg"];
23 | var fmlts;
24 | var fpsls;
25 |
26 | console.log('[DEBUG] You are currently running on ' + pkg.version);
27 | console.log('[SERVER] Starting Server...');
28 | var server;
29 | server = new WebSocket({port: config['port'], path: '/slither'}, function () {
30 | console.log('[SERVER] Server Started at 127.0.0.1:' + config['port'] + '! Waiting for Connections...');
31 | console.log("[BOTS] Bot Status: Bot's are currently unavailable! Please try again later.");
32 | //console.log('[BOTS] Creating ' + config['bots'] + ' bots!');
33 | //console.log('[BOTS] Bots successfully loaded: ' + botCount + (botCount === 0 ? "\n[BOTS] Reason: Bot's aren't implemented yet. Please try again later" : ''));
34 | generateFood(config['food']);
35 | generateSectors();
36 | });
37 | /* server.on('error', function() {
38 | console.log('[DEBUG] Error while connecting!');
39 | });
40 | console.log("[SERVER] Server Started at 127.0.0.1:" + config["port"] + "! Waiting for Connections...");
41 | */
42 | if (server.readyState === server.OPEN) {
43 | server.on('connection', handleConnection.bind(server));
44 | } else {
45 | console.log(server.readyState);
46 | }
47 | function handleConnection (conn) {
48 | if (clients.length >= config['max-connections']) {
49 | console.log('[SERVER] Too many connections. Closing newest connections!');
50 | conn.close();
51 | return;
52 | }
53 | try {
54 | conn.id = ++counter;
55 | clients[conn.id] = conn;
56 | } catch (e) {
57 | console.log('[ERROR] ' + e);
58 | }
59 | conn.on('message', handleMessage.bind(this, conn));
60 | conn.on('error', close.bind(conn.id));
61 | conn.on('close', function(){
62 | console.log('[DEBUG] Connection closed.');
63 | messages.end.build(2);
64 | clearInterval(conn.snake.update);
65 | delete clients[conn.id];
66 | });
67 | }
68 | function handleMessage (conn, data) {
69 | var firstByte, name, radians, secondByte, skin, speed, value, x, y;
70 | if (data.length === 0) {
71 | console.log('[SERVER] No Data to handle!');
72 | return;
73 | }
74 | if (data.length >= 227) {
75 | console.log('[SERVER] Data length less than 227!');
76 | conn.close();
77 | } else if (data.length === 1) {
78 | value = message.readInt8(0, data);
79 | if (value <= 250) {
80 | // console.log('Snake going to', value);
81 | if (value === conn.snake.direction.angle) {
82 | console.log('[DEBUG] Angle is equal to last');
83 | return;
84 | }
85 | radians = value * 2*Math.PI / 251;
86 | speed = 1;
87 | x = Math.cos(radians) + 1;
88 | y = Math.sin(radians) + 1;
89 | conn.snake.direction.x = x * 127 * speed;
90 | conn.snake.direction.y = y * 127 * speed;
91 | conn.snake.direction.angle = radians;
92 | } else if (value === 253) {
93 | console.log('Snake in normal mode');
94 | } else if (value === 254) {
95 | console.log('Snake in speed mode');
96 | // killPlayer(conn.id, 1);
97 | //messages.end.build(2);
98 | } else if (value === 251) {
99 | send(conn.id, messages.pong);
100 | }
101 | } else {
102 | firstByte = message.readInt8(0, data);
103 | secondByte = message.readInt8(1, data);
104 | if (firstByte === 115) {
105 | // setMscps(411);
106 | skin = message.readInt8(2, data);
107 | name = message.readString(3, data, data.byteLength);
108 | conn.snake = new Snake(conn.id, name, {
109 | x: 28907.6,
110 | y: 21137.4
111 | }, skin);
112 | send(conn.id, messages.initial);
113 | broadcast(messages.snake.build(conn.snake));
114 |
115 | console.log((conn.snake.name === '' ? '[DEBUG] An unnamed snake' : '[DEBUG] A new snake called ' + conn.snake.name) + ' has connected!');
116 | spawnSnakes(conn.id);
117 | conn.snake.update = setInterval(function () {
118 | var distance = conn.snake.speed * loopInterval / 8;
119 | conn.snake.body.x += Math.cos(conn.snake.direction.angle) * distance;
120 | conn.snake.body.y += Math.sin(conn.snake.direction.angle) * distance;
121 |
122 | var R = config['gameRadius'];
123 | var r = (Math.pow((conn.snake.body.x - R), 2)) + (Math.pow((conn.snake.body.y - R), 2));
124 | if (r > Math.pow(R, 2)) {
125 | // console.log("[TEST] " + r + " < " + R^2);
126 | console.log('[DEBUG] Outside of Radius');
127 | var arr = new Uint8Array(6);
128 | message.writeInt8(2, arr, "s".charCodeAt(0));
129 | message.writeInt16(3, arr, conn.id);
130 | message.writeInt8(5, arr, 1);
131 | broadcast(arr);
132 | broadcast(messages.end.build(0));
133 | //sleep(1000);
134 | delete clients[conn.id];
135 | conn.close();
136 | }
137 |
138 | broadcast(messages.position.build(conn.id, conn.snake));
139 | broadcast(messages.direction.build(conn.id, conn.snake));
140 | //broadcast(messages.movement.build(conn.id, conn.snake));
141 | }, loopInterval);
142 | } // else if(firstByte === 255){
143 | // var msg = message.readString(3, data, data.byteLength);
144 | // send(conn.id, messages.highscore.build(conn.snake.name, msg));
145 | // delete clients[conn.id];
146 | // conn.close();
147 | else {
148 | console.log('[ERROR] Unhandled message ' + (String.fromCharCode(firstByte)));
149 | }
150 | send(conn.id, messages.leaderboard.build([conn], clients.length, [conn]));
151 | send(conn.id, messages.highscore.build(highscoreName, highscoreMessage));
152 | send(conn.id, messages.minimap.build(foods));
153 | }
154 | }
155 | function generateFood (amount) {
156 | var color, i, id, results, size, x, y;
157 | i = 0;
158 | results = [];
159 | while (i < amount) {
160 | x = math.randomInt(0, 65535);
161 | y = math.randomInt(0, 65535);
162 | id = x * config['gameRadius'] * 3 + y;
163 | color = math.randomInt(0, config['foodColors']);
164 | size = math.randomInt(config['foodSize'][0], config['foodSize'][1]);
165 | foods.push(new Food(id, {
166 | x: x,
167 | y: y
168 | }, size, color));
169 | results.push(i++);
170 | }
171 | return results;
172 | }
173 | function generateSectors () {
174 | var i, results, sectorsAmount;
175 | sectorsAmount = config['gameRadius'] / config['sectorSize'];
176 | i = 0;
177 | results = [];
178 | while (i < sectorsAmount) {
179 | results.push(i++);
180 | }
181 | return results;
182 | }
183 | function spawnSnakes (id) {
184 | clients.forEach(function (newClient) {
185 | if (newClient.id !== id) {
186 | send(id, messages.snake.build(newClient.snake));
187 | }
188 | });
189 | }
190 |
191 | function send (id, data) {
192 | var client = clients[id];
193 | if (client/* && client.readyState == client.OPEN */) {
194 | var currentTime = Date.now();
195 | var deltaTime = client.lastTime ? currentTime - client.lastTime : 0;
196 | client.lastTime = currentTime;
197 | message.writeInt16(0, data, deltaTime);
198 | client.send(data, {binary: true});
199 | }
200 | }
201 |
202 | function broadcast (data) {
203 | for (var i = 0; i < clients.length; i++) {
204 | send(i, data);
205 | }
206 | }
207 | function killPlayer (playerId, endType) {
208 | broadcast(messages.end.build(endType));
209 | }
210 | function setMscps (mscps) {
211 | fmlts = [mscps + 1 + 2048];
212 | fpsls = [mscps + 1 + 2048];
213 |
214 | for (var i = 0; i <= mscps; i++) {
215 | fmlts[i] = (i >= mscps ? fmlts[i - 1] : Math.pow(1 - 1.0 * i / mscps, 2.25));
216 | fpsls[i] = (i === 0 ? 0 : fpsls[i - 1] + 1.0 / fmlts[i - 1]);
217 | }
218 |
219 | var fmltsFiller = fmlts[mscps];
220 | var fpslsFiller = fpsls[mscps];
221 |
222 | for (var i = 0; i < 2048; i++) {
223 | fmlts[mscps + 1 + i] = fmltsFiller;
224 | fpsls[mscps + 1 + i] = fpslsFiller;
225 | }
226 | }
227 |
228 | function close () {
229 | console.log('[SERVER] Server Closed');
230 | server.close();
231 | }
232 |
--------------------------------------------------------------------------------