diff --git a/.gitignore b/.gitignore
index b985a57..f99e79e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,8 @@ node_modules
notes.md
app/t2-stat-parser/serverStats/stats
+app/t2-stat-parser/serverStats/mlData
+app/t2-stat-parser/serverStats/lData
docker-compose.deploy.yml
traefik.yml
diff --git a/app/t2-stat-parser/main.go b/app/t2-stat-parser/main.go
index 10079d3..bf68e57 100644
--- a/app/t2-stat-parser/main.go
+++ b/app/t2-stat-parser/main.go
@@ -14,9 +14,9 @@ import (
)
func main() {
- fmt.Println("Starting FTP stat file download")
+ // fmt.Println("Starting FTP stat file download")
initFTP()
- fmt.Println("Stat files downloaded!")
+ // fmt.Println("Stat files downloaded!")
fmt.Println("Starting stat parser")
initParser()
diff --git a/app/t2-stat-parser/parser.go b/app/t2-stat-parser/parser.go
index 200dbb0..cab5af2 100644
--- a/app/t2-stat-parser/parser.go
+++ b/app/t2-stat-parser/parser.go
@@ -59,12 +59,12 @@ type Game struct {
dbStatOverWrite int `db.players:"stat_overwrite"`
statOverWrite int
- gameMap string `db.games:"map"`
- gameID int `db.games:"game_id"`
- gameType string `db.games:"gametype"`
- dateStamp string `db.games:"datestamp"`
- stats string `db.games:"stats"`
- uuid string `db.games:"uuid"`
+ gameMap string `db.game_detail:"map"`
+ gameID int `db.game_detail:"game_id"`
+ gameType string `db.game_detail:"gametype"`
+ dateStamp string `db.game_detail:"datestamp"`
+ stats string `db.game_detail:"stats"`
+ uuid string `db.game_detail:"uuid"`
}
func initParser() {
@@ -265,7 +265,10 @@ func parseStatOverWriteLine(g Game, mStatLine map[string][]string, arrPosition i
fmt.Println(g)
}
- if checkGameEntry(g) == false && g.gameID != 0 {
+ // Check if we need to create a new game record
+ checkGameRecord(g)
+
+ if checkGameEntryForPlayer(g) == false && g.gameID != 0 {
fmt.Println("does not exist, add")
// insert game stat
addPlayerGameStat(g, strings.ToLower(gt))
@@ -283,6 +286,28 @@ func rowExists(query string, args ...interface{}) bool {
return exists
}
+func checkGameRecord(g Game) {
+ check := rowExists("select game_id from games where game_id = $1 and map = $2", g.gameID, g.gameMap)
+ if !check {
+ createGame(g)
+ } else {
+ fmt.Println("Game Record ", g.gameID, g.gameMap, " already exists")
+ }
+}
+func createGame(g Game) {
+ fmt.Println("Creating new Game ", g.gameMap, g.gameID, g.dateStamp, g.gameType)
+
+ if g.gameID != 0 {
+ sqlInsert := `insert into games(map, game_id, datestamp, gametype) values($1,$2,$3,$4)`
+ _, err := db.Exec(sqlInsert, g.gameMap, g.gameID, g.dateStamp, g.gameType)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Unable to create new game record (Possible Dupe ID): %v\n", err)
+ // Don't exit - just skip this insert
+ // os.Exit(1)
+ }
+ }
+}
+
func checkPlayer(g Game) {
check := rowExists("select player_guid from players where player_guid = $1", g.playerGUID)
if !check {
@@ -292,8 +317,8 @@ func checkPlayer(g Game) {
}
}
-func checkGameEntry(g Game) bool {
- check := rowExists("select player_guid from games where player_guid = $1 and game_id = $2 and map = $3", g.playerGUID, g.gameID, g.gameMap)
+func checkGameEntryForPlayer(g Game) bool {
+ check := rowExists("select player_guid from game_detail where player_guid = $1 and game_id = $2 and map = $3", g.playerGUID, g.gameID, g.gameMap)
if !check {
return false
} else {
@@ -341,7 +366,7 @@ func addPlayerGameStat(g Game, gt string) {
if g.dateStamp != "0" {
// Insert new stat line
fmt.Println("New stat line!", g.playerName, g.dateStamp)
- sqlInsert := `insert into games(player_guid, player_name, stat_overwrite, map, game_id, stats, datestamp, uuid, gametype) values($1,$2,$3,$4,$5,$6,$7,$8,$9)`
+ sqlInsert := `insert into game_detail(player_guid, player_name, stat_overwrite, map, game_id, stats, datestamp, uuid, gametype) values($1,$2,$3,$4,$5,$6,$7,$8,$9)`
_, err := db.Exec(sqlInsert, g.playerGUID, g.playerName, g.statOverWrite, g.gameMap, g.gameID, g.stats, g.dateStamp, g.uuid, g.gameType)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to add player's game stat: %v\n", err)
diff --git a/app/t2-stat-parser/serverStats/dir.txt b/app/t2-stat-parser/serverStats/dir.txt
new file mode 100644
index 0000000..19910b3
--- /dev/null
+++ b/app/t2-stat-parser/serverStats/dir.txt
@@ -0,0 +1,7 @@
+./lData
+./mlData
+
+./stats/CTFGame
+./stats/DMGame
+./stats/LakRabbitGame
+./stats/SCTF/Game
\ No newline at end of file
diff --git a/app/webapp/app/Controllers/Http/GameController.js b/app/webapp/app/Controllers/Http/GameController.js
index 54fcef7..7ac4ea8 100644
--- a/app/webapp/app/Controllers/Http/GameController.js
+++ b/app/webapp/app/Controllers/Http/GameController.js
@@ -1,71 +1,64 @@
-'use strict'
+'use strict';
-const Database = use('Database')
+const Database = use('Database');
class GameController {
+ // /games
+ async index({ inertia }) {
+ const pageTitle = `Latest Games`;
- // /games
- async index({ inertia }) {
+ // const gamesQry = await Database.raw(`
+ // SELECT distinct game_id,map,gametype, datestamp
+ // FROM games
+ // WHERE (stats->>'score' IS NOT NULL) AND (game_id <> 0)
+ // ORDER BY game_id desc
+ // LIMIT 2000;
+ // `);
- const pageTitle = `Latest Games`;
+ // const gamesQry = await Database.raw(`
+ // WITH gamelist AS (
+ // SELECT DISTINCT p.game_id, p.map, p.gametype, p.datestamp, count(*) OVER (PARTITION BY game_id) as count from games p
+ // )
+ // SELECT * from gamelist
+ // WHERE (count > 1) AND (game_id <> 0)
+ // ORDER BY game_id desc
+ // LIMIT 2000
+ // `);
- // const gamesQry = await Database.raw(`
- // SELECT distinct game_id,map,gametype, datestamp
- // FROM games
- // WHERE (stats->>'score' IS NOT NULL) AND (game_id <> 0)
- // ORDER BY game_id desc
- // LIMIT 2000;
- // `);
+ // // filter out duplicate game_ids (https://dev.to/marinamosti/removing-duplicates-in-an-array-of-objects-in-js-with-sets-3fep)
+ // const games = gamesQry.rows.reduce((game, current) => {
+ // const x = game.find(item => item.game_id === current.game_id);
+ // if (!x) {
+ // return game.concat([current]);
+ // } else {
+ // return game;
+ // }
+ // }, []);
- const gamesQry = await Database.raw(`
- WITH gamelist AS (
- SELECT DISTINCT p.game_id, p.map, p.gametype, p.datestamp, count(*) OVER (PARTITION BY game_id) as count from games p
- )
- SELECT * from gamelist
- WHERE (count > 1) AND (game_id <> 0)
- ORDER BY game_id desc
- LIMIT 2000
- `);
+ const games = await Database.from('games').orderBy('game_id', 'desc').limit(200);
+ // const CTFgames = await Database.from('games').where({gametype: 'CTFGame'}).orderBy('game_id', 'desc').limit(120);
+ // const LAKgames = await Database.from('games').where({gametype: 'LakRabbitGame'}).orderBy('game_id', 'desc').limit(120);
- // filter out duplicate game_ids (https://dev.to/marinamosti/removing-duplicates-in-an-array-of-objects-in-js-with-sets-3fep)
- const games = gamesQry.rows.reduce((game, current) => {
+ // move the 0 score display logic here
- const x = game.find(item => item.game_id === current.game_id);
- if (!x) {
- return game.concat([current]);
- } else {
- return game;
- }
- }, []);
-
- // move the 0 score display logic here
-
- return inertia.render('Games/Main', { pageTitle, games }, { edgeVar: 'server-variable' })
- }
-
-
- // game/:game_id
- async game({ inertia, request }) {
- const gameInfo = await Database.from('games')
- .distinct('game_id',
- 'map',
- 'player_name',
- 'player_guid',
- 'gametype',
- 'stats',
- 'datestamp')
- .where({ game_id: request.params.game_id })
- const pageTitle = {
- name: gameInfo[0]['map'],
- gametype: gameInfo[0]['gametype']
- }
-
- return inertia.render('Games/Game', { pageTitle, gameInfo }, { edgeVar: 'server-variable' })
- }
+ return inertia.render('Games/Main', { pageTitle, games }, { edgeVar: 'server-variable' });
+ }
+ // game/:game_id
+ async game({ inertia, request }) {
+ const gameInfo = await Database.from('game_detail')
+ .select('game_id', 'map', 'player_name', 'player_guid', 'gametype', 'stats', 'datestamp')
+ .where({ game_id: request.params.game_id })
+ .orderByRaw("stats->>'scoreTG' desc");
+ const pageTitle = {
+ name: gameInfo[0]['map'],
+ gametype: gameInfo[0]['gametype']
+ };
+ return inertia.render('Games/Game', { pageTitle, gameInfo }, { edgeVar: 'server-variable' });
+ }
}
-module.exports = GameController
+module.exports = GameController;
diff --git a/app/webapp/app/Controllers/Http/PlayerController.js b/app/webapp/app/Controllers/Http/PlayerController.js
index d2521b1..14b7eb3 100644
--- a/app/webapp/app/Controllers/Http/PlayerController.js
+++ b/app/webapp/app/Controllers/Http/PlayerController.js
@@ -1,84 +1,82 @@
-'use strict'
+'use strict';
-const Database = use('Database')
+const Database = use('Database');
class PlayerController {
+ // Main Players List
+ async index({ inertia }) {
+ const pageTitle = 'All Players';
+ const players = await Database.table('players')
+ .distinct(
+ 'player_guid',
+ 'player_name',
+ 'total_games_ctfgame',
+ 'total_games_dmgame',
+ 'total_games_lakrabbitgame',
+ 'total_games_sctfgame',
+ 'updated_at'
+ )
+ .groupBy('player_guid')
+ .orderBy('player_name', 'asc')
+ .limit(1000);
- // Main Players List
- async index({ inertia }) {
- const pageTitle = "All Players"
- const players = await Database.table('players')
- .distinct('player_guid',
- 'player_name',
- 'total_games_ctfgame',
- 'total_games_dmgame',
- 'total_games_lakrabbitgame',
- 'total_games_sctfgame',
- 'updated_at')
- .groupBy('player_guid')
- .orderBy('player_name', 'asc')
- .limit(1000)
+ return inertia.render('Players/Main', { pageTitle, players }, { edgeVar: 'server-variable' });
+ }
- return inertia.render('Players/Main', { pageTitle, players }, { edgeVar: 'server-variable' })
- }
+ // Player Detail
+ async player({ inertia, request }) {
+ const playerInfo = await Database.from('players')
+ .distinct(
+ 'player_guid',
+ 'player_name',
+ 'total_games_ctfgame',
+ 'total_games_dmgame',
+ 'total_games_lakrabbitgame',
+ 'total_games_sctfgame'
+ )
+ .where({ player_guid: request.params.player_guid })
+ .limit(50);
- // Player Detail
- async player({ inertia, request }) {
- const playerInfo = await Database.from('players')
- .distinct('player_guid',
- 'player_name',
- 'total_games_ctfgame',
- 'total_games_dmgame',
- 'total_games_lakrabbitgame',
- 'total_games_sctfgame')
- .where({ player_guid: request.params.player_guid })
- .limit(50)
+ const playerStatData = await Database.from('game_detail')
+ .select('game_id', 'gametype', 'stats')
+ .where({ player_guid: request.params.player_guid })
+ .orderBy('game_id', 'desc')
+ .limit(50);
+ // Dynamically generate and sum the stats object
+ let playerStatTotals = {},
+ statKeys = Object.keys(playerStatData[0].stats);
- const playerStatData = await Database.from('games')
- .select('game_id',
- 'gametype',
- 'stats')
- .where({ player_guid: request.params.player_guid })
- .orderBy('game_id', 'desc')
- .limit(50)
+ for (let i = 0; i < statKeys.length; i++) {
+ if (statKeys[i] === 'map' || statKeys[i] === 'dateStamp' || statKeys[i] === 'timeDayMonth') {
+ continue;
+ }
+ playerStatTotals[statKeys[i]] = 0;
+ }
+ // Loop through the playerStatsData query from the DB
+ playerStatData.map((statLine) => {
+ // look through each object in playerStatsData array
+ for (let [ key, value ] of Object.entries(statLine.stats)) {
+ // console.log(`${key}: ${value}`);
+ // If the stat item exists, add it -- if not create a new key in playerStatTotals
+ if (playerStatTotals.hasOwnProperty(key) === true) {
+ playerStatTotals[key] = playerStatTotals[key] + Number(value);
+ } else {
+ playerStatTotals[key] = Number(value);
+ }
+ }
+ });
- // Dynamically generate and sum the stats object
- let playerStatTotals = {},
- statKeys = Object.keys(playerStatData[0].stats)
+ let playerData = {
+ player: playerInfo[0],
+ stats: playerStatData,
+ totals: playerStatTotals
+ };
- for(let i = 0 ; i < statKeys.length; i++) {
- if(statKeys[i] === "map" ||
- statKeys[i] === "dateStamp" ||
- statKeys[i] === "timeDayMonth" ){continue;}
- playerStatTotals[statKeys[i]] = 0;
- }
-
- // Loop through the playerStatsData query from the DB
- playerStatData.map(statLine => {
- // look through each object in playerStatsData array
- for (let [key, value] of Object.entries(statLine.stats)) {
- // console.log(`${key}: ${value}`);
- // If the stat item exists, add it -- if not create a new key in playerStatTotals
- if(playerStatTotals.hasOwnProperty(key) === true){
- playerStatTotals[key] = playerStatTotals[key] + Number(value);
- }else{
- playerStatTotals[key] = Number(value);
- }
- }
- })
-
-
- let playerData = {
- player: playerInfo[0],
- stats: playerStatData,
- totals: playerStatTotals
- }
-
- const pageTitle = playerData.player.player_name
- return inertia.render('Players/Player', { pageTitle, playerData }, { edgeVar: 'server-variable' })
- }
+ const pageTitle = playerData.player.player_name;
+ return inertia.render('Players/Player', { pageTitle, playerData }, { edgeVar: 'server-variable' });
+ }
}
-module.exports = PlayerController
+module.exports = PlayerController;
diff --git a/app/webapp/resources/js/Pages/Games/Game.js b/app/webapp/resources/js/Pages/Games/Game.js
index 7e6818d..18cb97c 100644
--- a/app/webapp/resources/js/Pages/Games/Game.js
+++ b/app/webapp/resources/js/Pages/Games/Game.js
@@ -1,170 +1,171 @@
-import React, {PureComponent} from 'react'
-import { InertiaLink } from '@inertiajs/inertia-react'
-import Layout from '@/Shared/Layout'
+import React, { PureComponent } from 'react';
+import { InertiaLink } from '@inertiajs/inertia-react';
+import Layout from '@/Shared/Layout';
-import {PieChart, Pie, Sector} from 'recharts'
+import { PieChart, Pie, Sector } from 'recharts';
const renderActiveShape = (props) => {
- const RADIAN = Math.PI / 180;
- const { cx, cy, midAngle, innerRadius, outerRadius, startAngle, endAngle,
- fill, payload, percent, value } = props;
- const sin = Math.sin(-RADIAN * midAngle);
- const cos = Math.cos(-RADIAN * midAngle);
- const sx = cx + (outerRadius + 10) * cos;
- const sy = cy + (outerRadius + 10) * sin;
- const mx = cx + (outerRadius + 30) * cos;
- const my = cy + (outerRadius + 30) * sin;
- const ex = mx + (cos >= 0 ? 1 : -1) * 22;
- const ey = my;
- const textAnchor = cos >= 0 ? 'start' : 'end';
+ const RADIAN = Math.PI / 180;
+ const { cx, cy, midAngle, innerRadius, outerRadius, startAngle, endAngle, fill, payload, percent, value } = props;
+ const sin = Math.sin(-RADIAN * midAngle);
+ const cos = Math.cos(-RADIAN * midAngle);
+ const sx = cx + (outerRadius + 10) * cos;
+ const sy = cy + (outerRadius + 10) * sin;
+ const mx = cx + (outerRadius + 30) * cos;
+ const my = cy + (outerRadius + 30) * sin;
+ const ex = mx + (cos >= 0 ? 1 : -1) * 22;
+ const ey = my;
+ const textAnchor = cos >= 0 ? 'start' : 'end';
- return (
-
{JSON.stringify(props.gameInfo)}- {player.stats.dateStamp} -
-+ + {player.stats.dateStamp} + +
+Stat Totals
+- Stat Totals -
-- Stats for past {props.playerData.stats.length} games -
-+ Stats for past {props.playerData.stats.length} games +
+ {JSON.stringify(props.playerData.stats)}