diff --git a/client/index.html b/client/index.html index 5fa42358b..9795711d6 100644 --- a/client/index.html +++ b/client/index.html @@ -1,7 +1,349 @@ - - -

-please head over to -

-Play.Ogarul.Tk - + + + + + + + + + + + + + OgarUnlimited.io + + + + + + + + + + + + + + +
+ + + +
+ +
+
+   +
+ + + + + diff --git a/client/main_out.js b/client/main_out.js index e6b77626b..908063183 100644 --- a/client/main_out.js +++ b/client/main_out.js @@ -5,23 +5,23 @@ * Example: 127.0.0.1:443 * */ - + /** * Enter path to the skin image folder * To take skins from the official server enter: "http://agar.io/skins/" */ - var SKIN_URL = "http://play.ogarul.tk/skins/";//skins folder + var SKIN_URL = "http://play.ogarul.tk/skins/"; //skins folder var touchX, touchY, - // is this running in a touch capable environment? + // is this running in a touch capable environment? touchable = 'createTouch' in document, touches = []; // array of touch vectors var leftTouchID = -1, - leftTouchPos = new Vector2(0,0), - leftTouchStartPos = new Vector2(0,0), - leftVector = new Vector2(0,0); + leftTouchPos = new Vector2(0, 0), + leftTouchStartPos = new Vector2(0, 0), + leftVector = new Vector2(0, 0); @@ -58,14 +58,13 @@ }; - if(touchable) { - mainCanvas.addEventListener( 'touchstart', onTouchStart, false ); - mainCanvas.addEventListener( 'touchmove', onTouchMove, false ); - mainCanvas.addEventListener( 'touchend', onTouchEnd, false ); - } + if (touchable) { + mainCanvas.addEventListener('touchstart', onTouchStart, false); + mainCanvas.addEventListener('touchmove', onTouchMove, false); + mainCanvas.addEventListener('touchend', onTouchEnd, false); + } - mainCanvas.onmouseup = function () { - }; + mainCanvas.onmouseup = function () {}; if (/firefox/i.test(navigator.userAgent)) { document.addEventListener("DOMMouseScroll", handleWheel, false); } else { @@ -114,29 +113,29 @@ } break; case 69: // e key - if (!ePressed && (!isTyping)) { - sendMouseMove(); - sendUint8(22); - if (!eMacro) ePressed = true; - console.log("E pressed") - } - break; + if (!ePressed && (!isTyping)) { + sendMouseMove(); + sendUint8(22); + if (!eMacro) ePressed = true; + console.log("E pressed") + } + break; case 82: // r key - if (!rPressed && (!isTyping)) { - sendMouseMove(); - sendUint8(23); - if (!rMacro) rPressed = true; - console.log("R pressed") - } - break; + if (!rPressed && (!isTyping)) { + sendMouseMove(); + sendUint8(23); + if (!rMacro) rPressed = true; + console.log("R pressed") + } + break; case 84: // T key - if (!rPressed && (!isTyping)) { - sendMouseMove(); - sendUint8(24); - tPressed = true; - console.log("T pressed") - } - break; + if (!rPressed && (!isTyping)) { + sendMouseMove(); + sendUint8(24); + tPressed = true; + console.log("T pressed") + } + break; case 27: // quit showOverlays(true); wHandle.isSpectating = false; @@ -150,8 +149,7 @@ if (chattxt.length > 0) sendChat(chattxt); document.getElementById("chat_textbox").value = ""; - } - else { + } else { if (!hasOverlay) { document.getElementById("chat_textbox").focus(); isTyping = true; @@ -168,14 +166,14 @@ wPressed = false; break; case 69: - ePressed = false; - break; - case 82: - rPressed = false; - break; - case 84: - tPressed = false; - break; + ePressed = false; + break; + case 82: + rPressed = false; + break; + case 84: + tPressed = false; + break; case 81: if (qPressed) { sendUint8(19); @@ -196,16 +194,16 @@ } else { setInterval(drawGameScene, 1E3 / 60); } - mouseinterval = setInterval(sendMouseMove, 40); - setInterval(function() { - try { - clearInterval(mouseinterval) - } catch (e) { - console.log("e at 204"); - } mouseinterval = setInterval(sendMouseMove, 40); - - },5000); + setInterval(function () { + try { + clearInterval(mouseinterval) + } catch (e) { + console.log("e at 204"); + } + mouseinterval = setInterval(sendMouseMove, 40); + + }, 5000); if (w) { wjQuery("#region").val(w); } @@ -223,24 +221,23 @@ function onTouchStart(e) { - for(var i = 0; i canvasWidth - size) && (touch.clientY > canvasHeight - size)) { sendMouseMove(); sendUint8(17); //split } - if ((touch.clientX > canvasWidth - size) && (touch.clientY > canvasHeight - 2*size -10) && (touch.clientY < canvasHeight - size -10 )) { + if ((touch.clientX > canvasWidth - size) && (touch.clientY > canvasHeight - 2 * size - 10) && (touch.clientY < canvasHeight - size - 10)) { sendMouseMove(); sendUint8(21); //eject } @@ -255,15 +252,14 @@ // Prevent the browser from doing its default thing (scroll, zoom) e.preventDefault(); - for(var i = 0; i") - .attr("value",det[0]) - .text(det[1])); -var pu = { -id: det[0], -name: det[1], -port: det[2], - - -} -knownServers.push(pu); -} -} + wjQuery("#gamemode").empty() + var info = getString() + var regi = info.split("|"); + for (var i in regi) { + if (!regi[i]) continue; + var det = regi[i].split(":"); + if (!det[2] || det[2] == "undefined") det[2] = defaultPort; + + wjQuery('#gamemode') + .append($("") + .attr("value", det[0]) + .text(det[1])); + var pu = { + id: det[0], + name: det[1], + port: det[2], + + + } + knownServers.push(pu); + } + } + function clientPacket(view, offset) { -function getString() { + function getString() { var text = '', char; while ((char = view.getUint8(offset, true)) != 0) { - offset ++; + offset++; text += String.fromCharCode(char); } - offset ++; + offset++; return text; } - var rawData = getString(); - var Data = JSON.parse(rawData); - for (var i in Data) { - -if (Data[i]) clientData[i] = Data[i]; -} -/* - // Macros - sMacro: 0, - wMacro: 0, - qMacro: 0, - eMacro: 0, - rMacro: 0, - - // Current client configs - darkBG: 1, - chat: 2, - skins: 2, - grid: 2, - acid: 1, - colors: 2, - names: 2, - showMass: 1, - smooth: 1, - - // Future feature - minionCount: 0, - minimap: 0, - - // Others - maxName: 15, - instructions: ""; - customHTML: ""; -*/ - if (Data.leavemessage) { - wjQuery(window).bind('beforeunload',function () { -return clientData.leavemessage -}); - } - if (Data.title) { - wjQuery(document).prop('title', clientData.title); - wjQuery("#titleh").text(clientData.title); - } - if (Data.defaultusername) wjQuery("#nick").val(clientData.defaultusername); - if (Data.nickplaceholder) wjQuery("#nick").attr("placeholder",clientData.nickplaceholder ) - if(Data.instructions) wjQuery("#customins").text(clientData.instructions); - if (Data.customHTML) wjQuery("#customht").html(clientData.customHTML); -if (Data.maxName) wjQuery("#nick").attr("maxlength", clientData.maxName); -if (Data.wMacro) wMacro = (clientData.wMacro == 1) ? true : false; -if (Data.sMacro) sMacro = (clientData.sMacro == 1) ? true : false; -if (Data.eMacro) eMacro = (clientData.eMacro == 1) ? true : false; -if (Data.rMacro) rMacro = (clientData.rMacro == 1) ? true : false; -if (Data.qMacro) qMacro = (clientData.qMacro == 1) ? true : false; -if (Data.chat) { if (clientData.chat < 2) wjQuery("#chat_textbox").hide(); else wjQuery("#chat_textbox").show();} -if (Data.darkBG) showDarkTheme = (clientData.darkBG < 2) ? false : true; -if (Data.skins) showSkin = (clientData.skins >= 2) ? true : false; -if (Data.grid) hideGrid = (clientData.grid >= 2) ? false : true; -if (Data.acid) xa = (clientData.acid < 2) ? false : true; -if (Data.colors) showColor = (clientData.colors >= 2) ? false : true; -if (Data.names) showName = (clientData.names < 2) ? false : true; -if (Data.showMass) showMass = (clientData.showMass < 2) ? false : true; -if (Data.smooth) smoothRender = (clientData.smooth >= 2) ? 2 : .4; -if (clientData.chat == 0 || clientData.chat == 3) wjQuery('#cchat').attr('disabled', true); else wjQuery('#cchat').attr('disabled', false); -if (clientData.darkBG == 0 || clientData.darkBG == 3) wjQuery('#cdark').attr('disabled', true); else wjQuery('#cdark').attr('disabled', false); -if (clientData.skins == 0 || clientData.skins == 3) wjQuery('#cskin').attr('disabled', true); else wjQuery('#cskin').attr('disabled', false); -if (clientData.grid == 0 || clientData.grid == 3) wjQuery('#cgrid').attr('disabled', true); else wjQuery('#cgrid').attr('disabled', false); -if (clientData.acid == 0 || clientData.acid == 3) wjQuery('#cacid').attr('disabled', true); else wjQuery('#cacid').attr('disabled', false); -if (clientData.colors == 0 || clientData.colors == 3) wjQuery('#ccolor').attr('disabled', true); else wjQuery('#ccolor').attr('disabled', false); -if (clientData.names == 0 || clientData.names == 3) wjQuery('#cname').attr('disabled', true); else wjQuery('#cname').attr('disabled', false); -if (clientData.showMass == 0 || clientData.showMass == 3) wjQuery('#cmass').attr('disabled', true); else wjQuery('#cmass').attr('disabled', false); -if (clientData.smooth == 0 || clientData.smooth == 3) wjQuery('#csmooth').attr('disabled', true); else wjQuery('#csmooth').attr('disabled', false); - -} + var rawData = getString(); + var Data = JSON.parse(rawData); + for (var i in Data) { + if (Data[i]) clientData[i] = Data[i]; + } + /* + // Macros + sMacro: 0, + wMacro: 0, + qMacro: 0, + eMacro: 0, + rMacro: 0, + + // Current client configs + darkBG: 1, + chat: 2, + skins: 2, + grid: 2, + acid: 1, + colors: 2, + names: 2, + showMass: 1, + smooth: 1, + + // Future feature + minionCount: 0, + minimap: 0, + + // Others + maxName: 15, + instructions: ""; + customHTML: ""; + */ + if (Data.leavemessage) { + wjQuery(window).bind('beforeunload', function () { + return clientData.leavemessage + }); + } + if (Data.title) { + wjQuery(document).prop('title', clientData.title); + wjQuery("#titleh").text(clientData.title); + } + if (Data.defaultusername) wjQuery("#nick").val(clientData.defaultusername); + if (Data.nickplaceholder) wjQuery("#nick").attr("placeholder", clientData.nickplaceholder) + if (Data.instructions) wjQuery("#customins").text(clientData.instructions); + if (Data.customHTML) wjQuery("#customht").html(clientData.customHTML); + if (Data.maxName) wjQuery("#nick").attr("maxlength", clientData.maxName); + if (Data.wMacro) wMacro = (clientData.wMacro == 1) ? true : false; + if (Data.sMacro) sMacro = (clientData.sMacro == 1) ? true : false; + if (Data.eMacro) eMacro = (clientData.eMacro == 1) ? true : false; + if (Data.rMacro) rMacro = (clientData.rMacro == 1) ? true : false; + if (Data.qMacro) qMacro = (clientData.qMacro == 1) ? true : false; + if (Data.chat) { + if (clientData.chat < 2) wjQuery("#chat_textbox").hide(); + else wjQuery("#chat_textbox").show(); + } + if (Data.darkBG) showDarkTheme = (clientData.darkBG < 2) ? false : true; + if (Data.skins) showSkin = (clientData.skins >= 2) ? true : false; + if (Data.grid) hideGrid = (clientData.grid >= 2) ? false : true; + if (Data.acid) xa = (clientData.acid < 2) ? false : true; + if (Data.colors) showColor = (clientData.colors >= 2) ? false : true; + if (Data.names) showName = (clientData.names < 2) ? false : true; + if (Data.showMass) showMass = (clientData.showMass < 2) ? false : true; + if (Data.smooth) smoothRender = (clientData.smooth >= 2) ? 2 : .4; + if (clientData.chat == 0 || clientData.chat == 3) wjQuery('#cchat').attr('disabled', true); + else wjQuery('#cchat').attr('disabled', false); + if (clientData.darkBG == 0 || clientData.darkBG == 3) wjQuery('#cdark').attr('disabled', true); + else wjQuery('#cdark').attr('disabled', false); + if (clientData.skins == 0 || clientData.skins == 3) wjQuery('#cskin').attr('disabled', true); + else wjQuery('#cskin').attr('disabled', false); + if (clientData.grid == 0 || clientData.grid == 3) wjQuery('#cgrid').attr('disabled', true); + else wjQuery('#cgrid').attr('disabled', false); + if (clientData.acid == 0 || clientData.acid == 3) wjQuery('#cacid').attr('disabled', true); + else wjQuery('#cacid').attr('disabled', false); + if (clientData.colors == 0 || clientData.colors == 3) wjQuery('#ccolor').attr('disabled', true); + else wjQuery('#ccolor').attr('disabled', false); + if (clientData.names == 0 || clientData.names == 3) wjQuery('#cname').attr('disabled', true); + else wjQuery('#cname').attr('disabled', false); + if (clientData.showMass == 0 || clientData.showMass == 3) wjQuery('#cmass').attr('disabled', true); + else wjQuery('#cmass').attr('disabled', false); + if (clientData.smooth == 0 || clientData.smooth == 3) wjQuery('#csmooth').attr('disabled', true); + else wjQuery('#csmooth').attr('disabled', false); + + } + // INSERT PROTOCOL function updateNodes(view, offset) { + + var obj = getData(view, 1); timestamp = +new Date; var code = Math.random(); ua = false; - var queueLength = view.getUint16(offset, true); - offset += 2; - for (i = 0; i < queueLength; ++i) { - var killer = nodes[view.getUint32(offset, true)], - killedNode = nodes[view.getUint32(offset + 4, true)]; - offset += 8; + + obj.eat.forEach((d) => { + var killer = nodes[d.killer], + killedNode = nodes[d.killed]; if (killer && killedNode) { killedNode.destroy(); killedNode.ox = killedNode.x; @@ -823,43 +831,22 @@ if (clientData.smooth == 0 || clientData.smooth == 3) wjQuery('#csmooth').attr(' killedNode.nSize = killedNode.size; killedNode.updateTime = timestamp; } - } - for (var i = 0; ;) { - var nodeid = view.getUint32(offset, true); - offset += 4; - if (0 == nodeid) break; - ++i; - var size, posY, posX = view.getInt16(offset, true); - offset += 2; - posY = view.getInt16(offset, true); - offset += 2; - size = view.getInt16(offset, true); - offset += 2; - for (var r = view.getUint8(offset++), g = view.getUint8(offset++), b = view.getUint8(offset++), - color = (r << 16 | g << 8 | b).toString(16); 6 > color.length;) color = "0" + color; + }) + + obj.update.forEach((up) => { + var nodeid = up.id; + var size = up.size, + posY = up.posY, + posX = up.posX; + for (var r = up.r, g = up.g, b = up.b, + color = (r << 16 | g << 8 | b).toString(16); 6 > color.length;) color = "0" + color; var colorstr = "#" + color, - flags = view.getUint8(offset++), + flags = up.flags, flagVirus = !!(flags & 1), flagAgitated = !!(flags & 16); - flags & 2 && (offset += 4); - flags & 4 && (offset += 8); - flags & 8 && (offset += 16); -if (isNewProto) { -for (var char, skin = ""; ;) { - char = view.getUint8(offset, true); - offset ++; - if (0 == char) break; - skin += String.fromCharCode(char); - } -} - for (var char, name = ""; ;) { - char = view.getUint16(offset, true); - offset += 2; - if (0 == char) break; - name += String.fromCharCode(char) - } - - + + var skin = up.skin; + var name = up.name; var node = null; if (nodes.hasOwnProperty(nodeid)) { node = nodes[nodeid]; @@ -893,15 +880,11 @@ for (var char, skin = ""; ;) { nodeY = node.y; } } - } - queueLength = view.getUint32(offset, true); - offset += 4; - for (i = 0; i < queueLength; i++) { - var nodeId = view.getUint32(offset, true); - offset += 4; + }) + obj.remove.forEach((nodeId) => { node = nodes[nodeId]; null != node && node.destroy(); - } + }) ua && 0 == playerCells.length && showOverlays(false) } @@ -934,7 +917,7 @@ for (var char, skin = ""; ;) { function sendChat(str) { console.log(str) - if (wsIsOpen() && (str.length < 200) && (str.length > 0) && !hideChat) { + if (wsIsOpen() && (str.length < 200) && (str.length > 0) && !hideChat) { var msg = prepareData(2 + 2 * str.length); var offset = 0; msg.setUint8(offset++, 99); @@ -968,7 +951,7 @@ for (var char, skin = ""; ;) { function canvasResize() { - window.scrollTo(0,0); + window.scrollTo(0, 0); canvasWidth = wHandle.innerWidth; canvasHeight = wHandle.innerHeight; nCanvas.width = canvasWidth; @@ -1066,9 +1049,8 @@ for (var char, skin = ""; ;) { } ctx.restore(); lbCanvas && lbCanvas.width && ctx.drawImage(lbCanvas, canvasWidth - lbCanvas.width - 10, 10); // draw Leader Board - if (!hideChat) - { - if ((chatCanvas != null)&&(chatCanvas.width > 0)) ctx.drawImage(chatCanvas, 0, canvasHeight - chatCanvas.height - 50); // draw Chat Board + if (!hideChat) { + if ((chatCanvas != null) && (chatCanvas.width > 0)) ctx.drawImage(chatCanvas, 0, canvasHeight - chatCanvas.height - 50); // draw Chat Board } userScore = Math.max(userScore, calcUserScore()); if (0 != userScore) { @@ -1080,9 +1062,9 @@ for (var char, skin = ""; ;) { a = c.width; ctx.globalAlpha = .2; ctx.fillStyle = '#000000'; - ctx.fillRect(10, 10, a + 10, 34);//canvasHeight - 10 - 24 - 10 + ctx.fillRect(10, 10, a + 10, 34); //canvasHeight - 10 - 24 - 10 ctx.globalAlpha = 1; - ctx.drawImage(c, 15, 15);//canvasHeight - 10 - 24 - 5 + ctx.drawImage(c, 15, 15); //canvasHeight - 10 - 24 - 5 } drawSplitIcon(ctx); drawTouch(ctx); @@ -1094,29 +1076,28 @@ for (var char, skin = ""; ;) { } - function drawTouch(ctx) - { + function drawTouch(ctx) { ctx.save(); - if(touchable) { + if (touchable) { - for(var i=0; i this.size) a = 0; if (this.isVirus) a = 30; var b = this.size; - if (!this.isVirus) (b *= viewZoom); + if (!this.isVirus)(b *= viewZoom); b *= z; - if (this.flag & 32) (b *= .25); + if (this.flag & 32)(b *= .25); return ~~Math.max(b, a); }, movePoints: function () { @@ -1552,8 +1534,8 @@ if (clientData.chat != 0 && clientData.chat != 3) pos2 = pointsacc[(i + 1) % numpoints]; pointsacc[i] += (Math.random() - .5) * (this.isAgitated ? 3 : 1); pointsacc[i] *= .7; - 10 < pointsacc[i] && (pointsacc[i] = 10); - -10 > pointsacc[i] && (pointsacc[i] = -10); + 10 < pointsacc[i] && (pointsacc[i] = 10); - + 10 > pointsacc[i] && (pointsacc[i] = -10); pointsacc[i] = (pos1 + pos2 + 8 * pointsacc[i]) / 10 } for (var ref = this, isvirus = this.isVirus ? 0 : (this.id / 1E3 + timestamp / 1E4) % (2 * Math.PI), j = 0; j < numpoints; ++j) { @@ -1598,8 +1580,8 @@ if (clientData.chat != 0 && clientData.chat != 3) var b = 0 > a ? 0 : 1 < a ? 1 : a; this.getNameSize(); if (this.destroyed && 1 <= b) { - var c = Cells.indexOf(this); - -1 != c && Cells.splice(c, 1) + var c = Cells.indexOf(this); - + 1 != c && Cells.splice(c, 1) } this.x = a * (this.nx - this.ox) + this.ox; this.y = a * (this.ny - this.oy) + this.oy; @@ -1637,8 +1619,7 @@ if (clientData.chat != 0 && clientData.chat != 3) if (b) { ctx.beginPath(); ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI, false); - } - else { + } else { this.movePoints(); ctx.beginPath(); var d = this.getNumPoints(); @@ -1650,29 +1631,29 @@ if (clientData.chat != 0 && clientData.chat != 3) } ctx.closePath(); -var skinurl = ''; -if (this.skin) { - var fir = this.skin.charAt(0); -if (fir == "%") { -skinurl = SKIN_URL + this.skin.substring(1) + ".png"; + var skinurl = ''; + if (this.skin) { + var fir = this.skin.charAt(0); + if (fir == "%") { + skinurl = SKIN_URL + this.skin.substring(1) + ".png"; -} else if (fir == ":") { -skinurl = this.skin.substring(1); + } else if (fir == ":") { + skinurl = this.skin.substring(1); -} -} + } + } if (!this.isAgitated && showSkin && skinurl) { - - - ski = new Image; - ski.src = skinurl; - - if (0 != ski.width && ski.complete) { - c = ski; - } else { - c = null; - } - + + + ski = new Image; + ski.src = skinurl; + + if (0 != ski.width && ski.complete) { + c = ski; + } else { + c = null; + } + } else { c = null; } @@ -1691,7 +1672,7 @@ skinurl = this.skin.substring(1); ctx.stroke(); } ctx.globalAlpha = 1; - + c = -1 != playerCells.indexOf(this); var ncache; //draw name @@ -1795,7 +1776,7 @@ skinurl = this.skin.substring(1); }, getWidth: function () { return (ctx.measureText(this._value).width + - 6); + 6); } }; Date.now || (Date.now = function () { @@ -1915,8 +1896,7 @@ skinurl = this.skin.substring(1); - + wHandle.onload = gameLoop -//console.log(knownNameDict); + //console.log(knownNameDict); })(window, window.jQuery); - diff --git a/client/oldindex.html b/client/oldindex.html deleted file mode 100644 index 39520efcc..000000000 --- a/client/oldindex.html +++ /dev/null @@ -1,183 +0,0 @@ - - - - - - - - - - - OgarUnlimited.io - - - - - - - - - - - - -
- - - -
- -
-
-   -
- - - - - diff --git a/package.json b/package.json index 37c2f8947..deb6cfe41 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,4 @@ -{ +{ "name": "MultiOgar", "version": "1.2.69", "description": "Open source Ogar server", @@ -10,7 +10,7 @@ "quad-node": "^1.0.5", "vector2-node": "latest", "ws": "latest", - "uglify-js": "latest", + "uglify-es": "latest", "javascript-obfuscator": "latest", "express": "latest" }, diff --git a/src/GameServer.js b/src/GameServer.js index 87eb67565..d1924cc0e 100644 --- a/src/GameServer.js +++ b/src/GameServer.js @@ -1,4 +1,4 @@ -// Library imports +// Library imports var http = require('http'); var fs = require("fs"); var os = require('os'); @@ -20,10 +20,12 @@ var Logger = require('./modules/Logger'); var UserRoleEnum = require('./enum/UserRoleEnum'); // GameServer implementation -function GameServer() { +function GameServer(protocols) { + this.protocols = protocols; + this.protocolMap = new Map(); this.httpServer = null; this.wsServer = null; - + // Startup this.run = true; this.lastNodeId = 1; @@ -32,18 +34,18 @@ function GameServer() { this.socketCount = 0; this.largestClient; // Required for spectators this.nodes = []; - this.nodesVirus = []; // Virus nodes + this.nodesVirus = []; // Virus nodes this.nodesEjected = []; // Ejected mass nodes this.quadTree = null; - + this.currentFood = 0; this.movingNodes = []; // For move engine this.leaderboard = []; this.leaderboardType = -1; // no type - + this.bots = new BotLoader(this); this.commands; // Command handler - + // Main loop tick this.startTime = Date.now(); this.stepDateTime = 0; @@ -52,98 +54,98 @@ function GameServer() { this.updateTimeAvg = 0; this.timerLoopBind = null; this.mainLoopBind = null; - + this.tickCounter = 0; - + this.setBorder(10000, 10000); - + // Config this.config = { - logVerbosity: 4, // Console log level (0=NONE; 1=FATAL; 2=ERROR; 3=WARN; 4=INFO; 5=DEBUG) - logFileVerbosity: 5, // File log level - - serverTimeout: 300, // Seconds to keep connection alive for non-responding client - serverWsModule: 'ws', // WebSocket module: 'ws' or 'uws' (install npm package before using uws) - serverMaxConnections: 64, // Maximum number of connections to the server. (0 for no limit) - serverIpLimit: 4, // Maximum number of connections from the same IP (0 for no limit) + logVerbosity: 4, // Console log level (0=NONE; 1=FATAL; 2=ERROR; 3=WARN; 4=INFO; 5=DEBUG) + logFileVerbosity: 5, // File log level + + serverTimeout: 300, // Seconds to keep connection alive for non-responding client + serverWsModule: 'ws', // WebSocket module: 'ws' or 'uws' (install npm package before using uws) + serverMaxConnections: 64, // Maximum number of connections to the server. (0 for no limit) + serverIpLimit: 4, // Maximum number of connections from the same IP (0 for no limit) serverMinionIgnoreTime: 30, // minion detection disable time on server startup [seconds] - serverMinionThreshold: 10, // max connections within serverMinionInterval time period, which will not be marked as minion + serverMinionThreshold: 10, // max connections within serverMinionInterval time period, which will not be marked as minion serverMinionInterval: 1000, // minion detection interval [milliseconds] - serverPort: 443, // Server port - serverBind: '0.0.0.0', // Network interface binding - serverTracker: 0, // Set to 1 if you want to show your server on the tracker http://ogar.mivabe.nl/master - serverGamemode: 0, // Gamemode, 0 = FFA, 1 = Teams - serverBots: 0, // Number of player bots to spawn - serverViewBaseX: 1920, // Base client screen resolution. Used to calculate view area. Warning: high values may cause lag - serverViewBaseY: 1080, // min value is 1920x1080 - serverMinScale: 0.15, // Min scale for player (low value leads to lags due to large visible area) - serverSpectatorScale: 0.4, // Scale (field of view) used for free roam spectators (low value leads to lags, vanilla=0.4, old vanilla=0.25) - serverStatsPort: 88, // Port for stats server. Having a negative number will disable the stats server. - serverStatsUpdate: 60, // Update interval of server stats in seconds - serverScrambleLevel: 2, // Toggles scrambling of coordinates. 0 = No scrambling, 1 = lightweight scrambling. 2 = full scrambling (also known as scramble minimap); 3 - high scrambling (no border) - serverMaxLB: 10, // Controls the maximum players displayed on the leaderboard. - serverChat: 1, // Set to 1 to allow chat; 0 to disable chat. - serverChatAscii: 1, // Set to 1 to disable non-ANSI letters in the chat (english only mode) - + serverPort: 443, // Server port + serverBind: '0.0.0.0', // Network interface binding + serverTracker: 0, // Set to 1 if you want to show your server on the tracker http://ogar.mivabe.nl/master + serverGamemode: 0, // Gamemode, 0 = FFA, 1 = Teams + serverBots: 0, // Number of player bots to spawn + serverViewBaseX: 1920, // Base client screen resolution. Used to calculate view area. Warning: high values may cause lag + serverViewBaseY: 1080, // min value is 1920x1080 + serverMinScale: 0.15, // Min scale for player (low value leads to lags due to large visible area) + serverSpectatorScale: 0.4, // Scale (field of view) used for free roam spectators (low value leads to lags, vanilla=0.4, old vanilla=0.25) + serverStatsPort: 88, // Port for stats server. Having a negative number will disable the stats server. + serverStatsUpdate: 60, // Update interval of server stats in seconds + serverScrambleLevel: 2, // Toggles scrambling of coordinates. 0 = No scrambling, 1 = lightweight scrambling. 2 = full scrambling (also known as scramble minimap); 3 - high scrambling (no border) + serverMaxLB: 10, // Controls the maximum players displayed on the leaderboard. + serverChat: 1, // Set to 1 to allow chat; 0 to disable chat. + serverChatAscii: 1, // Set to 1 to disable non-ANSI letters in the chat (english only mode) + serverName: 'MultiOgar #1', // Server name - serverWelcome1: 'Welcome to MultiOgar server!', // First server welcome message - serverWelcome2: '', // Second server welcome message (for info, etc) - - borderWidth: 14142, // Map border size (Vanilla value: 14142) - borderHeight: 14142, // Map border size (Vanilla value: 14142) - - foodMinSize: 10, // Minimum food size (vanilla 10) - foodMaxSize: 20, // Maximum food size (vanilla 20) - foodMinAmount: 1000, // Minimum food cells on the map - foodMaxAmount: 2000, // Maximum food cells on the map - foodSpawnAmount: 30, // The number of food to spawn per interval - foodMassGrow: 1, // Enable food mass grow ? - spawnInterval: 20, // The interval between each food cell spawn in ticks (1 tick = 50 ms) - - virusMinSize: 100, // Minimum virus size (vanilla 100) - virusMaxSize: 140, // Maximum virus size (vanilla 140) - virusMinAmount: 50, // Minimum number of viruses on the map. - virusMaxAmount: 100, // Maximum number of viruses on the map. If this number is reached, then ejected cells will pass through viruses. - - ejectSize: 38, // Size of ejected cells (vanilla 38) - ejectSizeLoss: 43, // Eject size which will be substracted from player cell (vanilla 43?) - ejectDistance: 780, // vanilla 780 - ejectCooldown: 3, // min ticks between ejects - ejectSpawnPlayer: 1, // if 1 then player may be spawned from ejected mass - - playerMinSize: 32, // Minimym size of the player cell (mass = 32*32/100 = 10.24) - playerMaxSize: 1500, // Maximum size of the player cell (mass = 1500*1500/100 = 22500) - playerMinSplitSize: 60, // Minimum player cell size allowed to split (mass = 60*60/100 = 36) - playerStartSize: 64, // Start size of the player cell (mass = 64*64/100 = 41) - playerMaxCells: 16, // Max cells the player is allowed to have - playerSpeed: 1, // Player speed multiplier - playerDecayRate: .002, // Amount of player cell size lost per second - playerRecombineTime: 30, // Base time in seconds before a cell is allowed to recombine - playerMaxNickLength: 15, // Maximum nick length - playerDisconnectTime: 60, // The time in seconds it takes for a player cell to be removed after disconnection (If set to -1, cells are never removed) - - tourneyMaxPlayers: 12, // Maximum number of participants for tournament style game modes - tourneyPrepTime: 10, // Number of ticks to wait after all players are ready (1 tick = 1000 ms) - tourneyEndTime: 30, // Number of ticks to wait after a player wins (1 tick = 1000 ms) - tourneyTimeLimit: 20, // Time limit of the game, in minutes. - tourneyAutoFill: 0, // If set to a value higher than 0, the tournament match will automatically fill up with bots after this amount of seconds - tourneyAutoFillPlayers: 1, // The timer for filling the server with bots will not count down unless there is this amount of real players + serverWelcome1: 'Welcome to MultiOgar server!', // First server welcome message + serverWelcome2: '', // Second server welcome message (for info, etc) + + borderWidth: 14142, // Map border size (Vanilla value: 14142) + borderHeight: 14142, // Map border size (Vanilla value: 14142) + + foodMinSize: 10, // Minimum food size (vanilla 10) + foodMaxSize: 20, // Maximum food size (vanilla 20) + foodMinAmount: 1000, // Minimum food cells on the map + foodMaxAmount: 2000, // Maximum food cells on the map + foodSpawnAmount: 30, // The number of food to spawn per interval + foodMassGrow: 1, // Enable food mass grow ? + spawnInterval: 20, // The interval between each food cell spawn in ticks (1 tick = 50 ms) + + virusMinSize: 100, // Minimum virus size (vanilla 100) + virusMaxSize: 140, // Maximum virus size (vanilla 140) + virusMinAmount: 50, // Minimum number of viruses on the map. + virusMaxAmount: 100, // Maximum number of viruses on the map. If this number is reached, then ejected cells will pass through viruses. + + ejectSize: 38, // Size of ejected cells (vanilla 38) + ejectSizeLoss: 43, // Eject size which will be substracted from player cell (vanilla 43?) + ejectDistance: 780, // vanilla 780 + ejectCooldown: 3, // min ticks between ejects + ejectSpawnPlayer: 1, // if 1 then player may be spawned from ejected mass + + playerMinSize: 32, // Minimym size of the player cell (mass = 32*32/100 = 10.24) + playerMaxSize: 1500, // Maximum size of the player cell (mass = 1500*1500/100 = 22500) + playerMinSplitSize: 60, // Minimum player cell size allowed to split (mass = 60*60/100 = 36) + playerStartSize: 64, // Start size of the player cell (mass = 64*64/100 = 41) + playerMaxCells: 16, // Max cells the player is allowed to have + playerSpeed: 1, // Player speed multiplier + playerDecayRate: .002, // Amount of player cell size lost per second + playerRecombineTime: 30, // Base time in seconds before a cell is allowed to recombine + playerMaxNickLength: 15, // Maximum nick length + playerDisconnectTime: 60, // The time in seconds it takes for a player cell to be removed after disconnection (If set to -1, cells are never removed) + + tourneyMaxPlayers: 12, // Maximum number of participants for tournament style game modes + tourneyPrepTime: 10, // Number of ticks to wait after all players are ready (1 tick = 1000 ms) + tourneyEndTime: 30, // Number of ticks to wait after a player wins (1 tick = 1000 ms) + tourneyTimeLimit: 20, // Time limit of the game, in minutes. + tourneyAutoFill: 0, // If set to a value higher than 0, the tournament match will automatically fill up with bots after this amount of seconds + tourneyAutoFillPlayers: 1, // The timer for filling the server with bots will not count down unless there is this amount of real players }; - + this.ipBanList = []; this.minionTest = []; this.userList = []; this.badWords = []; - + // Parse config this.loadConfig(); this.loadIpBanList(); this.loadUserList(); this.loadBadWords(); - + this.setBorder(this.config.borderWidth, this.config.borderHeight); this.quadTree = new QuadNode(this.border, 64, 32); - + // Gamemodes this.gameMode = Gamemode.get(this.config.serverGamemode); } @@ -153,29 +155,38 @@ module.exports = GameServer; GameServer.prototype.start = function () { this.timerLoopBind = this.timerLoop.bind(this); this.mainLoopBind = this.mainLoop.bind(this); - + // Gamemode configurations this.gameMode.onServerInit(this); - - var dirSsl = path.join(path.dirname(module.filename), '../ssl'); - var pathKey = path.join(dirSsl, 'key.pem'); - var pathCert = path.join(dirSsl, 'cert.pem'); - - if (fs.existsSync(pathKey) && fs.existsSync(pathCert)) { - // HTTP/TLS - var options = { - key: fs.readFileSync(pathKey, 'utf8'), - cert: fs.readFileSync(pathCert, 'utf8') - }; - Logger.info("TLS: supported"); - this.httpServer = HttpsServer.createServer(options); - } else { - // HTTP only - Logger.warn("TLS: not supported (SSL certificate not found!)"); - this.httpServer = http.createServer(); - } + + var express = require('express') + this.app = express(); + + this.app.use(function (req, res, next) { + res.header("Access-Control-Allow-Origin", "*"); + res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); + next(); + }); + + + + // HTTP only + this.httpServer = http.createServer(this.app); + + this.app.use('/main_out.js', (req, res, next) => { + var ip = req.connection.remoteAddress; + + var a = this.protocolMap.get(ip); + if (a) res.send(a.client); + else { + var random = this.protocols[Math.floor(Math.random() * this.protocols.length)] + this.protocolMap.set(ip, random) + res.send(random.client) + } + }) + this.app.use(express.static(__dirname + '/../client/')) var wsOptions = { - server: this.httpServer, + server: this.httpServer, perMessageDeflate: false, maxPayload: 4096 }; @@ -190,33 +201,35 @@ GameServer.prototype.start = function () { } var buffer = packet.build(this.playerTracker.socket.packetHandler.protocol); if (buffer != null) { - this.send(buffer, { binary: true }); + this.send(buffer, { + binary: true + }); } } else { this.readyState = WebSocket.CLOSED; this.emit('close'); } }; - + this.wsServer = new WebSocket.Server(wsOptions); this.wsServer.on('error', this.onServerSocketError.bind(this)); this.wsServer.on('connection', this.onClientSocketOpen.bind(this)); this.httpServer.listen(this.config.serverPort, this.config.serverBind, this.onHttpServerOpen.bind(this)); - + this.startStatsServer(this.config.serverStatsPort); }; GameServer.prototype.onHttpServerOpen = function () { // Spawn starting food this.startingFood(); - + // Start Main Loop setTimeout(this.timerLoopBind, 1); - + // Done Logger.info("Listening on port " + this.config.serverPort); Logger.info("Current game mode is " + this.gameMode.name); - + // Player bots (Experimental) if (this.config.serverBots > 0) { for (var i = 0; i < this.config.serverBots; i++) { @@ -242,9 +255,14 @@ GameServer.prototype.onServerSocketError = function (error) { GameServer.prototype.onClientSocketOpen = function (ws) { var logip = ws._socket.remoteAddress + ":" + ws._socket.remotePort; + var proto = this.protocolMap.get(ws._socket.remoteAddress); + if (!proto) return ws.close(1000, 'No protocol!') + //console.log(proto.UNodesProtocol) ws.on('error', function (err) { Logger.writeError("[" + logip + "] " + err.stack); }); + + if (this.config.serverMaxConnections > 0 && this.socketCount >= this.config.serverMaxConnections) { ws.close(1000, "No slots"); return; @@ -270,12 +288,12 @@ GameServer.prototype.onClientSocketOpen = function (ws) { ws.remoteAddress = ws._socket.remoteAddress; ws.remotePort = ws._socket.remotePort; ws.lastAliveTime = Date.now(); - Logger.write("CONNECTED " + ws.remoteAddress + ":" + ws.remotePort + ", origin: \"" + ws.upgradeReq.headers.origin + "\""); - - ws.playerTracker = new PlayerTracker(this, ws); + Logger.write("CONNECTED " + ws.remoteAddress + ":" + ws.remotePort + ", origin: \"\""); + + ws.playerTracker = new PlayerTracker(this, ws, proto); ws.packetHandler = new PacketHandler(this, ws); ws.playerCommand = new PlayerCommand(this, ws.playerTracker); - + var self = this; var onMessage = function (message) { self.onClientSocketMessage(ws, message); @@ -291,7 +309,7 @@ GameServer.prototype.onClientSocketOpen = function (ws) { ws.on('close', onClose); this.socketCount++; this.clients.push(ws); - + // Minion detection if (this.config.serverMinionThreshold) { if ((ws.lastAliveTime - this.startTime) / 1000 >= this.config.serverMinionIgnoreTime) { @@ -312,7 +330,7 @@ GameServer.prototype.onClientSocketOpen = function (ws) { }; GameServer.prototype.onClientSocketClose = function (ws, code) { - if (ws._socket.destroy != null && typeof ws._socket.destroy == 'function') { + if (ws._socket && ws._socket.destroy != null && typeof ws._socket.destroy == 'function') { ws._socket.destroy(); } if (this.socketCount < 1) { @@ -321,11 +339,14 @@ GameServer.prototype.onClientSocketClose = function (ws, code) { this.socketCount--; } ws.isConnected = false; - ws.sendPacket = function (data) { }; - ws.closeReason = { code: ws._closeCode, message: ws._closeMessage }; + ws.sendPacket = function (data) {}; + ws.closeReason = { + code: ws._closeCode, + message: ws._closeMessage + }; ws.closeTime = Date.now(); Logger.write("DISCONNECTED " + ws.remoteAddress + ":" + ws.remotePort + ", code: " + ws._closeCode + ", reason: \"" + ws._closeMessage + "\", name: \"" + ws.playerTracker.getName() + "\""); - + // disconnected effect var color = this.getGrayColor(ws.playerTracker.getColor()); ws.playerTracker.setColor(color); @@ -336,7 +357,7 @@ GameServer.prototype.onClientSocketClose = function (ws, code) { }; GameServer.prototype.onClientSocketError = function (ws, error) { - ws.sendPacket = function (data) { }; + ws.sendPacket = function (data) {}; }; GameServer.prototype.onClientSocketMessage = function (ws, message) { @@ -409,23 +430,63 @@ GameServer.prototype.getRandomColor = function () { var h = 360 * Math.random(); var s = 248 / 255; var v = 1; - + // hsv to rgb - var rgb = { r: v, g: v, b: v }; // achromatic (grey) + var rgb = { + r: v, + g: v, + b: v + }; // achromatic (grey) if (s > 0) { - h /= 60; // sector 0 to 5 + h /= 60; // sector 0 to 5 var i = Math.floor(h) >> 0; - var f = h - i; // factorial part of h + var f = h - i; // factorial part of h var p = v * (1 - s); var q = v * (1 - s * f); var t = v * (1 - s * (1 - f)); switch (i) { - case 0: rgb = { r: v, g: t, b: p }; break - case 1: rgb = { r: q, g: v, b: p }; break - case 2: rgb = { r: p, g: v, b: t }; break - case 3: rgb = { r: p, g: q, b: v }; break - case 4: rgb = { r: t, g: p, b: v }; break - default: rgb = { r: v, g: p, b: q }; break + case 0: + rgb = { + r: v, + g: t, + b: p + }; + break + case 1: + rgb = { + r: q, + g: v, + b: p + }; + break + case 2: + rgb = { + r: p, + g: v, + b: t + }; + break + case 3: + rgb = { + r: p, + g: q, + b: v + }; + break + case 4: + rgb = { + r: t, + g: p, + b: v + }; + break + default: + rgb = { + r: v, + g: p, + b: q + }; + break } } // check color range @@ -475,19 +536,24 @@ GameServer.prototype.addNode = function (node) { x: x, y: y, size: size, - bound: { minx: x-size, miny: y-size, maxx: x+size, maxy: y+size } + bound: { + minx: x - size, + miny: y - size, + maxx: x + size, + maxy: y + size + } }; this.quadTree.insert(node.quadItem); - + this.nodes.push(node); - + // Adds to the owning player's screen if (node.owner) { node.setColor(node.owner.getColor()); node.owner.cells.push(node); node.owner.socket.sendPacket(new Packet.AddNode(node.owner, node)); } - + // Special on-add actions node.onAdd(this); }; @@ -499,26 +565,26 @@ GameServer.prototype.removeNode = function (node) { node.isRemoved = true; this.quadTree.remove(node.quadItem); node.quadItem = null; - + // Remove from main nodes list var index = this.nodes.indexOf(node); if (index != -1) { this.nodes.splice(index, 1); } - + // Remove from moving cells list index = this.movingNodes.indexOf(node); if (index != -1) { this.movingNodes.splice(index, 1); } - + // Special on-remove actions node.onRemove(this); }; GameServer.prototype.updateClients = function () { // check minions - for (var i = 0; i < this.minionTest.length; ) { + for (var i = 0; i < this.minionTest.length;) { var playerTracker = this.minionTest[i]; if (this.stepDateTime - playerTracker.connectedTime > this.config.serverMinionInterval) { this.minionTest.splice(i, 1); @@ -527,7 +593,7 @@ GameServer.prototype.updateClients = function () { } } // check dead clients - for (var i = 0; i < this.clients.length; ) { + for (var i = 0; i < this.clients.length;) { var playerTracker = this.clients[i].playerTracker; playerTracker.checkConnection(); if (playerTracker.isRemoved) { @@ -551,11 +617,11 @@ GameServer.prototype.updateLeaderboard = function () { this.leaderboard = []; this.leaderboardType = -1; this.gameMode.updateLB(this); - + if (!this.gameMode.specByLeaderboard) { // Get client with largest score if gamemode doesn't have a leaderboard var clients = this.clients.valueOf(); - + // Use sort function clients.sort(function (a, b) { return b.playerTracker.getScore() - a.playerTracker.getScore(); @@ -626,7 +692,7 @@ GameServer.prototype.sendChatMessage = function (from, to, message) { GameServer.prototype.timerLoop = function () { var timeStep = 40; - + var ts = Date.now(); var dt = ts - this.timeStamp; if (dt < timeStep - 5) { @@ -644,7 +710,7 @@ GameServer.prototype.timerLoop = function () { } if (dt > 120) { // too high lag => resynchronize - this.timeStamp = ts-timeStep; + this.timeStamp = ts - timeStep; } // update average this.updateTimeAvg += 0.5 * (this.updateTime - this.updateTimeAvg); @@ -661,12 +727,12 @@ GameServer.prototype.timerLoop = function () { GameServer.prototype.mainLoop = function () { this.stepDateTime = Date.now(); var tStart = process.hrtime(); - + // Loop main functions if (this.run) { this.updateMoveEngine(); if ((this.getTick() % this.config.spawnInterval) == 0) { - this.updateFood(); // Spawn food + this.updateFood(); // Spawn food this.updateVirus(); // Spawn viruses } this.gameMode.onTick(this); @@ -675,20 +741,20 @@ GameServer.prototype.mainLoop = function () { this.updateMassDecay(); } } - + this.updateClients(); - + if (((this.getTick() + 7) % (1000 / 40)) == 0) { // once per second this.updateLeaderboard(); } - + // ping server tracker if (this.config.serverTracker && (this.getTick() % (10000 / 40)) == 0) { // once per 30 seconds this.pingServerTracker(); } - + if (this.run) { this.tickCounter++; } @@ -773,11 +839,11 @@ GameServer.prototype.spawnPlayer = function (player, pos, size) { // Get starting mass size = this.config.playerStartSize; } - + // Spawn player and add to world var cell = new Entity.PlayerCell(this, player, pos, size); this.addNode(cell); - + // Set initial mouse coords player.mouse = { x: pos.x, @@ -794,7 +860,7 @@ GameServer.prototype.willCollide = function (pos, size) { maxy: pos.y + size }; return this.quadTree.any( - bound, + bound, function (item) { return item.cell.cellType == 0; // check players only }); @@ -806,7 +872,7 @@ GameServer.prototype.checkCellCollision = function (cell, check) { var r = cell.getSize() + check.getSize(); var dx = check.position.x - cell.position.x; var dy = check.position.y - cell.position.y; - var squared = dx * dx + dy * dy; // squared distance from cell to check + var squared = dx * dx + dy * dy; // squared distance from cell to check if (squared > r * r) { // no collision return null; @@ -815,10 +881,10 @@ GameServer.prototype.checkCellCollision = function (cell, check) { return { cell1: cell, cell2: check, - r: r, // radius sum - dx: dx, // delta x from cell1 to cell2 - dy: dy, // delta y from cell1 to cell2 - squared: squared // squared distance from cell1 to cell2 + r: r, // radius sum + dx: dx, // delta x from cell1 to cell2 + dy: dy, // delta y from cell1 to cell2 + squared: squared // squared distance from cell1 to cell2 }; }; @@ -828,26 +894,26 @@ GameServer.prototype.resolveRigidCollision = function (manifold, border) { var d = Math.sqrt(manifold.squared); if (d <= 0) return; var invd = 1 / d; - + // normal var nx = ~~manifold.dx * invd; var ny = ~~manifold.dy * invd; - + // body penetration distance var penetration = manifold.r - d; if (penetration <= 0) return; - + // penetration vector = penetration * normal var px = penetration * nx; var py = penetration * ny; - + // body impulse var totalMass = manifold.cell1.getSizeSquared() + manifold.cell2.getSizeSquared(); if (totalMass <= 0) return; var invTotalMass = 1 / totalMass; var impulse1 = manifold.cell2.getSizeSquared() * invTotalMass; var impulse2 = manifold.cell1.getSizeSquared() * invTotalMass; - + // apply extrusion force manifold.cell1.position.x -= px * impulse1; manifold.cell1.position.y -= py * impulse1; @@ -864,7 +930,7 @@ GameServer.prototype.checkRigidCollision = function (manifold) { return false; if (manifold.cell1.owner != manifold.cell2.owner) { // Different owners - return this.gameMode.haveTeams && + return this.gameMode.haveTeams && manifold.cell1.owner.getTeam() == manifold.cell2.owner.getTeam(); } // The same owner @@ -889,17 +955,17 @@ GameServer.prototype.resolveCollision = function (manifold) { minCell = manifold.cell2; maxCell = manifold.cell1; } - + // check distance var eatDistance = maxCell.getSize() - minCell.getSize() / 3; if (manifold.squared >= eatDistance * eatDistance) { // too far => can't eat return; } - + if (minCell.owner && minCell.owner == maxCell.owner) { // collision owned/owned => ignore or resolve or remerge - + var tick = this.getTick(); if (minCell.getAge(tick) < 15 || maxCell.getAge(tick) < 15) { // just splited => ignore @@ -914,7 +980,7 @@ GameServer.prototype.resolveCollision = function (manifold) { } } else { // collision owned/enemy => check if can eat - + // Team check if (this.gameMode.haveTeams && minCell.owner && maxCell.owner) { if (minCell.owner.getTeam() == maxCell.owner.getTeam()) { @@ -932,28 +998,28 @@ GameServer.prototype.resolveCollision = function (manifold) { // maxCell don't want to eat return; } - + // Now maxCell can eat minCell minCell.isRemoved = true; - + // Disable mergeOverride on the last merging cell // We need to disable it before onCosume to prevent merging loop // (onConsume may cause split for big mass) if (minCell.owner && minCell.owner.cells.length <= 2) { minCell.owner.mergeOverride = false; } - + var isMinion = (maxCell.owner && maxCell.owner.isMinion) || (minCell.owner && minCell.owner.isMinion); if (!isMinion) { // Consume effect maxCell.onEat(minCell); minCell.onEaten(maxCell); - + // update bounds this.updateNodeQuad(maxCell); } - + // Remove cell minCell.setKiller(maxCell); this.removeNode(minCell); @@ -998,7 +1064,7 @@ GameServer.prototype.updateMoveEngine = function () { } } // Move moving cells - for (var i = 0; i < this.movingNodes.length; ) { + for (var i = 0; i < this.movingNodes.length;) { var cell1 = this.movingNodes[i]; if (cell1.isRemoved) continue; @@ -1009,9 +1075,9 @@ GameServer.prototype.updateMoveEngine = function () { else i++; } - + // === check for collisions === - + // Scan for player cells collisions var self = this; var rigidCollisions = []; @@ -1027,21 +1093,27 @@ GameServer.prototype.updateMoveEngine = function () { var manifold = self.checkCellCollision(cell1, cell2); if (manifold == null) return; if (self.checkRigidCollision(manifold)) - rigidCollisions.push({ cell1: cell1, cell2: cell2 }); + rigidCollisions.push({ + cell1: cell1, + cell2: cell2 + }); else - eatCollisions.push({ cell1: cell1, cell2: cell2 }); + eatCollisions.push({ + cell1: cell1, + cell2: cell2 + }); }); } } - + // resolve rigid body collisions ////for (var z = 0; z < 2; z++) { // loop for better rigid body resolution quality (slow) - for (var k = 0; k < rigidCollisions.length; k++) { - var c = rigidCollisions[k]; - var manifold = this.checkCellCollision(c.cell1, c.cell2); - if (manifold == null) continue; - this.resolveRigidCollision(manifold, this.border); - } + for (var k = 0; k < rigidCollisions.length; k++) { + var c = rigidCollisions[k]; + var manifold = this.checkCellCollision(c.cell1, c.cell2); + if (manifold == null) continue; + this.resolveRigidCollision(manifold, this.border); + } ////} // Update quad tree for (var k = 0; k < rigidCollisions.length; k++) { @@ -1050,7 +1122,7 @@ GameServer.prototype.updateMoveEngine = function () { this.updateNodeQuad(c.cell2); } rigidCollisions = null; - + // resolve eat collisions for (var k = 0; k < eatCollisions.length; k++) { var c = eatCollisions[k]; @@ -1059,9 +1131,9 @@ GameServer.prototype.updateMoveEngine = function () { this.resolveCollision(manifold); } eatCollisions = null; - + //this.gameMode.onCellMove(cell1, this); - + // Scan for ejected cell collisions (scan for ejected or virus only) rigidCollisions = []; eatCollisions = []; @@ -1077,7 +1149,10 @@ GameServer.prototype.updateMoveEngine = function () { if (manifold == null) return; if (cell1.cellType == 3 && cell2.cellType == 3) { // ejected/ejected - rigidCollisions.push({ cell1: cell1, cell2: cell2 }); + rigidCollisions.push({ + cell1: cell1, + cell2: cell2 + }); // add to moving nodes if needed if (!cell1.isMoving) { cell1.isMoving = true @@ -1087,13 +1162,15 @@ GameServer.prototype.updateMoveEngine = function () { cell2.isMoving = true self.movingNodes.push(cell2); } - } - else { - eatCollisions.push({ cell1: cell1, cell2: cell2 }); + } else { + eatCollisions.push({ + cell1: cell1, + cell2: cell2 + }); } }); } - + // resolve rigid body collisions for (var k = 0; k < rigidCollisions.length; k++) { var c = rigidCollisions[k]; @@ -1109,7 +1186,7 @@ GameServer.prototype.updateMoveEngine = function () { this.updateNodeQuad(c.cell2); } rigidCollisions = null; - + // resolve eat collisions for (var k = 0; k < eatCollisions.length; k++) { var c = eatCollisions[k]; @@ -1124,7 +1201,7 @@ GameServer.prototype.splitMass = function (mass, count) { // min throw size (vanilla 44) var throwSize = this.config.playerMinSize + 12; var throwMass = throwSize * throwSize / 100; - + // check maxCount var maxCount = count; var curMass = mass; @@ -1134,7 +1211,7 @@ GameServer.prototype.splitMass = function (mass, count) { if (maxCount < 2) { return [mass]; } - + // calculate mass var minMass = this.config.playerMinSize * this.config.playerMinSize / 100; var splitMass = curMass / maxCount; @@ -1242,7 +1319,7 @@ GameServer.prototype.splitCells = function (client) { } var angle = Math.atan2(dx, dy); if (isNaN(angle)) angle = Math.PI / 2; - + if (this.splitPlayerCell(client, cell, angle, null)) { splitCells++; } @@ -1252,12 +1329,12 @@ GameServer.prototype.splitCells = function (client) { // TODO: replace mass with size (Virus) GameServer.prototype.splitPlayerCell = function (client, parent, angle, mass) { // Returns boolean whether a cell has been split or not. You can use this in the future. - + if (client.cells.length >= this.config.playerMaxCells) { // Player cell limit return false; } - + var size1 = 0; var size2 = 0; if (mass == null) { @@ -1270,20 +1347,20 @@ GameServer.prototype.splitPlayerCell = function (client, parent, angle, mass) { if (isNaN(size1) || size1 < this.config.playerMinSize) { return false; } - + // Remove mass from parent cell first parent.setSize(size1); - + // make a small shift to the cell position to prevent extrusion in wrong direction var pos = { x: parent.position.x + 40 * Math.sin(angle), y: parent.position.y + 40 * Math.cos(angle) }; - + // Create cell var newCell = new Entity.PlayerCell(this, client, pos, size2); newCell.setBoost(780, angle); - + // Add to node list this.addNode(newCell); return true; @@ -1310,11 +1387,11 @@ GameServer.prototype.ejectMass = function (client) { return; for (var i = 0; i < client.cells.length; i++) { var cell = client.cells[i]; - + if (!cell) { continue; } - + if (cell.getSize() < this.config.playerMinSplitSize) { continue; } @@ -1325,7 +1402,7 @@ GameServer.prototype.ejectMass = function (client) { continue; } var size1 = Math.sqrt(sizeSquared); - + var dx = client.mouse.x - cell.position.x; var dy = client.mouse.y - cell.position.y; var dl = dx * dx + dy * dy; @@ -1337,28 +1414,28 @@ GameServer.prototype.ejectMass = function (client) { dx /= dl; dy /= dl; } - + // Remove mass from parent cell first cell.setSize(size1); - + // Get starting position var pos = { x: cell.position.x + dx * cell.getSize(), y: cell.position.y + dy * cell.getSize() }; - + var angle = Math.atan2(dx, dy); if (isNaN(angle)) angle = Math.PI / 2; - + // Randomize angle angle += (Math.random() * 0.6) - 0.3; - + // Create cell var ejected = new Entity.EjectedMass(this, null, pos, size2); ejected.ejector = cell; ejected.setColor(cell.getColor()); ejected.setBoost(this.config.ejectDistance, angle); - + this.addNode(ejected); } }; @@ -1368,10 +1445,10 @@ GameServer.prototype.shootVirus = function (parent, angle) { x: parent.position.x, y: parent.position.y, }; - + var newVirus = new Entity.Virus(this, null, parentPos, this.config.virusMinSize); newVirus.setBoost(780, angle); - + // Add to moving cells list this.addNode(newVirus); }; @@ -1427,7 +1504,7 @@ GameServer.prototype.checkSkinName = function (skinName) { if (skinName.length == 1 || skinName.length > 25) { return false; } - if (skinName[0] != '%' /* && skinName[0] != ':' */) { + if (skinName[0] != '%' /* && skinName[0] != ':' */ ) { return false; } for (var i = 1; i < skinName.length; i++) { @@ -1480,8 +1557,12 @@ GameServer.prototype.loadBadWords = function () { } else { var words = fs.readFileSync(fileNameBadWords, 'utf-8'); words = words.split(/[\r\n]+/); - words = words.map(function (arg) { return arg.trim().toLowerCase(); }); - words = words.filter(function (arg) { return !!arg; }); + words = words.map(function (arg) { + return arg.trim().toLowerCase(); + }); + words = words.filter(function (arg) { + return !!arg; + }); this.badWords = words; Logger.info(this.badWords.length + " bad words loaded"); } @@ -1513,12 +1594,12 @@ GameServer.prototype.changeConfig = function (name, value) { return; } this.config[name] = value; - + // update/validate this.config.playerMinSize = Math.max(32, this.config.playerMinSize); Logger.setVerbosity(this.config.logVerbosity); Logger.setFileVerbosity(this.config.logFileVerbosity); - + Logger.print("Set " + name + " = " + this.config[name]); }; @@ -1531,7 +1612,7 @@ GameServer.prototype.loadUserList = function () { } var usersJson = fs.readFileSync(fileNameUsers, 'utf-8'); var list = JSON.parse(usersJson.trim()); - for (var i = 0; i < list.length; ) { + for (var i = 0; i < list.length;) { var item = list[i]; if (!item.hasOwnProperty("ip") || !item.hasOwnProperty("password") || @@ -1660,12 +1741,12 @@ GameServer.prototype.banIp = function (ip) { // If already disconnected or the ip does not match if (socket == null || !socket.isConnected || !this.checkIpBan(socket.remoteAddress)) return; - + // remove player cells socket.playerTracker.cells.forEach(function (cell) { this.removeNode(cell); }, this); - + // disconnect socket.close(1000, "Banned from server"); var name = socket.playerTracker.getFriendlyName(); @@ -1720,11 +1801,11 @@ GameServer.prototype.startStatsServer = function (port) { if (port < 1) { return; } - + // Create stats this.stats = "Test"; this.getStats(); - + // Show stats this.httpServer = http.createServer(function (req, res) { res.setHeader('Access-Control-Allow-Origin', '*'); @@ -1734,7 +1815,7 @@ GameServer.prototype.startStatsServer = function (port) { this.httpServer.on('error', function (err) { Logger.error("Stats Server: " + err.message); }); - + var getStatsBind = this.getStats.bind(this); this.httpServer.listen(port, function () { // Stats server @@ -1790,8 +1871,7 @@ GameServer.prototype.pingServerTracker = function () { continue; if (socket.isConnected == null) { robotPlayers++; - } - else { + } else { totalPlayers++; if (socket.playerTracker.cells.length > 0) alivePlayers++; @@ -1799,27 +1879,27 @@ GameServer.prototype.pingServerTracker = function () { spectatePlayers++; } } - + // Send Ping... - + // ogar-tracker.tk var obj = { - port: this.config.serverPort, // [mandatory] web socket port which listens for game client connections - name: this.config.serverName, // [mandatory] server name - mode: this.gameMode.name, // [mandatory] game mode - total: totalPlayers, // [mandatory] total online players (server bots is not included!) - alive: alivePlayers, // [mandatory] alive players (server bots is not included!) - spect: spectatePlayers, // [mandatory] spectate players (server bots is not included!) - robot: robotPlayers, // [mandatory] server bots - limit: this.config.serverMaxConnections, // [mandatory] maximum allowed connection count - protocol: 'M', // [mandatory] required protocol id or 'M' for multiprotocol (if all protocols is supported) - uptime: process.uptime() >>> 0, // [mandatory] server uptime [seconds] - w: this.border.width >>> 0, // [mandatory] map border width [integer] - h: this.border.height >>> 0, // [mandatory] map border height [integer] - version: 'MultiOgar ' + pjson.version, // [optional] server version - stpavg: this.updateTimeAvg >>> 0, // [optional] average server loop time - chat: this.config.serverChat ? 1 : 0, // [optional] 0 - chat disabled, 1 - chat enabled - os: os.platform() // [optional] operating system + port: this.config.serverPort, // [mandatory] web socket port which listens for game client connections + name: this.config.serverName, // [mandatory] server name + mode: this.gameMode.name, // [mandatory] game mode + total: totalPlayers, // [mandatory] total online players (server bots is not included!) + alive: alivePlayers, // [mandatory] alive players (server bots is not included!) + spect: spectatePlayers, // [mandatory] spectate players (server bots is not included!) + robot: robotPlayers, // [mandatory] server bots + limit: this.config.serverMaxConnections, // [mandatory] maximum allowed connection count + protocol: 'M', // [mandatory] required protocol id or 'M' for multiprotocol (if all protocols is supported) + uptime: process.uptime() >>> 0, // [mandatory] server uptime [seconds] + w: this.border.width >>> 0, // [mandatory] map border width [integer] + h: this.border.height >>> 0, // [mandatory] map border height [integer] + version: 'MultiOgar ' + pjson.version, // [optional] server version + stpavg: this.updateTimeAvg >>> 0, // [optional] average server loop time + chat: this.config.serverChat ? 1 : 0, // [optional] 0 - chat disabled, 1 - chat enabled + os: os.platform() // [optional] operating system }; trackerRequest({ host: 'ogar-tracker.tk', @@ -1827,29 +1907,29 @@ GameServer.prototype.pingServerTracker = function () { path: '/api/ping', method: 'PUT' }, 'application/json', JSON.stringify(obj)); - + // mivabe.nl // Why don't just to use JSON? var data = 'current_players=' + totalPlayers + - '&alive=' + alivePlayers + - '&spectators=' + spectatePlayers + - '&max_players=' + this.config.serverMaxConnections + - '&sport=' + this.config.serverPort + - '&gamemode=[*] ' + this.gameMode.name + // we add [*] to indicate that this is multi-server - '&agario=true' + // protocol version - '&name=Unnamed Server' + // we cannot use it, because other value will be used as dns name - '&opp=' + os.platform() + ' ' + os.arch() + // "win32 x64" - '&uptime=' + process.uptime() + // Number of seconds server has been running - '&version=MultiOgar ' + pjson.version + - '&start_time=' + this.startTime; + '&alive=' + alivePlayers + + '&spectators=' + spectatePlayers + + '&max_players=' + this.config.serverMaxConnections + + '&sport=' + this.config.serverPort + + '&gamemode=[*] ' + this.gameMode.name + // we add [*] to indicate that this is multi-server + '&agario=true' + // protocol version + '&name=Unnamed Server' + // we cannot use it, because other value will be used as dns name + '&opp=' + os.platform() + ' ' + os.arch() + // "win32 x64" + '&uptime=' + process.uptime() + // Number of seconds server has been running + '&version=MultiOgar ' + pjson.version + + '&start_time=' + this.startTime; trackerRequest({ host: 'ogar.mivabe.nl', port: 80, path: '/master', method: 'POST' }, 'application/x-www-form-urlencoded', data); - + // c0nsume.me trackerRequest({ host: 'c0nsume.me', @@ -1881,4 +1961,4 @@ function trackerRequest(options, type, body) { }); req.write(body); req.end() -}; \ No newline at end of file +}; diff --git a/src/PlayerTracker.js b/src/PlayerTracker.js index bcd294261..b0cd223cf 100644 --- a/src/PlayerTracker.js +++ b/src/PlayerTracker.js @@ -1,9 +1,10 @@ -var Packet = require('./packet'); +var Packet = require('./packet'); var GameServer = require('./GameServer'); var BinaryWriter = require("./packet/BinaryWriter"); var UserRoleEnum = require("./enum/UserRoleEnum"); -function PlayerTracker(gameServer, socket) { +function PlayerTracker(gameServer, socket, proto) { + this.protocol = proto; this.gameServer = gameServer; this.socket = socket; this.pID = -1; @@ -16,7 +17,11 @@ function PlayerTracker(gameServer, socket) { this._nameUtf8 = null; this._nameUnicode = null; this._skinUtf8 = null; - this.color = { r: 0, g: 0, b: 0 }; + this.color = { + r: 0, + g: 0, + b: 0 + }; this.viewNodes = []; this.clientNodes = []; this.cells = []; @@ -26,19 +31,19 @@ function PlayerTracker(gameServer, socket) { this._scaleF = 1; this.isMassChanged = true; this.borderCounter = 0; - + this.mouse = { x: 0, y: 0 }; this.tickLeaderboard = 0; - + this.team = 0; this.spectate = false; - this.freeRoam = false; // Free-roam mode enables player to move in spectate mode + this.freeRoam = false; // Free-roam mode enables player to move in spectate mode this.spectateTarget = null; // Spectate target, null for largest player this.lastSpectateSwitchTick = 0; - + this.centerPos = { x: 0, y: 0 @@ -53,17 +58,17 @@ function PlayerTracker(gameServer, socket) { halfWidth: 0, halfHeight: 0 }; - + // Scramble the coordinate system for anti-raga this.scrambleX = 0; this.scrambleY = 0; this.scrambleId = 0; - + this.connectedTime = 0; this.isMinion = false; this.spawnCounter = 0; this.isMuted = false; - + // Gamemode function if (gameServer) { this.connectedTime = gameServer.stepDateTime; @@ -88,8 +93,7 @@ PlayerTracker.prototype.scramble = function () { this.scrambleX = 0; this.scrambleY = 0; } else { - this.scrambleId = (Math.random() * 0xFFFFFFFF) >>> 0; - // avoid mouse packet limitations + this.scrambleId = 0; var maxx = Math.max(0, 32767 - 1000 - this.gameServer.border.width); var maxy = Math.max(0, 32767 - 1000 - this.gameServer.border.height); var x = maxx * Math.random(); @@ -219,7 +223,7 @@ PlayerTracker.prototype.joinGame = function (name, skin) { this.spectate = false; this.freeRoam = false; this.spectateTarget = null; - + // some old clients don't understand ClearAll message // so we will send update for them if (this.socket.packetHandler.protocol < 6) { @@ -231,8 +235,7 @@ PlayerTracker.prototype.joinGame = function (name, skin) { if (this.gameServer.config.serverScrambleLevel < 2) { // no scramble / lightweight scramble this.socket.sendPacket(new Packet.SetBorder(this, this.gameServer.border)); - } - else if (this.gameServer.config.serverScrambleLevel == 3) { + } else if (this.gameServer.config.serverScrambleLevel == 3) { // Scramble level 3 (no border) // Ruins most known minimaps var border = { @@ -286,7 +289,7 @@ PlayerTracker.prototype.updateTick = function () { if (this.freeRoam || this.getSpectateTarget() == null) { // free roam this.updateCenterFreeRoam(); - this._scale = this.gameServer.config.serverSpectatorScale;//0.25; + this._scale = this.gameServer.config.serverSpectatorScale; //0.25; } else { // spectate target return; @@ -300,16 +303,16 @@ PlayerTracker.prototype.updateTick = function () { }; PlayerTracker.prototype.sendUpdate = function () { - if (this.isRemoved|| + if (this.isRemoved || !this.socket.packetHandler.protocol || - !this.socket.isConnected || - (this.socket._socket.writable != null && !this.socket._socket.writable) || + !this.socket.isConnected || + (this.socket._socket.writable != null && !this.socket._socket.writable) || this.socket.readyState != this.socket.OPEN) { // do not send update for disconnected clients // also do not send if initialization is not complete yet return; } - + if (this.spectate) { if (!this.freeRoam) { // spectate target @@ -323,7 +326,7 @@ PlayerTracker.prototype.sendUpdate = function () { } this.sendCameraPacket(); } - + if (this.gameServer.config.serverScrambleLevel == 2) { // scramble (moving border) if (this.borderCounter == 0) { @@ -339,7 +342,7 @@ PlayerTracker.prototype.sendUpdate = function () { if (this.borderCounter >= 20) this.borderCounter = 0; } - + var delNodes = []; var eatNodes = []; var addNodes = []; @@ -368,11 +371,11 @@ PlayerTracker.prototype.sendUpdate = function () { newIndex++; oldIndex++; } - for (; newIndex < this.viewNodes.length; ) { + for (; newIndex < this.viewNodes.length;) { addNodes.push(this.viewNodes[newIndex]); newIndex++; } - for (; oldIndex < this.clientNodes.length; ) { + for (; oldIndex < this.clientNodes.length;) { var node = this.clientNodes[oldIndex]; if (node.isRemoved && node.getKiller() != null && node.owner != node.getKiller().owner) eatNodes.push(node); @@ -381,15 +384,15 @@ PlayerTracker.prototype.sendUpdate = function () { oldIndex++; } this.clientNodes = this.viewNodes; - + // Send packet this.socket.sendPacket(new Packet.UpdateNodes( - this, - addNodes, - updNodes, - eatNodes, + this, + addNodes, + updNodes, + eatNodes, delNodes)); - + // Update leaderboard if (++this.tickLeaderboard > 25) { // 1 / 0.040 = 25 (once per second) @@ -427,18 +430,18 @@ PlayerTracker.prototype.updateCenterFreeRoam = function () { var dx = this.mouse.x - this.centerPos.x; var dy = this.mouse.y - this.centerPos.y; var squared = dx * dx + dy * dy; - if (squared < 1) return; // stop threshold - + if (squared < 1) return; // stop threshold + // distance var d = Math.sqrt(squared); - + var invd = 1 / d; var nx = dx * invd; var ny = dy * invd; - + var speed = Math.min(d, 32); if (speed <= 0) return; - + var x = this.centerPos.x + nx * speed; var y = this.centerPos.y + ny * speed; this.setCenterPos(x, y); @@ -473,7 +476,7 @@ PlayerTracker.prototype.pressQ = function () { if (tick - this.lastSpectateSwitchTick < 40) return; this.lastSpectateSwitchTick = tick; - + if (this.spectateTarget == null) { this.freeRoam = !this.freeRoam; } @@ -484,8 +487,7 @@ PlayerTracker.prototype.pressQ = function () { PlayerTracker.prototype.pressW = function () { if (this.spectate) { return; - } - else if (this.gameServer.run) { + } else if (this.gameServer.run) { this.gameServer.ejectMass(this); } }; @@ -497,7 +499,7 @@ PlayerTracker.prototype.pressSpace = function () { if (tick - this.lastSpectateSwitchTick < 40) return; this.lastSpectateSwitchTick = tick; - + // Space doesn't work for freeRoam mode if (this.freeRoam || this.gameServer.largestClient == null) return; @@ -557,7 +559,9 @@ PlayerTracker.prototype.updateVisibleNodes = function () { }); } this.viewNodes = this.viewNodes.concat(this.cells); - this.viewNodes.sort(function (a, b) { return a.nodeId - b.nodeId; }); + this.viewNodes.sort(function (a, b) { + return a.nodeId - b.nodeId; + }); }; PlayerTracker.prototype.setCenterPos = function (x, y) { diff --git a/src/gameserver.ini b/src/gameserver.ini index 83b25554b..c1b0b65d7 100644 --- a/src/gameserver.ini +++ b/src/gameserver.ini @@ -1,4 +1,4 @@ -# MultiOgar configurations file +# MultiOgar configurations file # Lines starting with number sign (#) are comments # [NOTE] @@ -50,7 +50,7 @@ serverIpLimit = 4 serverMinionIgnoreTime = 30 serverMinionThreshold = 10 serverMinionInterval = 1000 -serverPort = 443 +serverPort = 8080 serverBind = "0.0.0.0" serverTracker = 0 serverGamemode = 0 @@ -59,9 +59,9 @@ serverViewBaseX = 1920 serverViewBaseY = 1080 serverMinScale = 0.15 serverSpectatorScale = 0.4 -serverStatsPort = 88 +serverStatsPort = -1 serverStatsUpdate = 60 -serverScrambleLevel = 2 +serverScrambleLevel = 0 serverMaxLB = 10 serverChat = 1 serverChatAscii = 1 diff --git a/src/generateProtocols.js b/src/generateProtocols.js index 7fff6087f..392e27454 100644 --- a/src/generateProtocols.js +++ b/src/generateProtocols.js @@ -44,7 +44,7 @@ module.exports = function (amount, call) { loading("Generating secure protocol.") var results = []; - var client = fs.readFileSync(__dirname + '/../client/js/game.js', 'utf8'); + var client = fs.readFileSync(__dirname + '/../client/main_out.js', 'utf8'); var childs = []; for (var i = 0; i < cpus; i++) { childs.push(Child.fork(__dirname + '/generatorChild.js')) @@ -88,11 +88,12 @@ module.exports = function (amount, call) { if (results.length === amount) { results.forEach((d, i) => { d.id = i; + d.update = new Function('data1', d.UNodesProtocol); }) childs.forEach((child) => { child.send({ type: 'stop' - }) + }); }); loading('Done! ' + results.length + '/' + amount); console.log('') @@ -104,29 +105,32 @@ module.exports = function (amount, call) { child.send({ type: 'generate', client: client, + amount: a, updateNodesStruct: { - deleteUnits: [ - "int 0 4000000000" - ], - addUnits: [ + eat: [ { - id: "int 0 4000000000", - ownerID: "int 0 4000000000", - x: "int 0 4000000000", - y: "int 0 4000000000", - rotation: "int 0 255", - type: "int 0 100" - } - ], - moveUnits: [ + killer: 'int 0 4000000000', + killed: 'int 0 4000000000' + } + ], + update: [ { - id: "int 0 4000000000", - x: "int -32000 32000", - y: "int -32000 32000", + id: 'int 0 4000000000', + posX: 'int -32000 32000', + posY: 'int -32000 32000', + size: 'int -32000 32000', + r: 'int uint8', + g: 'int uint8', + b: 'int uint8', + flags: 'int 0 50', + skin: 'string 8', + name: 'string 16', + } + ], + remove: [ + 'int 0 4000000000' + ] } - ] - }, - amount: a }) } diff --git a/src/generatorChild.js b/src/generatorChild.js index 56b75a638..5e066d1fe 100644 --- a/src/generatorChild.js +++ b/src/generatorChild.js @@ -18,7 +18,7 @@ */ var JavaScriptObfuscator = require('javascript-obfuscator'); -var SimpleProtocols = require('../modules/SimpleProtocols/index.js'); +var SimpleProtocols = require('./modules/SimpleProtocols/index.js'); var UglifyJS = require("uglify-es"); var fs = require('fs'); @@ -63,16 +63,14 @@ process.on('message', (msg, socket) => { switch (msg.type) { case 'generate': - msg.client; - msg.updateNodesStruct; for (var i = 0; i < msg.amount; i++) { var updatenodes = SimpleProtocols(msg.updateNodesStruct); var nclient = msg.client.replace('// INSERT PROTOCOL', function () { return updatenodes.getb }) - nclient = compile(nclient); - nclient = obfuscate(nclient); + //nclient = compile(nclient); + //nclient = obfuscate(nclient); generated.push({ UNodesProtocol: updatenodes.set, UNodesProtocolBrowser: updatenodes.getb, diff --git a/src/index.js b/src/index.js index d5febef5d..ffa19a5f4 100644 --- a/src/index.js +++ b/src/index.js @@ -1,88 +1,137 @@ -// Imports -var pjson = require('../package.json'); -var Logger = require('./modules/Logger'); -var Commands = require('./modules/CommandList'); -var GameServer = require('./GameServer'); - -// Init variables -var showConsole = true; - -// Start msg -Logger.start(); - -process.on('exit', function (code) { - Logger.debug("process.exit(" + code + ")"); - Logger.shutdown(); -}); - -process.on('uncaughtException', function (err) { - Logger.fatal(err.stack); - process.exit(1); -}); - -Logger.info("\u001B[1m\u001B[32mMultiOgar " + pjson.version + "\u001B[37m - An open source multi-protocol ogar server\u001B[0m"); - - -// Handle arguments -process.argv.forEach(function (val) { - if (val == "--noconsole") { - showConsole = false; - } else if (val == "--help") { - console.log("Proper Usage: node index.js"); - console.log(" --noconsole Disables the console"); - console.log(" --help Help menu."); - console.log(""); - } -}); - -// Run Ogar -var gameServer = new GameServer(); -gameServer.start(); -// Add command handler -gameServer.commands = Commands.list; -// Initialize the server console -if (showConsole) { - var readline = require('readline'); - var in_ = readline.createInterface({ - input: process.stdin, - output: process.stdout - }); - setTimeout(prompt, 100); -} - -// Console functions - -function prompt() { - in_.question(">", function (str) { - try { - parseCommands(str); - } catch (err) { - Logger.error(err.stack); - } finally { - setTimeout(prompt, 0); - } - }); -} - -function parseCommands(str) { - // Log the string - Logger.write(">" + str); - - // Don't process ENTER - if (str === '') - return; - - // Splits the string - var split = str.split(" "); - - // Process the first string value - var first = split[0].toLowerCase(); - - // Get command function - var execute = gameServer.commands[first]; - if (typeof execute != 'undefined') { - execute(gameServer, split); - } else { - Logger.warn("Invalid Command!"); - } -} + Map.prototype.every = function (c) { + var a = this.entries() + var b; + while (b = a.next().value) { + if (!c(b[1], b[0])) return false; + } + + return true; + } + Map.prototype.toArray = function () { + var array = []; + this.forEach(function (a) { + array.push(a) + }) + return array + } + + Map.prototype.map = function (c) { + var f = new Map(); + var a = this.entries() + var b; + while (b = a.next().value) { + f.set(b[0], c(b[1], b[0])) + } + return f; + + } + Map.prototype.filter = function (c) { + var f = new Map(); + var a = this.entries() + var b; + while (b = a.next().value) { + if (c(b[1], b[0])) f.set(b[0], b[1]) + } + return f; + + } + Map.prototype.peek = function () { + var a = this.entries(); + var b = a.next().value; + return (b) ? b[1] : false; + } + + + // Imports + var pjson = require('../package.json'); + var Logger = require('./modules/Logger'); + var Commands = require('./modules/CommandList'); + var GameServer = require('./GameServer'); + + // Init variables + var showConsole = true; + + // Start msg + Logger.start(); + + process.on('exit', function (code) { + Logger.debug("process.exit(" + code + ")"); + Logger.shutdown(); + }); + + process.on('uncaughtException', function (err) { + Logger.fatal(err.stack); + process.exit(1); + }); + + Logger.info("\u001B[1m\u001B[32mMultiOgar " + pjson.version + "\u001B[37m - An open source multi-protocol ogar server\u001B[0m"); + + + // Handle arguments + process.argv.forEach(function (val) { + if (val == "--noconsole") { + showConsole = false; + } else if (val == "--help") { + console.log("Proper Usage: node index.js"); + console.log(" --noconsole Disables the console"); + console.log(" --help Help menu."); + console.log(""); + } + }); + + // Run Ogar + var p = require('./generateProtocols.js'); + p(10, function (protocols) { + var gameServer = new GameServer(protocols); + + + gameServer.start(); + // Add command handler + gameServer.commands = Commands.list; + // Initialize the server console + if (showConsole) { + var readline = require('readline'); + var in_ = readline.createInterface({ + input: process.stdin, + output: process.stdout + }); + setTimeout(prompt, 100); + } + + // Console functions + + function prompt() { + in_.question(">", function (str) { + try { + parseCommands(str); + } catch (err) { + Logger.error(err.stack); + } finally { + setTimeout(prompt, 0); + } + }); + } + + function parseCommands(str) { + // Log the string + Logger.write(">" + str); + + // Don't process ENTER + if (str === '') + return; + + // Splits the string + var split = str.split(" "); + + // Process the first string value + var first = split[0].toLowerCase(); + + // Get command function + var execute = gameServer.commands[first]; + if (typeof execute != 'undefined') { + execute(gameServer, split); + } else { + Logger.warn("Invalid Command!"); + } + } + }) diff --git a/src/modules/SimpleProtocols/assets/fastBuffersBrowser.js b/src/modules/SimpleProtocols/assets/fastBuffersBrowser.js index 7973f6e64..5f4f9f202 100644 --- a/src/modules/SimpleProtocols/assets/fastBuffersBrowser.js +++ b/src/modules/SimpleProtocols/assets/fastBuffersBrowser.js @@ -17,9 +17,9 @@ */ module.exports = function (type) { var FastBuffers = { - reader: '\nvar Reader = function (buf) {\n\ - this.index = 0;\n\ - this.buffer = new DataView(buf);\n\ + reader: '\nvar Reader = function (buf, ind) {\n\ + this.index = ind || 0;\n\ + this.buffer = buf;\n\ }\n\ Reader.prototype.readDynamic = function() {\n\ var num = 0;\n\ diff --git a/src/modules/SimpleProtocols/lib/integerManager.js b/src/modules/SimpleProtocols/lib/integerManager.js index 0fc91329d..67bb0041c 100644 --- a/src/modules/SimpleProtocols/lib/integerManager.js +++ b/src/modules/SimpleProtocols/lib/integerManager.js @@ -19,7 +19,8 @@ module.exports = function (obj, data, name, type, lvl, opt) { var split = obj.split(" "); var get, set, count; - + var off = "", + off2 = "" var dtobj = { dynamic: function () { get = 'reader.readDynamic()' @@ -90,9 +91,8 @@ module.exports = function (obj, data, name, type, lvl, opt) { mindiff = 255 - diff; } - var off = "", - off2 = "", - omin = min; + + var omin = min; if (opt.scrambleNumbers) { var offset = Math.floor(Math.random() * mindiff); min += offset; diff --git a/src/modules/SimpleProtocols/lib/parser.js b/src/modules/SimpleProtocols/lib/parser.js index cd3c7395b..bd679a7f6 100644 --- a/src/modules/SimpleProtocols/lib/parser.js +++ b/src/modules/SimpleProtocols/lib/parser.js @@ -113,7 +113,7 @@ module.exports = function (object, options) { data.get.push(rc4); data.count.push(rc4); } - //data.get.push("var reader = new Reader(buf);"); + data.get.push("var reader = new Reader(buf,ind);"); data.count.push("var byteLen = 0;") // data.count.push("var ifs = [];") @@ -214,7 +214,7 @@ module.exports = function (object, options) { if (data.if) data.count.push("byteLen += Math.ceil(ifs.length / 7) + 1") data.count.push("var writer = new Writer(byteLen + 1);") - data.count.push("writer.writeUInt8(2);") + data.count.push("writer.writeUInt8(16);") if (data.if) data.count.push("setIfs(writer,ifs);"); if (data.if) { @@ -224,9 +224,9 @@ module.exports = function (object, options) { var getCode = sprintf(data.get.toString(), "", "") var setCode = sprintf(data.count.toString(), "", "") + "\n" + data.set.toString() } - var get = "function " + options.getname + "(reader) {\n" + getCode + "}"; - var set = "function " + options.setname + "(data1) {\n" + FastBuffers.NodeJS("writer") + "\n" + setCode + "}"; - var getBrowser = "function " + options.getname + "(reader) {\n" + getCode + "}"; + var get = "function " + options.getname + "(buf,ind) {\n" + FastBuffers.NodeJS("reader") + getCode + "}"; + var set = FastBuffers.NodeJS("writer") + "\n" + setCode; + var getBrowser = "function " + options.getname + "(buf,ind) {\n" + FastBuffers.Browser("reader") + getCode + "}"; var setBrowser = "function " + options.setname + "(data1) {" + FastBuffers.Browser("writer") + "\n" + setCode + "}"; if (options.pack) { diff --git a/src/packet/UpdateNodes.js b/src/packet/UpdateNodes.js index 1931ccd6d..c0659056b 100644 --- a/src/packet/UpdateNodes.js +++ b/src/packet/UpdateNodes.js @@ -1,8 +1,7 @@ -// Import +// Import var BinaryWriter = require("./BinaryWriter"); var Logger = require('../modules/Logger'); -var sharedWriter = new BinaryWriter(128*1024); // for about 25000 cells per client function UpdateNodes(playerTracker, addNodes, updNodes, eatNodes, delNodes) { this.playerTracker = playerTracker; @@ -15,288 +14,93 @@ function UpdateNodes(playerTracker, addNodes, updNodes, eatNodes, delNodes) { module.exports = UpdateNodes; UpdateNodes.prototype.build = function (protocol) { - if (!protocol) return null; - - var writer = sharedWriter; - writer.reset(); - writer.writeUInt8(0x10); // Packet ID - this.writeEatItems(writer); - - if (protocol < 5) this.writeUpdateItems4(writer); - else if (protocol == 5) this.writeUpdateItems5(writer); - else this.writeUpdateItems6(writer); - - this.writeRemoveItems(writer, protocol); - return writer.toBuffer(); -}; + var obj = { + eat: [], + update: [], + remove: [] + }; -// protocol 4 -UpdateNodes.prototype.writeUpdateItems4 = function (writer) { - var scrambleX = this.playerTracker.scrambleX; - var scrambleY = this.playerTracker.scrambleY; - var scrambleId = this.playerTracker.scrambleId; - - for (var i = 0; i < this.updNodes.length; i++) { - var node = this.updNodes[i]; - if (node.nodeId == 0) - continue; - var cellX = node.position.x + scrambleX; - var cellY = node.position.y + scrambleY; - - // Write update record - writer.writeUInt32((node.nodeId ^ scrambleId) >>> 0); // Cell ID - writer.writeInt16(cellX >> 0); // Coordinate X - writer.writeInt16(cellY >> 0); // Coordinate Y - writer.writeUInt16(node.getSize() >>> 0); // Cell Size (not to be confused with mass, because mass = size*size/100) - var color = node.getColor(); - writer.writeUInt8(color.r >>> 0); // Color R - writer.writeUInt8(color.g >>> 0); // Color G - writer.writeUInt8(color.b >>> 0); // Color B - - var flags = 0; - if (node.isSpiked) - flags |= 0x01; // isVirus - if (node.isAgitated) - flags |= 0x10; // isAgitated - if (node.cellType == 3) - flags |= 0x20; // isEjected - writer.writeUInt8(flags >>> 0); // Flags - - writer.writeUInt16(0); // Name - } - for (var i = 0; i < this.addNodes.length; i++) { - var node = this.addNodes[i]; - if (node.nodeId == 0) - continue; - var cellX = node.position.x + scrambleX; - var cellY = node.position.y + scrambleY; - var cellName = null; - if (node.owner) { - cellName = node.owner.getNameUnicode(); + for (var i = 0; i < this.eatNodes.length; i++) { + var node = this.eatNodes[i]; + var hunterId = 0; + if (node.getKiller()) { + hunterId = node.getKiller().nodeId; } - - // Write update record - writer.writeUInt32((node.nodeId ^ scrambleId) >>> 0); // Cell ID - writer.writeInt16(cellX >> 0); // Coordinate X - writer.writeInt16(cellY >> 0); // Coordinate Y - writer.writeUInt16(node.getSize() >>> 0); // Cell Size (not to be confused with mass, because mass = size*size/100) - var color = node.getColor(); - writer.writeUInt8(color.r >>> 0); // Color R - writer.writeUInt8(color.g >>> 0); // Color G - writer.writeUInt8(color.b >>> 0); // Color B - - var flags = 0; - if (node.isSpiked) - flags |= 0x01; // isVirus - if (node.isAgitated) - flags |= 0x10; // isAgitated - if (node.cellType == 3) - flags |= 0x20; // isEjected - writer.writeUInt8(flags >>> 0); // Flags - - if (cellName != null) - writer.writeBytes(cellName); // Name - else - writer.writeUInt16(0); // Name + obj.eat.push({ + killer: hunterId, + killed: node.nodeId + }) } - writer.writeUInt32(0); // Cell Update record terminator -}; - -// protocol 5 -UpdateNodes.prototype.writeUpdateItems5 = function (writer) { - var scrambleX = this.playerTracker.scrambleX; - var scrambleY = this.playerTracker.scrambleY; - var scrambleId = this.playerTracker.scrambleId; - for (var i = 0; i < this.updNodes.length; i++) { var node = this.updNodes[i]; if (node.nodeId == 0) continue; - var cellX = node.position.x + scrambleX; - var cellY = node.position.y + scrambleY; - - // Write update record - writer.writeUInt32((node.nodeId ^ scrambleId) >>> 0); // Cell ID - writer.writeInt32(cellX >> 0); // Coordinate X - writer.writeInt32(cellY >> 0); // Coordinate Y - writer.writeUInt16(node.getSize() >>> 0); // Cell Size (not to be confused with mass, because mass = size*size/100) + var cellX = node.position.x; + var cellY = node.position.y; var color = node.getColor(); - writer.writeUInt8(color.r >>> 0); // Color R - writer.writeUInt8(color.g >>> 0); // Color G - writer.writeUInt8(color.b >>> 0); // Color B - var flags = 0; if (node.isSpiked) - flags |= 0x01; // isVirus + flags |= 0x01; // isVirus if (node.isAgitated) - flags |= 0x10; // isAgitated + flags |= 0x10; // isAgitated if (node.cellType == 3) - flags |= 0x20; // isEjected - writer.writeUInt8(flags >>> 0); // Flags - - writer.writeUInt16(0); // Cell Name + flags |= 0x20; // isEjected + + obj.update.push({ + id: node.nodeId, + posX: Math.floor(cellX), + posY: Math.floor(cellY), + size: Math.floor(node.getSize()), + r: color.r, + g: color.g, + b: color.b, + flags: flags, + name: '', + skin: '' + }) } for (var i = 0; i < this.addNodes.length; i++) { var node = this.addNodes[i]; if (node.nodeId == 0) continue; - - var cellX = node.position.x + scrambleX; - var cellY = node.position.y + scrambleY; - var skinName = null; + var cellX = node.position.x; + var cellY = node.position.y; var cellName = null; if (node.owner) { - skinName = node.owner.getSkinUtf8(); cellName = node.owner.getNameUnicode(); } - - // Write update record - writer.writeUInt32((node.nodeId ^ scrambleId) >>> 0); // Cell ID - writer.writeInt32(cellX >> 0); // Coordinate X - writer.writeInt32(cellY >> 0); // Coordinate Y - writer.writeUInt16(node.getSize() >>> 0); // Cell Size (not to be confused with mass, because mass = size*size/100) var color = node.getColor(); - writer.writeUInt8(color.r >>> 0); // Color R - writer.writeUInt8(color.g >>> 0); // Color G - writer.writeUInt8(color.b >>> 0); // Color B - - var flags = 0; - if (node.isSpiked) - flags |= 0x01; // isVirus - if (skinName != null) - flags |= 0x04; // isSkinPresent - if (node.isAgitated) - flags |= 0x10; // isAgitated - if (node.cellType == 3) - flags |= 0x20; // isEjected - writer.writeUInt8(flags >>> 0); // Flags - - if (flags & 0x04) - writer.writeBytes(skinName); // Skin Name in UTF8 - - if (cellName != null) - writer.writeBytes(cellName); // Name - else - writer.writeUInt16(0); // Name - } - writer.writeUInt32(0 >> 0); // Cell Update record terminator -}; -// protocol 6 -UpdateNodes.prototype.writeUpdateItems6 = function (writer) { - var scrambleX = this.playerTracker.scrambleX; - var scrambleY = this.playerTracker.scrambleY; - var scrambleId = this.playerTracker.scrambleId; - for (var i = 0; i < this.updNodes.length; i++) { - var node = this.updNodes[i]; - if (node.nodeId == 0) - continue; - - var cellX = node.position.x + scrambleX; - var cellY = node.position.y + scrambleY; - - // Write update record - writer.writeUInt32((node.nodeId ^ scrambleId) >>> 0); // Cell ID - writer.writeInt32(cellX >> 0); // Coordinate X - writer.writeInt32(cellY >> 0); // Coordinate Y - writer.writeUInt16(node.getSize() >>> 0); // Cell Size (not to be confused with mass, because mass = size*size/100) - - var flags = 0; - if (node.isSpiked) - flags |= 0x01; // isVirus - if (node.cellType == 0) - flags |= 0x02; // isColorPresent (for players only) - if (node.isAgitated) - flags |= 0x10; // isAgitated - if (node.cellType == 3) - flags |= 0x20; // isEjected - writer.writeUInt8(flags >>> 0); // Flags - - if (flags & 0x02) { - var color = node.getColor(); - writer.writeUInt8(color.r >>> 0); // Color R - writer.writeUInt8(color.g >>> 0); // Color G - writer.writeUInt8(color.b >>> 0); // Color B - } - } - for (var i = 0; i < this.addNodes.length; i++) { - var node = this.addNodes[i]; - if (node.nodeId == 0) - continue; - - var cellX = node.position.x + scrambleX; - var cellY = node.position.y + scrambleY; - var skinName = null; - var cellName = null; - if (node.owner) { - skinName = node.owner.getSkinUtf8(); - cellName = node.owner.getNameUtf8(); - } - - // Write update record - writer.writeUInt32((node.nodeId ^ scrambleId) >>> 0); // Cell ID - writer.writeInt32(cellX >> 0); // Coordinate X - writer.writeInt32(cellY >> 0); // Coordinate Y - writer.writeUInt16(node.getSize() >>> 0); // Cell Size (not to be confused with mass, because mass = size*size/100) - var flags = 0; if (node.isSpiked) - flags |= 0x01; // isVirus - if (true) - flags |= 0x02; // isColorPresent (always for added) - if (skinName != null) - flags |= 0x04; // isSkinPresent - if (cellName != null) - flags |= 0x08; // isNamePresent + flags |= 0x01; // isVirus if (node.isAgitated) - flags |= 0x10; // isAgitated + flags |= 0x10; // isAgitated if (node.cellType == 3) - flags |= 0x20; // isEjected - writer.writeUInt8(flags >>> 0); // Flags - - if (flags & 0x02) { - var color = node.getColor(); - writer.writeUInt8(color.r >>> 0); // Color R - writer.writeUInt8(color.g >>> 0); // Color G - writer.writeUInt8(color.b >>> 0); // Color B - } - if (flags & 0x04) - writer.writeBytes(skinName); // Skin Name in UTF8 - if (flags & 0x08) - writer.writeBytes(cellName); // Cell Name in UTF8 - } - writer.writeUInt32(0); // Cell Update record terminator -}; + flags |= 0x20; // isEjected + + obj.update.push({ + id: node.nodeId, + posX: Math.floor(cellX), + posY: Math.floor(cellY), + size: Math.floor(node.getSize()), + r: color.r, + g: color.g, + b: color.b, + flags: flags, + name: cellName || '', + skin: '' + }) -UpdateNodes.prototype.writeEatItems = function (writer) { - var scrambleId = this.playerTracker.scrambleId; - - writer.writeUInt16(this.eatNodes.length >>> 0); // EatRecordCount - for (var i = 0; i < this.eatNodes.length; i++) { - var node = this.eatNodes[i]; - var hunterId = 0; - if (node.getKiller()) { - hunterId = node.getKiller().nodeId; - } - writer.writeUInt32((hunterId ^ scrambleId) >>> 0); // Hunter ID - writer.writeUInt32((node.nodeId ^ scrambleId) >>> 0); // Prey ID } -}; -UpdateNodes.prototype.writeRemoveItems = function (writer, protocol) { - var scrambleId = this.playerTracker.scrambleId; - - var length = this.eatNodes.length + this.delNodes.length; - if (protocol < 6) - writer.writeUInt32(length >>> 0); // RemoveRecordCount - else - writer.writeUInt16(length >>> 0); // RemoveRecordCount for (var i = 0; i < this.eatNodes.length; i++) { var node = this.eatNodes[i]; - writer.writeUInt32((node.nodeId ^ scrambleId) >>> 0); // Cell ID + obj.remove.push(node.nodeId); // Cell ID } for (var i = 0; i < this.delNodes.length; i++) { var node = this.delNodes[i]; - writer.writeUInt32((node.nodeId ^ scrambleId) >>> 0); // Cell ID + obj.remove.push(node.nodeId); // Cell ID } } + return this.playerTracker.protocol.update(obj); };