@ -1 +1,2 @@ |
|||||||
.idea |
.idea |
||||||
|
.env |
||||||
|
@ -1,33 +0,0 @@ |
|||||||
'use strict';
|
|
||||||
|
|
||||||
function keyPressed(){
|
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
function keyReleased(){ |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
function mouseMoved(){ |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
function mouseDragged(){ |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
function mousePressed(){ |
|
||||||
if (game) |
|
||||||
if (!game.winId) |
|
||||||
game.onMouseDown(); |
|
||||||
} |
|
||||||
|
|
||||||
function mouseReleased(){ |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
window.onresize = () => { |
|
||||||
let w = $('#canvas-holder').width(); |
|
||||||
let h = $('#canvas-holder').height(); |
|
||||||
resizeCanvas(w, h); |
|
||||||
} |
|
@ -1,104 +0,0 @@ |
|||||||
'use strict'; |
|
||||||
|
|
||||||
let projectName = "chainreact"; |
|
||||||
|
|
||||||
let debug = false, |
|
||||||
productionMode = false, |
|
||||||
font, |
|
||||||
localSettings, |
|
||||||
loader; |
|
||||||
|
|
||||||
//Only for online games
|
|
||||||
let socket; |
|
||||||
|
|
||||||
let game; |
|
||||||
let gemContentImage; |
|
||||||
let gemBorderImage; |
|
||||||
let gemContentGraphics = {}; |
|
||||||
|
|
||||||
let antiCacheQuery = '?_=' + new Date().getTime(); |
|
||||||
|
|
||||||
function preload(){ |
|
||||||
localSettings = loadJSON('data/settings/settings.json' + antiCacheQuery, json => { |
|
||||||
console.log('Local settings loaded: ', json); |
|
||||||
}, error => { |
|
||||||
console.log('Local settings failed: ', error); |
|
||||||
}); |
|
||||||
|
|
||||||
font = loadFont('data/styles/Tajawal/Tajawal-Regular.ttf', json => { |
|
||||||
console.log('Local font loaded: ', json); |
|
||||||
}, error => { |
|
||||||
console.log('Local font failed: ', error); |
|
||||||
}); |
|
||||||
|
|
||||||
gemContentImage = loadImage('data/images/gem_content.png', img => { |
|
||||||
console.log('Image loaded: ', img); |
|
||||||
}, error => { |
|
||||||
console.log('Image failed: ' , error); |
|
||||||
}); |
|
||||||
|
|
||||||
gemBorderImage = loadImage('data/images/gem_border.png', img => { |
|
||||||
console.log('Image loaded: ', img); |
|
||||||
}, error => { |
|
||||||
console.log('Image failed: ' , error); |
|
||||||
}); |
|
||||||
|
|
||||||
loadJSON('data/settings/libraries.json' + antiCacheQuery, json => { |
|
||||||
loadScripts(json) |
|
||||||
console.log('BenjoCraeft library scripts loaded: ', json) |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
function setup(){ |
|
||||||
canvasSetup(); |
|
||||||
interfaceSetup(); |
|
||||||
} |
|
||||||
|
|
||||||
function draw(){ |
|
||||||
background(0, 0, 10); |
|
||||||
|
|
||||||
if (game){ |
|
||||||
game.display(); |
|
||||||
game.update(); |
|
||||||
} |
|
||||||
|
|
||||||
if (loader){ |
|
||||||
loader.update(); |
|
||||||
loader.display(); |
|
||||||
} |
|
||||||
|
|
||||||
if (debug) debugInformation(); |
|
||||||
} |
|
||||||
|
|
||||||
function canvasSetup(){ |
|
||||||
setFrameRate(60); |
|
||||||
let w = $('#canvas-holder').width(), |
|
||||||
h = $('#canvas-holder').height(); |
|
||||||
let canvas = createCanvas(w, h); |
|
||||||
canvas.parent('canvas-holder'); |
|
||||||
textFont(font); |
|
||||||
textAlign(CENTER, CENTER); |
|
||||||
imageMode(CENTER); |
|
||||||
colorMode(HSB); |
|
||||||
} |
|
||||||
|
|
||||||
function interfaceSetup(){ |
|
||||||
window.onresize(); |
|
||||||
setInterval(() => window.onresize(), 500); |
|
||||||
$('#version').html(localSettings.project.version); |
|
||||||
$('#start_feedback, #give_feedback').attr('disabled', 'disabled'); |
|
||||||
nameTyped($('#main > input')); |
|
||||||
|
|
||||||
$('#main').fadeIn(menuesFadeTime); |
|
||||||
} |
|
||||||
|
|
||||||
function loadScripts(libs){ |
|
||||||
for (let script in libs){ |
|
||||||
if (libs[script]){ |
|
||||||
let url = '/lib/benjocraeft/' + script + '.js' |
|
||||||
$.getScript(url, () => { |
|
||||||
console.log('Successfully loaded script: ', url) |
|
||||||
}); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
Before Width: | Height: | Size: 318 B After Width: | Height: | Size: 318 B |
Before Width: | Height: | Size: 679 B After Width: | Height: | Size: 679 B |
Before Width: | Height: | Size: 585 B After Width: | Height: | Size: 585 B |
Before Width: | Height: | Size: 782 B After Width: | Height: | Size: 782 B |
@ -0,0 +1,14 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
|
||||||
|
p.mousePressed = () => { |
||||||
|
if (game) |
||||||
|
if (!game.winId) |
||||||
|
game.onMouseDown(); |
||||||
|
} |
||||||
|
|
||||||
|
window.onresize = () => { |
||||||
|
let w = $('#canvas-holder').width(); |
||||||
|
let h = $('#canvas-holder').height(); |
||||||
|
p.resizeCanvas(w, h); |
||||||
|
} |
@ -0,0 +1,100 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
let projectName = "chainreact"; |
||||||
|
|
||||||
|
let debug = false, |
||||||
|
productionMode = false, |
||||||
|
font, |
||||||
|
localSettings, |
||||||
|
loader; |
||||||
|
|
||||||
|
//Only for online games
|
||||||
|
let socket; |
||||||
|
|
||||||
|
let game; |
||||||
|
let gemContentImage; |
||||||
|
let gemBorderImage; |
||||||
|
let gemContentGraphics = {}; |
||||||
|
|
||||||
|
let antiCacheQuery = '?_=' + new Date().getTime(); |
||||||
|
|
||||||
|
let p; |
||||||
|
|
||||||
|
p = new p5(s => { |
||||||
|
s.preload = () => { |
||||||
|
localSettings = p.loadJSON('data/settings/settings.json' + antiCacheQuery, json => { |
||||||
|
console.log('Local settings loaded: ', json); |
||||||
|
}, error => { |
||||||
|
console.log('Local settings failed: ', error); |
||||||
|
}); |
||||||
|
|
||||||
|
font = p.loadFont('data/styles/Tajawal/Tajawal-Regular.ttf', json => { |
||||||
|
console.log('Local font loaded: ', json); |
||||||
|
}, error => { |
||||||
|
console.log('Local font failed: ', error); |
||||||
|
}); |
||||||
|
|
||||||
|
gemContentImage = p.loadImage('data/images/gem_content.png', img => { |
||||||
|
console.log('Image loaded: ', img); |
||||||
|
}, error => { |
||||||
|
console.log('Image failed: ', error); |
||||||
|
}); |
||||||
|
|
||||||
|
gemBorderImage = p.loadImage('data/images/gem_border.png', img => { |
||||||
|
console.log('Image loaded: ', img); |
||||||
|
}, error => { |
||||||
|
console.log('Image failed: ', error); |
||||||
|
}); |
||||||
|
|
||||||
|
p.loadJSON('data/settings/libraries.json' + antiCacheQuery, json => { |
||||||
|
loadScripts(json) |
||||||
|
console.log('BenjoCraeft library scripts loaded: ', json) |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
s.setup = () => { |
||||||
|
canvasSetup(); |
||||||
|
interfaceSetup(); |
||||||
|
} |
||||||
|
|
||||||
|
s.draw = () => { |
||||||
|
p.background(0, 0, 10); |
||||||
|
if (game){ |
||||||
|
game.display(); |
||||||
|
game.update(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
}, null, null); |
||||||
|
|
||||||
|
function canvasSetup(){ |
||||||
|
p.setFrameRate(60); |
||||||
|
let w = $('#canvas-holder').width(), |
||||||
|
h = $('#canvas-holder').height(); |
||||||
|
let canvas = p.createCanvas(w, h); |
||||||
|
canvas.parent('canvas-holder'); |
||||||
|
p.textFont(font); |
||||||
|
p.textAlign(p.CENTER, p.CENTER); |
||||||
|
p.imageMode(p.CENTER); |
||||||
|
p.colorMode(p.HSB); |
||||||
|
} |
||||||
|
|
||||||
|
function interfaceSetup(){ |
||||||
|
window.onresize(); |
||||||
|
setInterval(() => window.onresize(), 500); |
||||||
|
$('#start_feedback, #give_feedback').attr('disabled', 'disabled'); |
||||||
|
nameTyped($('#main > input')); |
||||||
|
|
||||||
|
$('#main').fadeIn(menuesFadeTime); |
||||||
|
} |
||||||
|
|
||||||
|
function loadScripts(libs){ |
||||||
|
for (let script in libs){ |
||||||
|
if (libs[script]){ |
||||||
|
let url = '/lib/benjocraeft/' + script + '.js' |
||||||
|
$.getScript(url, () => { |
||||||
|
console.log('Successfully loaded script: ', url) |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
echo parse_ini_file("../../../server/.env")["HTTPS_PORT"]; |
@ -1,6 +1,5 @@ |
|||||||
{ |
{ |
||||||
"project": { |
"project": { |
||||||
"version": "v1.2.3", |
|
||||||
"name": "chainreact", |
"name": "chainreact", |
||||||
"author": "BenjoCraeft", |
"author": "BenjoCraeft", |
||||||
"playerCounts": [1, 2, 3, 4], |
"playerCounts": [1, 2, 3, 4], |
@ -1,16 +1,11 @@ |
|||||||
<!-- Web project created by Benjo Craeft (alias) --> |
|
||||||
<!DOCTYPE html> |
<!DOCTYPE html> |
||||||
<html lang="en"> |
<html lang="en"> |
||||||
<head> |
<head> |
||||||
<meta charset="utf-8"> |
<meta charset="utf-8"> |
||||||
<script src="/lib/socket.io/socket.io.min.js" type="text/javascript"></script> |
<script src="https://cdn.socket.io/4.4.1/socket.io.min.js" type="text/javascript"></script> |
||||||
<script src="/lib/socket.io/socket.io-p2p.min.js" type="text/javascript"></script> |
<script src="data/lib/socketiop2p.min.js" type="text/javascript"></script> |
||||||
<script src="/lib/p5/p5.min.js" type="text/javascript"></script> |
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.min.js" type="text/javascript"></script> |
||||||
<script src="/lib/p5/p5.dom.min.js" type="text/javascript"></script> |
<script src="https://code.jquery.com/jquery-3.6.4.min.js" type="text/javascript"></script> |
||||||
<script src="/lib/p5/p5.sound.min.js" type="text/javascript"></script> |
|
||||||
<script src="/lib/jquery/jquery.min.js" type="text/javascript"></script> |
|
||||||
<script src="/lib/jquery/jquery-ui.min.js" type="text/javascript"></script> |
|
||||||
<script src="/lib/vue/vue.js" type="text/javascript"></script> |
|
||||||
<script src="data/scripts/init.js" type="text/javascript"></script> |
<script src="data/scripts/init.js" type="text/javascript"></script> |
||||||
<script src="data/scripts/events.js" type="text/javascript"></script> |
<script src="data/scripts/events.js" type="text/javascript"></script> |
||||||
<script src="data/scripts/online.js" type="text/javascript"></script> |
<script src="data/scripts/online.js" type="text/javascript"></script> |
After Width: | Height: | Size: 169 KiB |
@ -0,0 +1,3 @@ |
|||||||
|
out |
||||||
|
logs |
||||||
|
node_modules |
@ -0,0 +1,439 @@ |
|||||||
|
{ |
||||||
|
"name": "chainreact-server", |
||||||
|
"version": "2.0", |
||||||
|
"lockfileVersion": 2, |
||||||
|
"requires": true, |
||||||
|
"packages": { |
||||||
|
"": { |
||||||
|
"name": "chainreact-server", |
||||||
|
"version": "2.0", |
||||||
|
"dependencies": { |
||||||
|
"dotenv": "^16.0.3", |
||||||
|
"https": "^1.0.0", |
||||||
|
"socket.io": "^4.4.1", |
||||||
|
"typescript": "^5.0.2" |
||||||
|
}, |
||||||
|
"devDependencies": { |
||||||
|
"@types/node": "^18.15.3" |
||||||
|
} |
||||||
|
}, |
||||||
|
"base": { |
||||||
|
"name": "game-server", |
||||||
|
"version": "2.0", |
||||||
|
"extraneous": true, |
||||||
|
"dependencies": { |
||||||
|
"dotenv": "^16.0.3", |
||||||
|
"https": "^1.0.0", |
||||||
|
"ini": "^2.0.0", |
||||||
|
"socket.io": "^4.4.1" |
||||||
|
}, |
||||||
|
"devDependencies": { |
||||||
|
"@types/node": "^17.0.18", |
||||||
|
"typescript": "^4.8.4" |
||||||
|
} |
||||||
|
}, |
||||||
|
"node_modules/@socket.io/component-emitter": { |
||||||
|
"version": "3.1.0", |
||||||
|
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", |
||||||
|
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" |
||||||
|
}, |
||||||
|
"node_modules/@types/cookie": { |
||||||
|
"version": "0.4.1", |
||||||
|
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", |
||||||
|
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" |
||||||
|
}, |
||||||
|
"node_modules/@types/cors": { |
||||||
|
"version": "2.8.13", |
||||||
|
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", |
||||||
|
"integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", |
||||||
|
"dependencies": { |
||||||
|
"@types/node": "*" |
||||||
|
} |
||||||
|
}, |
||||||
|
"node_modules/@types/node": { |
||||||
|
"version": "18.15.3", |
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.3.tgz", |
||||||
|
"integrity": "sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==" |
||||||
|
}, |
||||||
|
"node_modules/accepts": { |
||||||
|
"version": "1.3.8", |
||||||
|
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", |
||||||
|
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", |
||||||
|
"dependencies": { |
||||||
|
"mime-types": "~2.1.34", |
||||||
|
"negotiator": "0.6.3" |
||||||
|
}, |
||||||
|
"engines": { |
||||||
|
"node": ">= 0.6" |
||||||
|
} |
||||||
|
}, |
||||||
|
"node_modules/base64id": { |
||||||
|
"version": "2.0.0", |
||||||
|
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", |
||||||
|
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", |
||||||
|
"engines": { |
||||||
|
"node": "^4.5.0 || >= 5.9" |
||||||
|
} |
||||||
|
}, |
||||||
|
"node_modules/cookie": { |
||||||
|
"version": "0.4.2", |
||||||
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", |
||||||
|
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", |
||||||
|
"engines": { |
||||||
|
"node": ">= 0.6" |
||||||
|
} |
||||||
|
}, |
||||||
|
"node_modules/cors": { |
||||||
|
"version": "2.8.5", |
||||||
|
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", |
||||||
|
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", |
||||||
|
"dependencies": { |
||||||
|
"object-assign": "^4", |
||||||
|
"vary": "^1" |
||||||
|
}, |
||||||
|
"engines": { |
||||||
|
"node": ">= 0.10" |
||||||
|
} |
||||||
|
}, |
||||||
|
"node_modules/debug": { |
||||||
|
"version": "4.3.4", |
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", |
||||||
|
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", |
||||||
|
"dependencies": { |
||||||
|
"ms": "2.1.2" |
||||||
|
}, |
||||||
|
"engines": { |
||||||
|
"node": ">=6.0" |
||||||
|
}, |
||||||
|
"peerDependenciesMeta": { |
||||||
|
"supports-color": { |
||||||
|
"optional": true |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
"node_modules/dotenv": { |
||||||
|
"version": "16.0.3", |
||||||
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", |
||||||
|
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", |
||||||
|
"engines": { |
||||||
|
"node": ">=12" |
||||||
|
} |
||||||
|
}, |
||||||
|
"node_modules/engine.io": { |
||||||
|
"version": "6.4.1", |
||||||
|
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.1.tgz", |
||||||
|
"integrity": "sha512-JFYQurD/nbsA5BSPmbaOSLa3tSVj8L6o4srSwXXY3NqE+gGUNmmPTbhn8tjzcCtSqhFgIeqef81ngny8JM25hw==", |
||||||
|
"dependencies": { |
||||||
|
"@types/cookie": "^0.4.1", |
||||||
|
"@types/cors": "^2.8.12", |
||||||
|
"@types/node": ">=10.0.0", |
||||||
|
"accepts": "~1.3.4", |
||||||
|
"base64id": "2.0.0", |
||||||
|
"cookie": "~0.4.1", |
||||||
|
"cors": "~2.8.5", |
||||||
|
"debug": "~4.3.1", |
||||||
|
"engine.io-parser": "~5.0.3", |
||||||
|
"ws": "~8.11.0" |
||||||
|
}, |
||||||
|
"engines": { |
||||||
|
"node": ">=10.0.0" |
||||||
|
} |
||||||
|
}, |
||||||
|
"node_modules/engine.io-parser": { |
||||||
|
"version": "5.0.6", |
||||||
|
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.6.tgz", |
||||||
|
"integrity": "sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw==", |
||||||
|
"engines": { |
||||||
|
"node": ">=10.0.0" |
||||||
|
} |
||||||
|
}, |
||||||
|
"node_modules/https": { |
||||||
|
"version": "1.0.0", |
||||||
|
"resolved": "https://registry.npmjs.org/https/-/https-1.0.0.tgz", |
||||||
|
"integrity": "sha512-4EC57ddXrkaF0x83Oj8sM6SLQHAWXw90Skqu2M4AEWENZ3F02dFJE/GARA8igO79tcgYqGrD7ae4f5L3um2lgg==" |
||||||
|
}, |
||||||
|
"node_modules/mime-db": { |
||||||
|
"version": "1.52.0", |
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", |
||||||
|
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", |
||||||
|
"engines": { |
||||||
|
"node": ">= 0.6" |
||||||
|
} |
||||||
|
}, |
||||||
|
"node_modules/mime-types": { |
||||||
|
"version": "2.1.35", |
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", |
||||||
|
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", |
||||||
|
"dependencies": { |
||||||
|
"mime-db": "1.52.0" |
||||||
|
}, |
||||||
|
"engines": { |
||||||
|
"node": ">= 0.6" |
||||||
|
} |
||||||
|
}, |
||||||
|
"node_modules/ms": { |
||||||
|
"version": "2.1.2", |
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", |
||||||
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" |
||||||
|
}, |
||||||
|
"node_modules/negotiator": { |
||||||
|
"version": "0.6.3", |
||||||
|
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", |
||||||
|
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", |
||||||
|
"engines": { |
||||||
|
"node": ">= 0.6" |
||||||
|
} |
||||||
|
}, |
||||||
|
"node_modules/object-assign": { |
||||||
|
"version": "4.1.1", |
||||||
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", |
||||||
|
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", |
||||||
|
"engines": { |
||||||
|
"node": ">=0.10.0" |
||||||
|
} |
||||||
|
}, |
||||||
|
"node_modules/socket.io": { |
||||||
|
"version": "4.6.1", |
||||||
|
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.6.1.tgz", |
||||||
|
"integrity": "sha512-KMcaAi4l/8+xEjkRICl6ak8ySoxsYG+gG6/XfRCPJPQ/haCRIJBTL4wIl8YCsmtaBovcAXGLOShyVWQ/FG8GZA==", |
||||||
|
"dependencies": { |
||||||
|
"accepts": "~1.3.4", |
||||||
|
"base64id": "~2.0.0", |
||||||
|
"debug": "~4.3.2", |
||||||
|
"engine.io": "~6.4.1", |
||||||
|
"socket.io-adapter": "~2.5.2", |
||||||
|
"socket.io-parser": "~4.2.1" |
||||||
|
}, |
||||||
|
"engines": { |
||||||
|
"node": ">=10.0.0" |
||||||
|
} |
||||||
|
}, |
||||||
|
"node_modules/socket.io-adapter": { |
||||||
|
"version": "2.5.2", |
||||||
|
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", |
||||||
|
"integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", |
||||||
|
"dependencies": { |
||||||
|
"ws": "~8.11.0" |
||||||
|
} |
||||||
|
}, |
||||||
|
"node_modules/socket.io-parser": { |
||||||
|
"version": "4.2.2", |
||||||
|
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz", |
||||||
|
"integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==", |
||||||
|
"dependencies": { |
||||||
|
"@socket.io/component-emitter": "~3.1.0", |
||||||
|
"debug": "~4.3.1" |
||||||
|
}, |
||||||
|
"engines": { |
||||||
|
"node": ">=10.0.0" |
||||||
|
} |
||||||
|
}, |
||||||
|
"node_modules/typescript": { |
||||||
|
"version": "5.0.2", |
||||||
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz", |
||||||
|
"integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==", |
||||||
|
"bin": { |
||||||
|
"tsc": "bin/tsc", |
||||||
|
"tsserver": "bin/tsserver" |
||||||
|
}, |
||||||
|
"engines": { |
||||||
|
"node": ">=12.20" |
||||||
|
} |
||||||
|
}, |
||||||
|
"node_modules/vary": { |
||||||
|
"version": "1.1.2", |
||||||
|
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", |
||||||
|
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", |
||||||
|
"engines": { |
||||||
|
"node": ">= 0.8" |
||||||
|
} |
||||||
|
}, |
||||||
|
"node_modules/ws": { |
||||||
|
"version": "8.11.0", |
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", |
||||||
|
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", |
||||||
|
"engines": { |
||||||
|
"node": ">=10.0.0" |
||||||
|
}, |
||||||
|
"peerDependencies": { |
||||||
|
"bufferutil": "^4.0.1", |
||||||
|
"utf-8-validate": "^5.0.2" |
||||||
|
}, |
||||||
|
"peerDependenciesMeta": { |
||||||
|
"bufferutil": { |
||||||
|
"optional": true |
||||||
|
}, |
||||||
|
"utf-8-validate": { |
||||||
|
"optional": true |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
"dependencies": { |
||||||
|
"@socket.io/component-emitter": { |
||||||
|
"version": "3.1.0", |
||||||
|
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", |
||||||
|
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" |
||||||
|
}, |
||||||
|
"@types/cookie": { |
||||||
|
"version": "0.4.1", |
||||||
|
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", |
||||||
|
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" |
||||||
|
}, |
||||||
|
"@types/cors": { |
||||||
|
"version": "2.8.13", |
||||||
|
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", |
||||||
|
"integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", |
||||||
|
"requires": { |
||||||
|
"@types/node": "*" |
||||||
|
} |
||||||
|
}, |
||||||
|
"@types/node": { |
||||||
|
"version": "18.15.3", |
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.3.tgz", |
||||||
|
"integrity": "sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==" |
||||||
|
}, |
||||||
|
"accepts": { |
||||||
|
"version": "1.3.8", |
||||||
|
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", |
||||||
|
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", |
||||||
|
"requires": { |
||||||
|
"mime-types": "~2.1.34", |
||||||
|
"negotiator": "0.6.3" |
||||||
|
} |
||||||
|
}, |
||||||
|
"base64id": { |
||||||
|
"version": "2.0.0", |
||||||
|
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", |
||||||
|
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" |
||||||
|
}, |
||||||
|
"cookie": { |
||||||
|
"version": "0.4.2", |
||||||
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", |
||||||
|
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" |
||||||
|
}, |
||||||
|
"cors": { |
||||||
|
"version": "2.8.5", |
||||||
|
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", |
||||||
|
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", |
||||||
|
"requires": { |
||||||
|
"object-assign": "^4", |
||||||
|
"vary": "^1" |
||||||
|
} |
||||||
|
}, |
||||||
|
"debug": { |
||||||
|
"version": "4.3.4", |
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", |
||||||
|
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", |
||||||
|
"requires": { |
||||||
|
"ms": "2.1.2" |
||||||
|
} |
||||||
|
}, |
||||||
|
"dotenv": { |
||||||
|
"version": "16.0.3", |
||||||
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", |
||||||
|
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==" |
||||||
|
}, |
||||||
|
"engine.io": { |
||||||
|
"version": "6.4.1", |
||||||
|
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.1.tgz", |
||||||
|
"integrity": "sha512-JFYQurD/nbsA5BSPmbaOSLa3tSVj8L6o4srSwXXY3NqE+gGUNmmPTbhn8tjzcCtSqhFgIeqef81ngny8JM25hw==", |
||||||
|
"requires": { |
||||||
|
"@types/cookie": "^0.4.1", |
||||||
|
"@types/cors": "^2.8.12", |
||||||
|
"@types/node": ">=10.0.0", |
||||||
|
"accepts": "~1.3.4", |
||||||
|
"base64id": "2.0.0", |
||||||
|
"cookie": "~0.4.1", |
||||||
|
"cors": "~2.8.5", |
||||||
|
"debug": "~4.3.1", |
||||||
|
"engine.io-parser": "~5.0.3", |
||||||
|
"ws": "~8.11.0" |
||||||
|
} |
||||||
|
}, |
||||||
|
"engine.io-parser": { |
||||||
|
"version": "5.0.6", |
||||||
|
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.6.tgz", |
||||||
|
"integrity": "sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw==" |
||||||
|
}, |
||||||
|
"https": { |
||||||
|
"version": "1.0.0", |
||||||
|
"resolved": "https://registry.npmjs.org/https/-/https-1.0.0.tgz", |
||||||
|
"integrity": "sha512-4EC57ddXrkaF0x83Oj8sM6SLQHAWXw90Skqu2M4AEWENZ3F02dFJE/GARA8igO79tcgYqGrD7ae4f5L3um2lgg==" |
||||||
|
}, |
||||||
|
"mime-db": { |
||||||
|
"version": "1.52.0", |
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", |
||||||
|
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" |
||||||
|
}, |
||||||
|
"mime-types": { |
||||||
|
"version": "2.1.35", |
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", |
||||||
|
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", |
||||||
|
"requires": { |
||||||
|
"mime-db": "1.52.0" |
||||||
|
} |
||||||
|
}, |
||||||
|
"ms": { |
||||||
|
"version": "2.1.2", |
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", |
||||||
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" |
||||||
|
}, |
||||||
|
"negotiator": { |
||||||
|
"version": "0.6.3", |
||||||
|
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", |
||||||
|
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" |
||||||
|
}, |
||||||
|
"object-assign": { |
||||||
|
"version": "4.1.1", |
||||||
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", |
||||||
|
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" |
||||||
|
}, |
||||||
|
"socket.io": { |
||||||
|
"version": "4.6.1", |
||||||
|
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.6.1.tgz", |
||||||
|
"integrity": "sha512-KMcaAi4l/8+xEjkRICl6ak8ySoxsYG+gG6/XfRCPJPQ/haCRIJBTL4wIl8YCsmtaBovcAXGLOShyVWQ/FG8GZA==", |
||||||
|
"requires": { |
||||||
|
"accepts": "~1.3.4", |
||||||
|
"base64id": "~2.0.0", |
||||||
|
"debug": "~4.3.2", |
||||||
|
"engine.io": "~6.4.1", |
||||||
|
"socket.io-adapter": "~2.5.2", |
||||||
|
"socket.io-parser": "~4.2.1" |
||||||
|
} |
||||||
|
}, |
||||||
|
"socket.io-adapter": { |
||||||
|
"version": "2.5.2", |
||||||
|
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", |
||||||
|
"integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", |
||||||
|
"requires": { |
||||||
|
"ws": "~8.11.0" |
||||||
|
} |
||||||
|
}, |
||||||
|
"socket.io-parser": { |
||||||
|
"version": "4.2.2", |
||||||
|
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz", |
||||||
|
"integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==", |
||||||
|
"requires": { |
||||||
|
"@socket.io/component-emitter": "~3.1.0", |
||||||
|
"debug": "~4.3.1" |
||||||
|
} |
||||||
|
}, |
||||||
|
"typescript": { |
||||||
|
"version": "5.0.2", |
||||||
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz", |
||||||
|
"integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==" |
||||||
|
}, |
||||||
|
"vary": { |
||||||
|
"version": "1.1.2", |
||||||
|
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", |
||||||
|
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" |
||||||
|
}, |
||||||
|
"ws": { |
||||||
|
"version": "8.11.0", |
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", |
||||||
|
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", |
||||||
|
"requires": {} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,18 @@ |
|||||||
|
{ |
||||||
|
"name": "chainreact-server", |
||||||
|
"version": "2.0", |
||||||
|
"private": true, |
||||||
|
"scripts": { |
||||||
|
"start": "node out/index.js", |
||||||
|
"tsc": "npx tsc" |
||||||
|
}, |
||||||
|
"dependencies": { |
||||||
|
"dotenv": "^16.0.3", |
||||||
|
"https": "^1.0.0", |
||||||
|
"socket.io": "^4.4.1", |
||||||
|
"typescript": "^5.0.2" |
||||||
|
}, |
||||||
|
"devDependencies": { |
||||||
|
"@types/node": "^18.15.3" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,104 @@ |
|||||||
|
import {ServerGame} from "./game_standard"; |
||||||
|
import {Client} from "./client"; |
||||||
|
import {Room} from "./room"; |
||||||
|
|
||||||
|
export class Chainreact extends ServerGame { |
||||||
|
|
||||||
|
readyForTurn: Client[]; |
||||||
|
currentTurnIndex: number; |
||||||
|
currentGameData: any; |
||||||
|
colorHues: { [id: string]: number }; |
||||||
|
|
||||||
|
constructor(room: Room, settings: Settings.Global) { |
||||||
|
super(room, settings); |
||||||
|
this.readyForTurn = [] |
||||||
|
} |
||||||
|
|
||||||
|
setEvents(client: Client) { |
||||||
|
let socket = client.socket; |
||||||
|
socket.on('ready-for-turn', isDead => { |
||||||
|
if (isDead) { |
||||||
|
client.isPlayer = false; |
||||||
|
client.isSpectator = true; |
||||||
|
this.room.toAll('client-list', this.room.clients) |
||||||
|
} else { |
||||||
|
this.readyForTurn.push(client) |
||||||
|
} |
||||||
|
|
||||||
|
let allReady = true; |
||||||
|
this.room.players.forEach(c => { |
||||||
|
if (this.readyForTurn.find(r => r.id === c.id) == null) { |
||||||
|
allReady = false |
||||||
|
} |
||||||
|
}); |
||||||
|
if (allReady) { |
||||||
|
this.nextTurn(); |
||||||
|
this.readyForTurn = [] |
||||||
|
} |
||||||
|
}); |
||||||
|
socket.on('set-slot', (fieldsIndex: number, slotsIndex: number) => { |
||||||
|
this.room.toAll('set-slot', fieldsIndex, slotsIndex, socket.id) |
||||||
|
}); |
||||||
|
socket.on('game-data', data => this.currentGameData = data) |
||||||
|
} |
||||||
|
|
||||||
|
addClient(client: Client): void { |
||||||
|
super.addClient(client); |
||||||
|
if (client.isSpectator) { |
||||||
|
let room = this.room; |
||||||
|
let data = this.currentGameData; |
||||||
|
let hues = this.colorHues; |
||||||
|
let turnId = ''; |
||||||
|
if (this.room.players[this.currentTurnIndex]) |
||||||
|
turnId = this.room.players[this.currentTurnIndex].id; |
||||||
|
client.send('start-spectate', room, data, hues, turnId) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
removeClient(client: Client): void { |
||||||
|
super.removeClient(client); |
||||||
|
if (this.room.players.indexOf(client) === this.currentTurnIndex) |
||||||
|
this.nextTurn(true); |
||||||
|
|
||||||
|
let s = client.socket; |
||||||
|
s.removeAllListeners('set-slot'); |
||||||
|
s.removeAllListeners('ready-for-turn'); |
||||||
|
s.removeAllListeners('game-data') |
||||||
|
} |
||||||
|
|
||||||
|
nextTurn(skip?: boolean) { |
||||||
|
if (this.currentTurnIndex != null && !skip) { |
||||||
|
this.currentTurnIndex++; |
||||||
|
if (this.currentTurnIndex >= this.room.players.length) { |
||||||
|
this.currentTurnIndex = 0 |
||||||
|
} |
||||||
|
} else if (!skip) { |
||||||
|
this.setTurnAndColors() |
||||||
|
} |
||||||
|
let index = this.currentTurnIndex; |
||||||
|
if (skip) { |
||||||
|
index = this.currentTurnIndex + 1; |
||||||
|
if (index >= this.room.players.length) { |
||||||
|
index = 0; |
||||||
|
this.currentTurnIndex = 0 |
||||||
|
} |
||||||
|
} |
||||||
|
if (this.room.players.length) { |
||||||
|
this.room.toAll('current-turn', this.room.players[index].id) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
setTurnAndColors() { |
||||||
|
this.currentTurnIndex = Math.floor(Math.random() * this.room.players.length); |
||||||
|
let colorHues = [0, 60, 120, 240]; |
||||||
|
this.colorHues = {}; |
||||||
|
for (let c of this.room.players) { |
||||||
|
let index = Math.floor(Math.random() * colorHues.length); |
||||||
|
let hue = colorHues[index]; |
||||||
|
colorHues.splice(index, 1); |
||||||
|
this.colorHues[c.id] = hue |
||||||
|
} |
||||||
|
this.room.toAll('player-colors', this.colorHues) |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,168 @@ |
|||||||
|
import {Room} from "./room.js" |
||||||
|
import {ConnectionManager, serializeObject} from "./manager.js" |
||||||
|
import {log} from "./logger.js"; |
||||||
|
import * as SocketIO from "socket.io"; |
||||||
|
|
||||||
|
export class Client { |
||||||
|
|
||||||
|
socket: SocketIO.Socket; |
||||||
|
name: string; |
||||||
|
game: string; |
||||||
|
id: string; |
||||||
|
isReady: boolean; |
||||||
|
isPlayer: boolean; |
||||||
|
isSpectator: boolean; |
||||||
|
|
||||||
|
constructor(socket: SocketIO.Socket, manager: ConnectionManager) { |
||||||
|
this.socket = socket; |
||||||
|
// @ts-ignore
|
||||||
|
this.name = socket.handshake.query.name; |
||||||
|
// @ts-ignore
|
||||||
|
this.game = socket.handshake.query.game; |
||||||
|
this.id = socket.id; |
||||||
|
this.setEvents(manager) |
||||||
|
} |
||||||
|
|
||||||
|
get serialized(): Serialized.Client { |
||||||
|
return { |
||||||
|
id: this.id, |
||||||
|
name: this.name, |
||||||
|
game: this.game, |
||||||
|
isReady: this.isReady, |
||||||
|
isPlayer: this.isPlayer, |
||||||
|
isSpectator: this.isSpectator |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
setEvents(mng: ConnectionManager): void { |
||||||
|
let s = this.socket; |
||||||
|
s.on('room-list', () => this.sendRoomList()); |
||||||
|
s.on('client-list', () => this.sendClientList()); |
||||||
|
s.on('set-ready', ready => this.setReady(ready)); |
||||||
|
s.on('game-settings', settings => this.setGameSettings(settings)); |
||||||
|
s.on('create-lobby', (settings, name) => this.createRoom(settings, name)); |
||||||
|
s.on('join-lobby', roomId => this.joinRoom(roomId)); |
||||||
|
s.on('leave-lobby', roomId => this.leaveRoom(roomId)); |
||||||
|
s.on('join-spectators', () => this.joinSpectators()); |
||||||
|
s.on('join-players', () => this.joinPlayers()); |
||||||
|
s.on('start-game', lobbyId => mng.startGame(this, lobbyId)); |
||||||
|
s.on('stop-game', lobbyId => mng.stopGame(this, lobbyId)); |
||||||
|
s.on('feedback', content => mng.saveFeedbackToFile(this, content)); |
||||||
|
s.on('disconnect', () => mng.disconnected(this)); |
||||||
|
|
||||||
|
this.send('connected') |
||||||
|
} |
||||||
|
|
||||||
|
sendRoomList(): void { |
||||||
|
let rooms = ConnectionManager.RoomListByGame(this.game); |
||||||
|
this.send('room-list', rooms) |
||||||
|
} |
||||||
|
|
||||||
|
sendClientList(): void { |
||||||
|
let clients = ConnectionManager.ClientListByClientId(this.id); |
||||||
|
this.send('client-list', clients) |
||||||
|
} |
||||||
|
|
||||||
|
setReady(ready: boolean): void { |
||||||
|
let room = Room.getByClientId(this.id, ConnectionManager.Instance.rooms); |
||||||
|
|
||||||
|
if (room) { |
||||||
|
this.isReady = ready; |
||||||
|
room.toAll('client-list', room.clients) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
setGameSettings(settings: any): void { |
||||||
|
let room = Room.getByClientId(this.id, ConnectionManager.Instance.rooms); |
||||||
|
|
||||||
|
if (room) { |
||||||
|
room.gameSettings = settings; |
||||||
|
room.toAll('game-settings', settings) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
createRoom(settings: Settings.Global, name: string): void { |
||||||
|
let room = ConnectionManager.Instance.createRoom(settings, name); |
||||||
|
|
||||||
|
room.add(this); |
||||||
|
this.send('created-lobby', room); |
||||||
|
|
||||||
|
log('lobby-created', this, room) |
||||||
|
} |
||||||
|
|
||||||
|
joinRoom(roomId: string): Room { |
||||||
|
let room = Room.getByRoomId(roomId, ConnectionManager.Instance.rooms); |
||||||
|
|
||||||
|
if (!room) { |
||||||
|
this.send('join-failed', 'Room does not exist!'); |
||||||
|
log('join-non-existent', this, new Room('not-existent', roomId)) |
||||||
|
} else if (room.hasStarted && !room.settings.spectators) { |
||||||
|
this.send('join-failed', 'Game has started yet!'); |
||||||
|
log('join-started', this, room) |
||||||
|
} else { |
||||||
|
room.add(this); |
||||||
|
log('member-joined', this, room) |
||||||
|
} |
||||||
|
return room |
||||||
|
} |
||||||
|
|
||||||
|
leaveRoom(_roomId: string): void { |
||||||
|
let room = Room.getByClientId(this.id, ConnectionManager.Instance.rooms); |
||||||
|
|
||||||
|
if (!room) |
||||||
|
return; |
||||||
|
|
||||||
|
this.leave(room.id); |
||||||
|
if (room.runningGame) |
||||||
|
room.runningGame.removeClient(this); |
||||||
|
room.clients.splice(room.clients.indexOf(this), 1); |
||||||
|
room.toAll('member-left', this.id, this.name); |
||||||
|
room.toAll('client-list', room.clients); |
||||||
|
|
||||||
|
this.send('left-lobby'); |
||||||
|
|
||||||
|
log('member-left', this, room); |
||||||
|
|
||||||
|
if (room.isEmpty && !room.settings.always) { |
||||||
|
ConnectionManager.Instance.deleteRoom(room) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
joinSpectators() { |
||||||
|
let room = Room.getByClientId(this.id, ConnectionManager.Instance.rooms); |
||||||
|
if (!room) |
||||||
|
return; |
||||||
|
|
||||||
|
this.isSpectator = true; |
||||||
|
this.isPlayer = false; |
||||||
|
|
||||||
|
room.toAll('client-list', room.clients) |
||||||
|
} |
||||||
|
|
||||||
|
joinPlayers() { |
||||||
|
let room = Room.getByClientId(this.id, ConnectionManager.Instance.rooms); |
||||||
|
if (!room) |
||||||
|
return; |
||||||
|
|
||||||
|
if (room.hasStarted) |
||||||
|
return; |
||||||
|
|
||||||
|
this.isSpectator = false; |
||||||
|
this.isPlayer = true; |
||||||
|
|
||||||
|
room.toAll('client-list', room.clients) |
||||||
|
} |
||||||
|
|
||||||
|
send(event: string, ...args: any[]): void { |
||||||
|
this.socket.emit(event, ...serializeObject(args)) |
||||||
|
} |
||||||
|
|
||||||
|
join(roomId: string): void { |
||||||
|
this.socket.join(roomId) |
||||||
|
} |
||||||
|
|
||||||
|
leave(roomId: string): void { |
||||||
|
this.socket.leave(roomId) |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
declare namespace Serialized { |
||||||
|
|
||||||
|
interface Lobby { |
||||||
|
id: string |
||||||
|
name: string |
||||||
|
game: string |
||||||
|
clientCounts: number[] |
||||||
|
clients: Client[] |
||||||
|
hasStarted: boolean |
||||||
|
} |
||||||
|
|
||||||
|
interface Client { |
||||||
|
id: string |
||||||
|
name: string |
||||||
|
game: string |
||||||
|
isReady: boolean |
||||||
|
isPlayer: boolean |
||||||
|
isSpectator: boolean |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,74 @@ |
|||||||
|
declare module Settings { |
||||||
|
interface Global { |
||||||
|
project: Project |
||||||
|
frameWork: FrameWork |
||||||
|
game: any |
||||||
|
always: boolean |
||||||
|
spectators: boolean |
||||||
|
} |
||||||
|
|
||||||
|
interface Project { |
||||||
|
name: string |
||||||
|
author: string |
||||||
|
playerCounts: number[] |
||||||
|
} |
||||||
|
|
||||||
|
interface FrameWork { |
||||||
|
frameRate: number |
||||||
|
updateRate: number |
||||||
|
width: number |
||||||
|
height: number |
||||||
|
} |
||||||
|
|
||||||
|
interface Game { |
||||||
|
ball: Ball |
||||||
|
player: Player |
||||||
|
cw: number |
||||||
|
ch: number |
||||||
|
} |
||||||
|
|
||||||
|
interface Ball { |
||||||
|
radius: number |
||||||
|
velocity: number |
||||||
|
acceleration: number |
||||||
|
runUp: Ball.RunUp |
||||||
|
color: Color |
||||||
|
cw: number |
||||||
|
ch: number |
||||||
|
} |
||||||
|
|
||||||
|
interface Player { |
||||||
|
width: number |
||||||
|
height: number |
||||||
|
margin: number |
||||||
|
points: number |
||||||
|
normal: State |
||||||
|
weakened: State |
||||||
|
enhanced: State |
||||||
|
cw: number |
||||||
|
ch: number |
||||||
|
} |
||||||
|
|
||||||
|
interface Color { |
||||||
|
stroke: string |
||||||
|
fill: string |
||||||
|
} |
||||||
|
|
||||||
|
interface State { |
||||||
|
vel: Vector |
||||||
|
color: Color |
||||||
|
moveMargin: number |
||||||
|
} |
||||||
|
|
||||||
|
interface Vector { |
||||||
|
x: number |
||||||
|
y: number |
||||||
|
} |
||||||
|
|
||||||
|
module Ball { |
||||||
|
interface RunUp { |
||||||
|
min: number |
||||||
|
max: number |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
import {Room} from "./room.js" |
||||||
|
import {Client} from "./client.js" |
||||||
|
|
||||||
|
export class ServerGame { |
||||||
|
|
||||||
|
room: Room; |
||||||
|
settings: Settings.Global; |
||||||
|
game: any; |
||||||
|
|
||||||
|
constructor(room: Room, settings: Settings.Global) { |
||||||
|
this.settings = settings; |
||||||
|
this.room = room; |
||||||
|
this.room.clients.forEach(c => this.addClient(c)) |
||||||
|
} |
||||||
|
|
||||||
|
addClient(client: Client): void { |
||||||
|
this.setEvents(client) |
||||||
|
} |
||||||
|
|
||||||
|
removeClient(client: Client): void { |
||||||
|
this.removeEvents(client) |
||||||
|
} |
||||||
|
|
||||||
|
gameAction(action: string, ...args: any[]): void { |
||||||
|
} |
||||||
|
|
||||||
|
setEvents(client: Client): void { |
||||||
|
let socket = client.socket; |
||||||
|
socket.on('game-action', (action, ...args) => this.gameAction(action, ...args)) |
||||||
|
} |
||||||
|
|
||||||
|
removeEvents(client: Client): void { |
||||||
|
let socket = client.socket; |
||||||
|
socket.removeAllListeners('game-action') |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
import {Chainreact} from "./chainreact"; |
||||||
|
import {StartServer} from "./start"; |
||||||
|
|
||||||
|
StartServer({ |
||||||
|
useP2P: false, |
||||||
|
gameClass: Chainreact |
||||||
|
}); |
@ -0,0 +1,105 @@ |
|||||||
|
import {Room} from "./room.js" |
||||||
|
import {Client} from "./client.js" |
||||||
|
|
||||||
|
import * as fs from "fs"; |
||||||
|
import * as util from "util"; |
||||||
|
|
||||||
|
let logFolder = "./logs"; |
||||||
|
|
||||||
|
if (!fs.existsSync(logFolder)) { |
||||||
|
fs.mkdirSync(logFolder); |
||||||
|
} |
||||||
|
|
||||||
|
let logFile = fs.createWriteStream(logFolder + '/' + new Date().getTime() + '.log', {flags: 'a'}); |
||||||
|
let logStdout = process.stdout; |
||||||
|
|
||||||
|
console.log = function () { |
||||||
|
logFile.write(util.format.apply(null, arguments) + '\n'); |
||||||
|
logStdout.write(util.format.apply(null, arguments) + '\n'); |
||||||
|
}; |
||||||
|
|
||||||
|
console.error = console.log; |
||||||
|
|
||||||
|
process.on('uncaughtException', err => { |
||||||
|
console.error('Uncaught error: ', err); |
||||||
|
process.exit(1); |
||||||
|
}); |
||||||
|
|
||||||
|
process.stdin.pipe(logFile); |
||||||
|
|
||||||
|
|
||||||
|
export function log(type: string, client: Client, lobby?: Room, msg?: string) { |
||||||
|
let now = new Date(Date.now()).toString(), message, name, game; |
||||||
|
let date = '[' + now.substring(0, now.indexOf('GMT') - 1) + ']'; |
||||||
|
|
||||||
|
if (client) { |
||||||
|
game = '[' + client.game + ']'; |
||||||
|
let short = client.id.substring(0, Math.round(client.id.length / 3)); |
||||||
|
name = '"' + client.name + '(' + short + '...)"'; |
||||||
|
} else { |
||||||
|
if (type === 'lobby-deleted') { |
||||||
|
game = '[' + lobby.gameName + ']'; |
||||||
|
} else { |
||||||
|
game = '[undefined]'; |
||||||
|
} |
||||||
|
name = 'UNKNOWN'; |
||||||
|
} |
||||||
|
if (lobby) { |
||||||
|
game = '[' + lobby.gameName + ']'; |
||||||
|
} |
||||||
|
switch (type) { |
||||||
|
case 'join-non-existent': |
||||||
|
message = name + ' tried to join non-existent lobby "' + lobby.id + '"'; |
||||||
|
break; |
||||||
|
case 'join-started': |
||||||
|
message = name + ' tried to join the started game "' + lobby.id + '"'; |
||||||
|
break; |
||||||
|
case 'lobby-created': |
||||||
|
message = name + ' created new lobby: "' + lobby.id + '"'; |
||||||
|
break; |
||||||
|
case 'game-started': |
||||||
|
message = name + ' started the game: "' + lobby.id + '"'; |
||||||
|
break; |
||||||
|
case 'game-stopped': |
||||||
|
message = name + ' stopped the game: "' + lobby.id + '"'; |
||||||
|
break; |
||||||
|
case 'member-joined': |
||||||
|
message = name + ' joined the lobby "' + lobby.id + '"'; |
||||||
|
break; |
||||||
|
case 'member-left': |
||||||
|
message = name + ' left the lobby "' + lobby.id + '"'; |
||||||
|
break; |
||||||
|
case 'lobby-deleted': |
||||||
|
message = 'Lobby "' + lobby.id + '" was deleted'; |
||||||
|
break; |
||||||
|
case 'save-success': |
||||||
|
message = msg; |
||||||
|
break; |
||||||
|
case 'save-error': |
||||||
|
message = 'Failed to save contents to file: ' + msg; |
||||||
|
break; |
||||||
|
case 'load-success': |
||||||
|
message = 'Successfully loaded and parsed file contents'; |
||||||
|
break; |
||||||
|
case 'load-error': |
||||||
|
message = 'Failed to load file: ' + msg; |
||||||
|
break; |
||||||
|
case 'parse-error': |
||||||
|
message = 'Failed to parse contents: ' + msg; |
||||||
|
break; |
||||||
|
case 'feedback': |
||||||
|
message = 'Saved feedback to file: ' + msg; |
||||||
|
break; |
||||||
|
case 'connection': |
||||||
|
message = name + ' connected'; |
||||||
|
break; |
||||||
|
case 'disconnection': |
||||||
|
message = name + ' disconnected'; |
||||||
|
break; |
||||||
|
case 'startup': |
||||||
|
message = msg; |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
console.log(date + game + ' ---> {' + message + '}'); |
||||||
|
} |
@ -0,0 +1,148 @@ |
|||||||
|
import {Room} from "./room.js" |
||||||
|
import {Client} from "./client.js" |
||||||
|
import {log} from "./logger.js" |
||||||
|
import * as fs from "fs"; |
||||||
|
import * as SocketIO from "socket.io" |
||||||
|
|
||||||
|
export class ConnectionManager { |
||||||
|
|
||||||
|
static Instance: ConnectionManager; |
||||||
|
io: SocketIO.Server; |
||||||
|
rooms: Room[]; |
||||||
|
|
||||||
|
constructor(io: SocketIO.Server) { |
||||||
|
ConnectionManager.Instance = this; |
||||||
|
|
||||||
|
this.io = io; |
||||||
|
this.rooms = []; |
||||||
|
|
||||||
|
/*let drawSettings = { |
||||||
|
project: { |
||||||
|
name: 'global-draw', |
||||||
|
playerCounts: null |
||||||
|
}, |
||||||
|
always: true, |
||||||
|
spectators: true |
||||||
|
}; |
||||||
|
let drawRoom = this.createRoom(drawSettings, ''); |
||||||
|
drawRoom.id = 'global-draw-room'; |
||||||
|
drawRoom.startGame(); |
||||||
|
this.rooms.push(drawRoom);*/ |
||||||
|
} |
||||||
|
|
||||||
|
static RoomListByGame(game: string): Room[] { |
||||||
|
return this.Instance.rooms.filter(l => l.gameName === game) |
||||||
|
} |
||||||
|
|
||||||
|
static ClientListByClientId(clientId: string): Client[] { |
||||||
|
let room = Room.getByClientId(clientId, this.Instance.rooms); |
||||||
|
|
||||||
|
return room.clients |
||||||
|
} |
||||||
|
|
||||||
|
newSocket(socket: SocketIO.Socket): void { |
||||||
|
let client = new Client(socket, this); |
||||||
|
log('connection', client) |
||||||
|
} |
||||||
|
|
||||||
|
roomListUpdate(): void { |
||||||
|
this.io.sockets.emit('room-list', serializeObject(this.rooms)) |
||||||
|
} |
||||||
|
|
||||||
|
createRoom(settings: Settings.Global | any, name: string): Room { |
||||||
|
let roomId = Room.generateCode(10); |
||||||
|
let room = new Room(name, roomId, settings, this.io); |
||||||
|
|
||||||
|
this.rooms.push(room); |
||||||
|
this.roomListUpdate(); |
||||||
|
|
||||||
|
return room |
||||||
|
} |
||||||
|
|
||||||
|
deleteRoom(room: Room): void { |
||||||
|
this.rooms.splice(this.rooms.indexOf(room), 1); |
||||||
|
this.roomListUpdate(); |
||||||
|
|
||||||
|
log('lobby-deleted', null, room) |
||||||
|
} |
||||||
|
|
||||||
|
//Starts the game of a room with given id
|
||||||
|
startGame(client: Client, _roomId: string): void { |
||||||
|
let lobby = Room.getByClientId(client.id, this.rooms); |
||||||
|
if (!lobby) return; |
||||||
|
|
||||||
|
if (!lobby.hasStarted) { |
||||||
|
lobby.startGame(); |
||||||
|
log('game-started', client, lobby) |
||||||
|
} |
||||||
|
|
||||||
|
this.io.sockets.emit('room-list', serializeObject(this.rooms)) |
||||||
|
} |
||||||
|
|
||||||
|
//Stops the game of a lobby with given id
|
||||||
|
stopGame(client: Client, lobbyId: string): void { |
||||||
|
let lobby = Room.getByRoomId(lobbyId, this.rooms); |
||||||
|
if (!lobby) return; |
||||||
|
|
||||||
|
lobby.stopGame(client); |
||||||
|
log('game-stopped', client, lobby) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
//Saves user feedback to a file
|
||||||
|
saveFeedbackToFile(client: Client, content: string): void { |
||||||
|
let date = new Date(Date.now()).toString(); |
||||||
|
let path = "feedback/" + client.game + '.txt'; |
||||||
|
let saveToFile = (content: string) => { |
||||||
|
fs.writeFile(path, content, (err: any) => { |
||||||
|
if (err) |
||||||
|
log('save-error', client, null, err.message); |
||||||
|
else |
||||||
|
log('feedback', client, null, path) |
||||||
|
}); |
||||||
|
}; |
||||||
|
if (fs.existsSync(path)) { |
||||||
|
fs.readFile(path, 'utf8', (err, data) => { |
||||||
|
if (err) |
||||||
|
log('load-error', client, null, err.message); |
||||||
|
else { |
||||||
|
log('load-success', client, null); |
||||||
|
let newContent = data + '\n\n\n\n' + date + '\n\n' + content; |
||||||
|
saveToFile(newContent) |
||||||
|
} |
||||||
|
}) |
||||||
|
} else { |
||||||
|
saveToFile(date + '\n' + content) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//Removes a disconnected client from all references
|
||||||
|
disconnected(client: Client): void { |
||||||
|
let room = Room.getByClientId(client.id, this.rooms); |
||||||
|
|
||||||
|
if (room) |
||||||
|
client.leaveRoom(room.id); |
||||||
|
|
||||||
|
log('disconnection', client) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
export function serializeObject(object: any): any { |
||||||
|
function serialize(obj: any) { |
||||||
|
if (!obj) |
||||||
|
return obj; |
||||||
|
if (obj.serialized) |
||||||
|
return obj.serialized; |
||||||
|
else if (obj instanceof Array) { |
||||||
|
let content = []; |
||||||
|
obj.forEach(o => { |
||||||
|
content.push(serialize(o)) |
||||||
|
}); |
||||||
|
return content |
||||||
|
} |
||||||
|
return obj |
||||||
|
} |
||||||
|
|
||||||
|
return serialize(object) |
||||||
|
} |
@ -0,0 +1,135 @@ |
|||||||
|
import {Client} from "./client.js" |
||||||
|
import {ServerGame} from "./game_standard.js" |
||||||
|
import {serializeObject} from "./manager.js"; |
||||||
|
import {Server} from "socket.io"; |
||||||
|
|
||||||
|
export class Room { |
||||||
|
|
||||||
|
id: string; |
||||||
|
gameName: string; |
||||||
|
clientCounts: number[]; |
||||||
|
io: Server; |
||||||
|
clients: Client[]; |
||||||
|
runningGame: ServerGame; |
||||||
|
settings: Settings.Global; |
||||||
|
gameSettings: any; |
||||||
|
name: string; |
||||||
|
|
||||||
|
static GameClass: typeof ServerGame |
||||||
|
|
||||||
|
constructor(name: string, id: string, settings?: Settings.Global, io?: Server) { |
||||||
|
this.id = id; |
||||||
|
this.name = name; |
||||||
|
if (!io || !settings) return; |
||||||
|
this.settings = settings; |
||||||
|
this.gameName = settings.project.name; |
||||||
|
this.clientCounts = settings.project.playerCounts; |
||||||
|
this.io = io; |
||||||
|
this.clients = []; |
||||||
|
this.gameSettings = {} |
||||||
|
} |
||||||
|
|
||||||
|
get leader(): Client { |
||||||
|
return this.players[0] |
||||||
|
} |
||||||
|
|
||||||
|
get players(): Client[] { |
||||||
|
return this.clients.filter(c => c.isPlayer) |
||||||
|
} |
||||||
|
|
||||||
|
get spectators(): Client[] { |
||||||
|
return this.clients.filter(c => c.isSpectator) |
||||||
|
} |
||||||
|
|
||||||
|
get serialized(): Serialized.Lobby { |
||||||
|
return { |
||||||
|
id: this.id, |
||||||
|
name: this.name, |
||||||
|
game: this.gameName, |
||||||
|
clientCounts: this.clientCounts, |
||||||
|
clients: serializeObject(this.clients), |
||||||
|
hasStarted: this.hasStarted |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
get isEmpty(): boolean { |
||||||
|
return !(this.clients.length) |
||||||
|
} |
||||||
|
|
||||||
|
get hasStarted(): boolean { |
||||||
|
return this.runningGame != null |
||||||
|
} |
||||||
|
|
||||||
|
static getByRoomId(id: string, lobbies: Room[]): Room { |
||||||
|
for (let l of lobbies) { |
||||||
|
if (l.id === id) |
||||||
|
return l |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
static getByClientId(id: string, lobbies: Room[]): Room { |
||||||
|
for (let l of lobbies) { |
||||||
|
for (let c of l.clients) { |
||||||
|
if (c.id === id) |
||||||
|
return l |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
static generateCode(elements: number): string { |
||||||
|
let code = ''; |
||||||
|
let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; |
||||||
|
while (elements--) { |
||||||
|
code += possible.charAt(Math.floor(Math.random() * possible.length)) |
||||||
|
} |
||||||
|
return code |
||||||
|
} |
||||||
|
|
||||||
|
startGame(): void { |
||||||
|
let seed = Math.random() * 10000; |
||||||
|
this.toAll('start-game', seed); |
||||||
|
this.runGame() |
||||||
|
} |
||||||
|
|
||||||
|
stopGame(client: Client): void { |
||||||
|
this.toAll('stop-game', client); |
||||||
|
this.runningGame = null |
||||||
|
} |
||||||
|
|
||||||
|
add(client: Client): void { |
||||||
|
this.clients.push(client); |
||||||
|
|
||||||
|
let isPlayer = !this.hasStarted && this.hasValidPlayerCount(); |
||||||
|
client.isPlayer = isPlayer; |
||||||
|
client.isSpectator = !isPlayer; |
||||||
|
client.isReady = false; |
||||||
|
client.join(this.id); |
||||||
|
|
||||||
|
this.toAll('member-joined', client.id, client.name); |
||||||
|
this.toAll('client-list', this.clients); |
||||||
|
this.toAll('game-settings', this.gameSettings); |
||||||
|
|
||||||
|
if (this.hasStarted) |
||||||
|
this.runningGame.addClient(client) |
||||||
|
} |
||||||
|
|
||||||
|
hasValidPlayerCount(): boolean { |
||||||
|
let valid = false; |
||||||
|
this.clientCounts.forEach(c => { |
||||||
|
if (c === this.clients.length) |
||||||
|
valid = true |
||||||
|
}); |
||||||
|
return valid |
||||||
|
} |
||||||
|
|
||||||
|
runGame(): void { |
||||||
|
this.runningGame = new Room.GameClass(this, this.settings); |
||||||
|
} |
||||||
|
|
||||||
|
toAll(event: string, ...args: any[]): void { |
||||||
|
this.io.to(this.id).emit(event, serializeObject(this), ...serializeObject(args)) |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,39 @@ |
|||||||
|
import {ConnectionManager} from "./manager.js"; |
||||||
|
import {log} from "./logger.js"; |
||||||
|
|
||||||
|
import {Server} from 'socket.io'; |
||||||
|
import {Room} from "./room.js"; |
||||||
|
import * as https from "https"; |
||||||
|
import * as fs from "fs"; |
||||||
|
|
||||||
|
export function StartServer(settings: any){ |
||||||
|
|
||||||
|
require("dotenv").config(); |
||||||
|
const httpsPort = parseInt(process.env.HTTPS_PORT); |
||||||
|
|
||||||
|
let cert = fs.readFileSync(`${process.env.SSL_PATH}/cert.pem`); |
||||||
|
let key = fs.readFileSync(`${process.env.SSL_PATH}/key.pem`); |
||||||
|
|
||||||
|
let httpsServer = https.createServer({key: key, cert: cert}); |
||||||
|
|
||||||
|
let sIO = new Server(httpsServer, { |
||||||
|
cors: { |
||||||
|
origin: ["https://play.benjamin-kraft.local", "https://play.benjamin-kraft.eu"] |
||||||
|
} |
||||||
|
}); |
||||||
|
if (settings.useP2P){ |
||||||
|
const p2p = require('socket.io-p2p-server').Server; |
||||||
|
sIO.use(p2p); |
||||||
|
} |
||||||
|
|
||||||
|
httpsServer.listen(httpsPort); |
||||||
|
|
||||||
|
Room.GameClass = settings.gameClass; |
||||||
|
|
||||||
|
let connectionManager = new ConnectionManager(sIO); |
||||||
|
|
||||||
|
// On new connection
|
||||||
|
sIO.on('connection', socket => connectionManager.newSocket(socket)); |
||||||
|
|
||||||
|
log('startup', null, null, 'Server is listening on port ' + httpsPort); |
||||||
|
} |
@ -0,0 +1,11 @@ |
|||||||
|
{ |
||||||
|
"compilerOptions": { |
||||||
|
"module": "CommonJS", |
||||||
|
"outDir": "./out", |
||||||
|
"sourceMap": true, |
||||||
|
"alwaysStrict": true |
||||||
|
}, |
||||||
|
"include": [ |
||||||
|
"./src" |
||||||
|
] |
||||||
|
} |