From 0d055b2ce50d1a620cacb25145ec93f6d14c61db Mon Sep 17 00:00:00 2001 From: MrKritio Date: Sat, 17 Aug 2024 01:44:20 +0200 Subject: [PATCH] second commit --- database.js | 35 ------- elo.js | 10 -- events.js | 54 ----------- main.js | 257 +++++++++++++++++++++++++++++++++++++++++++-------- package.json | 25 +++++ player.js | 22 ----- 6 files changed, 245 insertions(+), 158 deletions(-) delete mode 100644 database.js delete mode 100644 elo.js delete mode 100644 events.js create mode 100644 package.json delete mode 100644 player.js diff --git a/database.js b/database.js deleted file mode 100644 index 701a6af..0000000 --- a/database.js +++ /dev/null @@ -1,35 +0,0 @@ -// database.js -const mysql = require('mysql2/promise'); - -const dbConfig = { - host: "95.217.113.161", - user: "Likima", - password: "27As$r0q1", - database: "jedaiito", - charset: "utf8" -}; - -const pool = mysql.createPool({ - ...dbConfig, - waitForConnections: true, - connectionLimit: 10, - queueLimit: 0 -}); - -async function updatePlayerElo(player) { - const connection = await pool.getConnection(); - try { - const updateQuery = ` - UPDATE players - SET elo = ? - WHERE guid = ? - `; - await connection.query(updateQuery, [player.elo, player.guid]); - } finally { - connection.release(); - } -} - -module.exports = { - updatePlayerElo, -}; diff --git a/elo.js b/elo.js deleted file mode 100644 index 1a486dc..0000000 --- a/elo.js +++ /dev/null @@ -1,10 +0,0 @@ -// elo.js -function calculateElo(currentRating, opponentRating, actualScore, kFactor = 32) { - const expectedScore = 1 / (1 + Math.pow(10, (opponentRating - currentRating) / 400)); - const newRating = currentRating + kFactor * (actualScore - expectedScore); - return newRating; -} - -module.exports = { - calculateElo, -}; diff --git a/events.js b/events.js deleted file mode 100644 index 648455e..0000000 --- a/events.js +++ /dev/null @@ -1,54 +0,0 @@ -// events.js -const events = require('events'); -const { calculateElo } = require('./elo'); -const { updatePlayerElo } = require('./database'); - -class GameEventEmitter extends events.EventEmitter {} - -const gameEventEmitter = new GameEventEmitter(); - -function handleRoundEnd(redScore, blueScore, playerScores, currentPlayers) { - console.log(`Round ended. Red: ${redScore}, Blue: ${blueScore}`); - - let winningTeam, losingTeam; - - if (redScore > blueScore) { - winningTeam = 'red'; - losingTeam = 'blue'; - } else if (blueScore > redScore) { - winningTeam = 'blue'; - losingTeam = 'red'; - } else { - console.log("It's a draw. No Elo change."); - return; - } - - const kFactor = 32; // You can adjust this as needed - - const winningPlayers = currentPlayers.filter(player => player.team === winningTeam); - const losingPlayers = currentPlayers.filter(player => player.team === losingTeam); - - const averageWinningElo = winningPlayers.reduce((acc, player) => acc + player.elo, 0) / winningPlayers.length; - const averageLosingElo = losingPlayers.reduce((acc, player) => acc + player.elo, 0) / losingPlayers.length; - - winningPlayers.forEach(async (player) => { - const individualPerformanceFactor = playerScores[player.id] / redScore; // Adjust based on individual contribution - player.elo = calculateElo(player.elo, averageLosingElo, 1 * individualPerformanceFactor, kFactor); - await updatePlayerElo(player); - }); - - losingPlayers.forEach(async (player) => { - const individualPerformanceFactor = playerScores[player.id] / blueScore; // Adjust based on individual contribution - player.elo = calculateElo(player.elo, averageWinningElo, 0 * individualPerformanceFactor, kFactor); - await updatePlayerElo(player); - }); - - console.log("Elo ratings updated."); -} - -gameEventEmitter.on('RoundEnd', handleRoundEnd); - -module.exports = { - gameEventEmitter, - handleRoundEnd, -}; diff --git a/main.js b/main.js index c9cabad..dcb6e4a 100644 --- a/main.js +++ b/main.js @@ -1,46 +1,229 @@ -// main.js -const { spawn } = require('child_process'); -const { gameEventEmitter } = require('./events'); -const { Player } = require('./player'); +const mysql = require('mysql2/promise'); +const WebSocket = require('ws'); +const axios = require('axios'); +const events = require('events'); -let currentPlayers = []; -let playerScores = {}; +// Database configuration +const dbConfig = { + host: "95.217.113.161", + user: "Likima", + password: "27As$r0q1", + database: "jedaiito", + charset: "utf8" +}; -function runCommand(command) { - const p = spawn('sh', ['-c', command], { stdio: 'pipe' }); +// Create a MySQL connection pool +const pool = mysql.createPool({ + ...dbConfig, + waitForConnections: true, + connectionLimit: 10, + queueLimit: 0 +}); - p.stderr.on('data', (data) => { - const line = data.toString().trim(); - console.log(">>> " + line); +// Elo Rating Calculation +function calculateElo(currentRating, opponentRating, actualScore, kFactor = 32) { + const expectedScore = 1 / (1 + Math.pow(10, (opponentRating - currentRating) / 400)); + const newRating = currentRating + kFactor * (actualScore - expectedScore); + return newRating; +} - if (line.startsWith('>>> red:') && line.includes(' blue:')) { - const redScore = parseInt(line.split('red:')[1].split(' ')[0]); - const blueScore = parseInt(line.split('blue:')[1]); - gameEventEmitter.emit('RoundEnd', redScore, blueScore, playerScores, currentPlayers); - playerScores = {}; // Reset playerScores after round end - } else if (line.startsWith('>>> score:')) { - const parts = line.split(' '); - const score = parseInt(parts[2]); - const clientId = parseInt(parts[6]); - const playerName = parts.slice(7).join(' '); +// Simplified Player class +class Player { + constructor(id, ip, name, guid, elo = 1000, score = 0, team = '') { + this.id = id; + this.ip = ip; + this.name = name; + this.guid = guid; + this.elo = elo; + this.score = score; + this.team = team; + this.is_alive = true; + } +} - const player = currentPlayers.find(p => p.id === clientId); - if (player) { - player.score = score; - playerScores[clientId] = score; - console.log(`Player ${playerName} (ID: ${clientId}) has a score of ${score}`); +// Utility function to remove color codes +function removeColorCodes(name) { + return name.replace(/\^\d/g, ''); +} + +// Update Elo ratings in the database +async function updatePlayerElo(player) { + const connection = await pool.getConnection(); + try { + const updateQuery = ` + UPDATE jedaii_comp + SET elo = ? + WHERE guid = ? + `; + await connection.query(updateQuery, [player.elo, player.guid]); + } finally { + connection.release(); + } +} + +// Event handling + +class GameEventEmitter extends events.EventEmitter {} + +const gameEventEmitter = new GameEventEmitter(); + +// Player lists +const currentPlayers = []; +const playerQueue = []; + +// Handle round end event +gameEventEmitter.on('RoundEnd', async (redScore, blueScore, playerScores) => { + console.log(`Round ended. Red: ${redScore}, Blue: ${blueScore}`); + + let winningTeam, losingTeam; + + if (redScore > blueScore) { + winningTeam = 'red'; + losingTeam = 'blue'; + } else if (blueScore > redScore) { + winningTeam = 'blue'; + losingTeam = 'red'; + } else { + console.log("It's a draw. No Elo change."); + return; + } + + const kFactor = 32; // You can adjust this as needed + + const winningPlayers = currentPlayers.filter(player => player.team === winningTeam); + const losingPlayers = currentPlayers.filter(player => player.team === losingTeam); + + const averageWinningElo = winningPlayers.reduce((acc, player) => acc + player.elo, 0) / winningPlayers.length; + const averageLosingElo = losingPlayers.reduce((acc, player) => acc + player.elo, 0) / losingPlayers.length; + + for (const player of winningPlayers) { + const individualPerformanceFactor = playerScores[player.id] / redScore; // Adjust based on individual contribution + player.elo = calculateElo(player.elo, averageLosingElo, 1 * individualPerformanceFactor, kFactor); + await updatePlayerElo(player); + } + + for (const player of losingPlayers) { + const individualPerformanceFactor = playerScores[player.id] / blueScore; // Adjust based on individual contribution + player.elo = calculateElo(player.elo, averageWinningElo, 0 * individualPerformanceFactor, kFactor); + await updatePlayerElo(player); + } + + console.log("Elo ratings updated."); +}); + +// Function to request a new token +async function requestNewToken() { + const API_URL = 'https://panel.pineriver.net/api/client/servers/68f7edce/websocket'; // Corrected API endpoint + const API_KEY = 'Bearer ptlc_uohTuXbtbTmVaSAhwtD16R2oDynhQgTWBZKN2m5lWdh'; // Your actual API key + try { + const response = await axios.get(API_URL, { + headers: { + 'Authorization': API_KEY, + 'Accept': 'application/json', + 'Content-Type': 'application/json' } - } + }); - if (checkLine(line)) { - // Additional event handling can go here - gameEventEmitter.emit('SomeOtherEvent', line); - } - }); + const { data } = response; + return data.data.token; + } catch (error) { + console.error('Error requesting new token:', error); + throw error; + } +} - p.on('close', (code) => { - console.log(`Process exited with code ${code}`); - }); +// Main function to start WebSocket connection and handle console output +async function startWebSocketConnection() { + try { + const API_URL = 'https://panel.pineriver.net/api/client/servers/68f7edce/websocket'; + const API_KEY = 'Bearer ptlc_uohTuXbtbTmVaSAhwtD16R2oDynhQgTWBZKN2m5lWdh'; + + // Request the token and WebSocket URL + const response = await axios.get(API_URL, { + headers: { + 'Authorization': API_KEY, + 'Accept': 'application/json', + 'Content-Type': 'application/json' + } + }); + + const { token, socket } = response.data.data; + + // Create WebSocket connection + const ws = new WebSocket(socket); + + ws.on('open', () => { + ws.send(JSON.stringify({ + event: 'auth', + args: [token] + })); + console.log('WebSocket connection established and authenticated'); + }); + + ws.on('message', async (message) => { + const parsedMessage = JSON.parse(message); + + if (parsedMessage.event === 'console output') { + const consoleOutput = parsedMessage.args[0]; + handleConsoleOutput(consoleOutput); + } + + if (parsedMessage.event === 'token expiring') { + console.log('Token is expiring soon, requesting a new token...'); + const newToken = await requestNewToken(); + ws.send(JSON.stringify({ + event: 'auth', + args: [newToken] + })); + console.log('WebSocket re-authenticated with new token'); + } + + if (parsedMessage.event === 'token expired') { + console.log('Token has expired, reconnecting with a new token...'); + ws.close(); // Close the current WebSocket connection + startWebSocketConnection(); // Start a new WebSocket connection + } + }); + + ws.on('close', () => { + console.log('WebSocket connection closed'); + }); + + ws.on('error', (error) => { + console.error('WebSocket error:', error); + }); + + } catch (error) { + console.error('Error starting WebSocket connection:', error); + } +} + +// Handle console output received via WebSocket +function handleConsoleOutput(line) { + const playerScores = {}; + + if (line.startsWith('>>> red:') && line.includes(' blue:')) { + const redScore = parseInt(line.split('red:')[1].split(' ')[0]); + const blueScore = parseInt(line.split('blue:')[1]); + gameEventEmitter.emit('RoundEnd', redScore, blueScore, playerScores); + } else if (line.startsWith('>>> score:')) { + const parts = line.split(' '); + const score = parseInt(parts[2]); + const clientId = parseInt(parts[6]); + const playerName = parts.slice(7).join(' '); + + const player = currentPlayers.find(p => p.id === clientId); + if (player) { + player.score = score; + playerScores[clientId] = score; + console.log(`Player ${playerName} (ID: ${clientId}) has a score of ${score}`); + } + } + + if (checkLine(line)) { + // Additional event handling can go here + gameEventEmitter.emit('SomeOtherEvent', line); + } } function checkLine(line) { @@ -55,5 +238,5 @@ function checkLine(line) { return false; } -// Running the game command -runCommand("sh start.sh"); +// Start the WebSocket connection +startWebSocketConnection(); diff --git a/package.json b/package.json new file mode 100644 index 0000000..805bc0f --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name": "game-server-management", + "version": "1.0.0", + "description": "A Node.js application for managing game server events and player Elo ratings.", + "main": "index.js", + "scripts": { + "start": "node index.js" + }, + "dependencies": { + "axios": "^1.4.0", + "events": "^3.3.0", + "mysql2": "^3.1.0", + "ws": "^8.12.0" + }, + "keywords": [ + "game", + "server", + "elo", + "websocket", + "mysql" + ], + "author": "Your Name", + "license": "MIT" + } + \ No newline at end of file diff --git a/player.js b/player.js deleted file mode 100644 index a929978..0000000 --- a/player.js +++ /dev/null @@ -1,22 +0,0 @@ -// player.js -class Player { - constructor(id, ip, name, guid, elo = 1000, score = 0, team = '') { - this.id = id; - this.ip = ip; - this.name = name; - this.guid = guid; - this.elo = elo; - this.score = score; - this.team = team; - this.is_alive = true; - } -} - -function removeColorCodes(name) { - return name.replace(/\^\d/g, ''); -} - -module.exports = { - Player, - removeColorCodes, -};