commit
08aeda0de3
|
@ -54,7 +54,7 @@ const createBackup = () => {
|
|||
if (err) {
|
||||
error(err.message);
|
||||
}
|
||||
logger('\x1b[32m%s\x1b[0m',stderr);
|
||||
logger('\x1b[32m%s\x1b[0m', stderr);
|
||||
logger('\x1b[35m%s\x1b[0m', new Date().toLocaleString()
|
||||
+ ': cron job finished - CREATE BACKUP');
|
||||
})
|
||||
|
|
|
@ -12,8 +12,16 @@ let check = (requiredPermission, actualPermission, res, next) => {
|
|||
};
|
||||
|
||||
module.exports = {
|
||||
checkSql: (req, res, next) => { check(1, req.user.permission, res, next) },
|
||||
checkHl: (req, res, next) => { check(2, req.user.permission, res, next) },
|
||||
checkMT: (req, res, next) => { check(3, req.user.permission, res, next) },
|
||||
checkAdmin: (req, res, next) => { check(4, req.user.permission, res, next) }
|
||||
checkSql: (req, res, next) => {
|
||||
check(1, req.user.permission, res, next)
|
||||
},
|
||||
checkHl: (req, res, next) => {
|
||||
check(2, req.user.permission, res, next)
|
||||
},
|
||||
checkMT: (req, res, next) => {
|
||||
check(3, req.user.permission, res, next)
|
||||
},
|
||||
checkAdmin: (req, res, next) => {
|
||||
check(4, req.user.permission, res, next)
|
||||
}
|
||||
};
|
||||
|
|
|
@ -34,8 +34,8 @@ router.use((req, res, next) => {
|
|||
// request type application/json check
|
||||
router.use((req, res, next) => {
|
||||
if (['POST', 'PUT', 'PATCH'].indexOf(req.method) > -1 &&
|
||||
(!( /multipart\/form-data/.test(req.get('Content-Type'))) &&
|
||||
!( /application\/json/.test(req.get('Content-Type'))))) {
|
||||
(!(/multipart\/form-data/.test(req.get('Content-Type'))) &&
|
||||
!(/application\/json/.test(req.get('Content-Type'))))) {
|
||||
// send error code 415: unsupported media type
|
||||
res.status(415).send('wrong Content-Type'); // user has SEND the wrong type
|
||||
} else if (!req.accepts('json')) {
|
||||
|
|
|
@ -36,6 +36,6 @@ const LogTransportSchema = new Schema({
|
|||
collection: 'logTransport'
|
||||
});
|
||||
// optional more indices
|
||||
LogTransportSchema.index({war: 1});
|
||||
LogTransportSchema.index({war: 1, driver: 1});
|
||||
|
||||
module.exports = mongoose.model('LogTransport', LogTransportSchema);
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
"use strict";
|
||||
|
||||
const mongoose = require('mongoose');
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const LogVehicleKillSchema = new Schema({
|
||||
war: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: 'War',
|
||||
required: true
|
||||
},
|
||||
time: {
|
||||
type: Date,
|
||||
required: true
|
||||
},
|
||||
shooter: {
|
||||
type: String
|
||||
},
|
||||
target: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
fraction: {
|
||||
type: String,
|
||||
enum: ['BLUFOR', 'OPFOR', 'NONE'],
|
||||
required: true
|
||||
}
|
||||
}, {
|
||||
collection: 'logVehicle'
|
||||
});
|
||||
// optional more indices
|
||||
LogVehicleKillSchema.index({war: 1, shooter: 1, target: 1});
|
||||
|
||||
module.exports = mongoose.model('LogVehicle', LogVehicleKillSchema);
|
|
@ -24,6 +24,12 @@ const PlayerSchema = new Schema({
|
|||
set: v => Math.round(v),
|
||||
required: true
|
||||
},
|
||||
vehicle: {
|
||||
type: Number,
|
||||
get: v => Math.round(v),
|
||||
set: v => Math.round(v),
|
||||
required: true
|
||||
},
|
||||
death: {
|
||||
type: Number,
|
||||
get: v => Math.round(v),
|
||||
|
@ -58,12 +64,17 @@ const PlayerSchema = new Schema({
|
|||
type: Number,
|
||||
get: v => Math.round(v),
|
||||
set: v => Math.round(v)
|
||||
},
|
||||
steamUUID: {
|
||||
type: Number,
|
||||
get: v => Math.round(v),
|
||||
set: v => Math.round(v)
|
||||
}
|
||||
}, {
|
||||
collection: 'player',
|
||||
timestamps: {createdAt: 'timestamp'}
|
||||
});
|
||||
// optional more indices
|
||||
PlayerSchema.index({timestamp: 1});
|
||||
PlayerSchema.index({warId: 1});
|
||||
|
||||
module.exports = mongoose.model('Player', PlayerSchema);
|
||||
|
|
|
@ -11,7 +11,7 @@ const WarSchema = new Schema({
|
|||
date: {
|
||||
type: Date,
|
||||
},
|
||||
endDate : {
|
||||
endDate: {
|
||||
type: Date,
|
||||
},
|
||||
ptBlufor: {
|
||||
|
|
|
@ -45,7 +45,8 @@ account.route('/:id')
|
|||
req.body.updatedAt = new Date();
|
||||
req.body.$inc = {__v: 1};
|
||||
|
||||
// PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to reset attributes that are missing.
|
||||
// PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to
|
||||
// reset attributes that are missing.
|
||||
AppUserModel.findByIdAndUpdate(req.params.id, req.body, {new: true}).populate('squad').exec((err, item) => {
|
||||
if (err) {
|
||||
err.status = codes.wrongrequest;
|
||||
|
@ -70,7 +71,8 @@ account.route('/:id')
|
|||
err = new Error("item not found");
|
||||
err.status = codes.notfound;
|
||||
}
|
||||
// we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler user.use(..)
|
||||
// we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler
|
||||
// user.use(..)
|
||||
res.locals.processed = true;
|
||||
next(err); // this works because err is in normal case undefined and that is the same as no parameter
|
||||
});
|
||||
|
|
|
@ -44,8 +44,8 @@ awarding.route('/')
|
|||
if (err) {
|
||||
err.status = codes.servererror;
|
||||
return next(err);
|
||||
// with return before (or after) the next(err) we prevent that the code continues here after next(err) has finished.
|
||||
// this saves an extra else {..}
|
||||
// with return before (or after) the next(err) we prevent that the code continues here after next(err)
|
||||
// has finished. this saves an extra else {..}
|
||||
}
|
||||
// if the collection is empty we do not send empty arrays back.
|
||||
if (items && items.length > 0) {
|
||||
|
@ -60,8 +60,8 @@ awarding.route('/')
|
|||
if (err) {
|
||||
err.status = codes.servererror;
|
||||
return next(err);
|
||||
// with return before (or after) the next(err) we prevent that the code continues here after next(err) has finished.
|
||||
// this saves an extra else {..}
|
||||
// with return before (or after) the next(err) we prevent that the code continues here after next(err)
|
||||
// has finished. this saves an extra else {..}
|
||||
}
|
||||
let results = [];
|
||||
if (req.query.fractFilter) {
|
||||
|
@ -118,7 +118,8 @@ awarding.route('/:id')
|
|||
req.body.updatedAt = new Date();
|
||||
req.body.$inc = {__v: 1};
|
||||
|
||||
// PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to reset attributes that are missing.
|
||||
// PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to
|
||||
// reset attributes that are missing.
|
||||
AwardingModel.findByIdAndUpdate(req.params.id, req.body, {new: true}, (err, item) => {
|
||||
if (err) {
|
||||
err.status = codes.wrongrequest;
|
||||
|
@ -143,7 +144,8 @@ awarding.route('/:id')
|
|||
err = new Error("item not found");
|
||||
err.status = codes.notfound;
|
||||
}
|
||||
// we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler user.use(..)
|
||||
// we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler
|
||||
// user.use(..)
|
||||
res.locals.processed = true;
|
||||
next(err); // this works because err is in normal case undefined and that is the same as no parameter
|
||||
});
|
||||
|
|
|
@ -34,7 +34,14 @@ decoration.route('/')
|
|||
if (req.query.q) {
|
||||
filter.name = {$regex: req.query.q, $options: 'i'}
|
||||
}
|
||||
DecorationModel.find(filter, {}, {sort: {fraction: 'asc', isMedal: 'asc', sortingNumber: 'asc', name: 'asc'}}, (err, items) => {
|
||||
DecorationModel.find(filter, {}, {
|
||||
sort: {
|
||||
fraction: 'asc',
|
||||
isMedal: 'asc',
|
||||
sortingNumber: 'asc',
|
||||
name: 'asc'
|
||||
}
|
||||
}, (err, items) => {
|
||||
if (err) {
|
||||
err.status = codes.servererror;
|
||||
return next(err);
|
||||
|
@ -112,7 +119,8 @@ decoration.route('/:id')
|
|||
});
|
||||
}
|
||||
|
||||
// PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to reset attributes that are missing.
|
||||
// PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need
|
||||
// to reset attributes that are missing.
|
||||
DecorationModel.findByIdAndUpdate(req.params.id, req.body, {new: true}, (err, item) => {
|
||||
if (err) {
|
||||
err.status = codes.wrongrequest;
|
||||
|
@ -147,7 +155,8 @@ decoration.route('/:id')
|
|||
if (err) next(err);
|
||||
});
|
||||
|
||||
// we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler user.use(..)
|
||||
// we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler
|
||||
// user.use(..)
|
||||
res.locals.processed = true;
|
||||
next(err); // this works because err is in normal case undefined and that is the same as no parameter
|
||||
});
|
||||
|
|
|
@ -13,6 +13,7 @@ const LogBudgetModel = require('../models/logs/budget');
|
|||
const LogRespawnModel = require('../models/logs/respawn');
|
||||
const LogReviveModel = require('../models/logs/revive');
|
||||
const LogKillModel = require('../models/logs/kill');
|
||||
const LogVehicleModel = require('../models/logs/vehicle');
|
||||
const LogTransportModel = require('../models/logs/transport');
|
||||
const LogFlagModel = require('../models/logs/flag');
|
||||
const LogPointsModel = require('../models/logs/points');
|
||||
|
@ -43,6 +44,7 @@ logsRouter.route('/:warId')
|
|||
const respawnObjects = LogRespawnModel.find(filter, {}, sort);
|
||||
const reviveObjects = LogReviveModel.find(filter, {}, sort);
|
||||
const killObjects = LogKillModel.find(filter, {}, sort);
|
||||
const vehicleObjects = LogVehicleModel.find(filter, {}, sort);
|
||||
const transportObjects = LogTransportModel.find(filter, {}, sort);
|
||||
const flagObjects = LogFlagModel.find(filter, {}, sort);
|
||||
const resources = {
|
||||
|
@ -51,11 +53,12 @@ logsRouter.route('/:warId')
|
|||
respawn: respawnObjects.exec.bind(respawnObjects),
|
||||
revive: reviveObjects.exec.bind(reviveObjects),
|
||||
kill: killObjects.exec.bind(killObjects),
|
||||
vehicle: killObjects.exec.bind(vehicleObjects),
|
||||
transport: transportObjects.exec.bind(transportObjects),
|
||||
flag: flagObjects.exec.bind(flagObjects)
|
||||
};
|
||||
|
||||
async.parallel(resources, function (error, results){
|
||||
async.parallel(resources, function (error, results) {
|
||||
if (error) {
|
||||
res.status(500).send(error);
|
||||
return;
|
||||
|
|
|
@ -14,6 +14,9 @@ const CampaignModel = require('../models/campaign');
|
|||
const PlayerModel = require('../models/player');
|
||||
const WarModel = require('../models/war');
|
||||
|
||||
// Util
|
||||
const isSteamUUID = require('../tools/util').isSteamUUID;
|
||||
|
||||
const campaignPlayer = express.Router();
|
||||
|
||||
// routes **********************
|
||||
|
@ -33,13 +36,28 @@ campaignPlayer.route('/ranking/:campaignId')
|
|||
}
|
||||
|
||||
const rankingItems = [];
|
||||
new Set(items.map(x => x.name)).forEach(playerName => {
|
||||
const playerInstances = items.filter(p => p.name === playerName);
|
||||
const resItem = {name: playerName, kill: 0, death: 0, friendlyFire: 0, revive: 0, respawn: 0, flagTouch: 0};
|
||||
|
||||
// check only first player to have valid steamUUID - then decide if tracked by name or by ID
|
||||
const usesUUID = isSteamUUID(items[0].steamUUID);
|
||||
|
||||
new Set(items.map(usesUUID ? x => x.steamUUID : x => x.name))
|
||||
.forEach(player => {
|
||||
const playerInstances = items.filter(usesUUID ? p => p.steamUUID === player : p => p.name === player);
|
||||
const resItem = {
|
||||
name: usesUUID ? playerInstances[playerInstances.length - 1].name : player,
|
||||
kill: 0,
|
||||
vehicle: 0,
|
||||
death: 0,
|
||||
friendlyFire: 0,
|
||||
revive: 0,
|
||||
respawn: 0,
|
||||
flagTouch: 0
|
||||
};
|
||||
for (let i = 0; i < playerInstances.length; i++) {
|
||||
resItem.kill += playerInstances[i].kill;
|
||||
resItem.death += playerInstances[i].death;
|
||||
resItem.friendlyFire += playerInstances[i].friendlyFire;
|
||||
resItem.vehicle += playerInstances[i].vehicle;
|
||||
resItem.revive += playerInstances[i].revive;
|
||||
resItem.respawn += playerInstances[i].respawn;
|
||||
resItem.flagTouch += playerInstances[i].flagTouch;
|
||||
|
@ -62,6 +80,7 @@ campaignPlayer.route('/ranking/:campaignId')
|
|||
kill: getSortedField('kill'),
|
||||
death: getSortedField('death'),
|
||||
friendlyFire: getSortedField('friendlyFire'),
|
||||
vehicle: getSortedField('vehicle'),
|
||||
revive: getSortedField('revive'),
|
||||
respawn: getSortedField('respawn'),
|
||||
flagTouch: getSortedField('flagTouch')
|
||||
|
@ -75,7 +94,7 @@ campaignPlayer.route('/ranking/:campaignId')
|
|||
routerHandling.httpMethodNotAllowed
|
||||
);
|
||||
|
||||
campaignPlayer.route('/single/:campaignId/:playerName')
|
||||
campaignPlayer.route('/single/:campaignId/:playerId')
|
||||
.get((req, res, next) => {
|
||||
CampaignModel.findById(req.params.campaignId, (err, campaign) => {
|
||||
if (err) return next(err);
|
||||
|
@ -84,17 +103,24 @@ campaignPlayer.route('/single/:campaignId/:playerName')
|
|||
const warIds = wars.map((obj) => {
|
||||
return obj._id;
|
||||
});
|
||||
PlayerModel.find({name: req.params.playerName, warId: {"$in": warIds}})
|
||||
|
||||
// find by player name until v1.6.12, afterwards by SteamUUID
|
||||
const playerId = req.params.playerId;
|
||||
const filter = {};
|
||||
filter[isSteamUUID(playerId) ? 'steamUUID' : 'name'] = playerId;
|
||||
filter['warId'] = {"$in": warIds};
|
||||
|
||||
PlayerModel.find(filter)
|
||||
.populate('warId')
|
||||
.exec((err, items) => {
|
||||
if (err) return next(err);
|
||||
if (!items || items.length === 0) {
|
||||
const err = new Error('Unknown player name');
|
||||
const err = new Error('Unknown player id');
|
||||
err.status = codes.notfound;
|
||||
return next(err)
|
||||
}
|
||||
res.locals.items = {
|
||||
name: req.params.playerName,
|
||||
name: items[items.length - 1].name,
|
||||
campaign: campaign,
|
||||
players: items
|
||||
};
|
||||
|
|
|
@ -114,7 +114,8 @@ ranks.route('/:id')
|
|||
});
|
||||
}
|
||||
|
||||
// PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to reset attributes that are missing.
|
||||
// PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to
|
||||
// reset attributes that are missing.
|
||||
RankModel.findByIdAndUpdate(req.params.id, req.body, {new: true}, (err, item) => {
|
||||
if (err) {
|
||||
err.status = codes.wrongrequest;
|
||||
|
@ -139,7 +140,8 @@ ranks.route('/:id')
|
|||
err = new Error("item not found");
|
||||
err.status = codes.notfound;
|
||||
}
|
||||
// we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler user.use(..)
|
||||
// we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler
|
||||
// user.use(..)
|
||||
res.locals.processed = true;
|
||||
next(err); // this works because err is in normal case undefined and that is the same as no parameter
|
||||
})
|
||||
|
|
|
@ -141,7 +141,8 @@ request.route('/promotion/:id')
|
|||
req.body.updatedAt = new Date();
|
||||
req.body.$inc = {__v: 1};
|
||||
|
||||
// PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to reset attributes that are missing.
|
||||
// PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to
|
||||
// reset attributes that are missing.
|
||||
PromotionModel.findByIdAndUpdate(req.params.id, req.body, {new: true}, (err, item) => {
|
||||
if (err) {
|
||||
err.status = codes.wrongrequest;
|
||||
|
|
|
@ -116,7 +116,8 @@ squads.route('/:id')
|
|||
});
|
||||
}
|
||||
|
||||
// PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to reset attributes that are missing.
|
||||
// PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to
|
||||
// reset attributes that are missing.
|
||||
SquadModel.findByIdAndUpdate(req.params.id, req.body, {new: true}, (err, item) => {
|
||||
if (err) {
|
||||
err.status = codes.wrongrequest;
|
||||
|
@ -147,7 +148,8 @@ squads.route('/:id')
|
|||
if (err) next(err);
|
||||
});
|
||||
|
||||
// we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler user.use(..)
|
||||
// we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler
|
||||
// user.use(..)
|
||||
res.locals.processed = true;
|
||||
next(err); // this works because err is in normal case undefined and that is the same as no parameter
|
||||
});
|
||||
|
|
|
@ -118,7 +118,8 @@ users.route('/:id')
|
|||
req.body.updatedAt = new Date();
|
||||
req.body.$inc = {__v: 1};
|
||||
|
||||
// PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to reset attributes that are missing.
|
||||
// PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to
|
||||
// reset attributes that are missing.
|
||||
UserModel.findByIdAndUpdate(req.params.id, req.body, {new: true}, (err, item) => {
|
||||
if (err) {
|
||||
err.status = codes.wrongrequest;
|
||||
|
@ -156,7 +157,8 @@ users.route('/:id')
|
|||
// main difference of PUT and PATCH is that PUT expects all data in request: checked by using the schema
|
||||
const user = new UserModel(req.body);
|
||||
UserModel.findById(req.params.id, req.body, {new: true}, function (err, item) {
|
||||
// with parameter {new: true} the TweetNModel will return the new and changed object from the DB and not the old one.
|
||||
// with parameter {new: true} the TweetNModel will return the new and changed object from the DB and not the
|
||||
// old one.
|
||||
if (err) {
|
||||
err.status = codes.wrongrequest;
|
||||
return next(err);
|
||||
|
@ -225,7 +227,8 @@ users.route('/:id')
|
|||
});
|
||||
}
|
||||
|
||||
// we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler user.use(..)
|
||||
// we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler
|
||||
// user.use(..)
|
||||
res.locals.processed = true;
|
||||
next(err); // this works because err is in normal case undefined and that is the same as no parameter
|
||||
});
|
||||
|
|
|
@ -27,6 +27,7 @@ const CampaignModel = require('../models/campaign');
|
|||
const WarModel = require('../models/war');
|
||||
const PlayerModel = require('../models/player');
|
||||
const LogKillModel = require('../models/logs/kill');
|
||||
const LogVehicleKillModel = require('../models/logs/vehicle');
|
||||
const LogRespawnModel = require('../models/logs/respawn');
|
||||
const LogReviveModel = require('../models/logs/revive');
|
||||
const LogTransportModel = require('../models/logs/transport');
|
||||
|
@ -92,6 +93,8 @@ wars.route('/')
|
|||
return next(err);
|
||||
}
|
||||
LogKillModel.create(statsResult.kills, function () {
|
||||
LogVehicleKillModel.create(statsResult.vehicles, function () {
|
||||
|
||||
LogRespawnModel.create(statsResult.respawn, function () {
|
||||
LogReviveModel.create(statsResult.revive, function () {
|
||||
LogFlagModel.create(statsResult.flag, function () {
|
||||
|
@ -129,6 +132,7 @@ wars.route('/')
|
|||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
} else {
|
||||
|
@ -207,7 +211,8 @@ wars.route('/:id')
|
|||
fs.rmdir(warDir, (err) => {
|
||||
});
|
||||
}
|
||||
// we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler user.use(..)
|
||||
// we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler
|
||||
// user.use(..)
|
||||
res.locals.processed = true;
|
||||
next();
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ const playerArrayContains = require('./util').playerArrayContains;
|
|||
const WHITESPACE = ' ';
|
||||
|
||||
const parseWarLog = (lineArray, war) => {
|
||||
|
||||
const NAME_TOO_LONG_ERROR = 'Error: ENAMETOOLONG: name too long, open \'';
|
||||
|
||||
const stats = {
|
||||
|
@ -13,6 +14,7 @@ const parseWarLog = (lineArray, war) => {
|
|||
budget: [],
|
||||
points: [],
|
||||
kills: [],
|
||||
vehicles: [],
|
||||
respawn: [],
|
||||
revive: [],
|
||||
flag: [],
|
||||
|
@ -20,10 +22,21 @@ const parseWarLog = (lineArray, war) => {
|
|||
players: []
|
||||
};
|
||||
|
||||
const addPlayerIfNotExists = (inputPlayer) => {
|
||||
const vehicleBlacklist = [
|
||||
'Prowler (Unbewaffnet)', 'Prowler (Bewaffnet)', 'Hunter',
|
||||
'HEMTT Transporter', 'HEMTT Transporter (abgedeckt)', 'HEMTT SanitÀtsfahrzeug',
|
||||
'Remote Designator [NATO]', 'UGV Stomper',
|
||||
'Qilin (Unbewaffnet)', 'Qilin (Bewaffnet)', 'Ifrit',
|
||||
'Tempest-Transporter', 'Tempest-Transporter (abgedeckt)', 'Tempest SanitÀtsfahrzeug',
|
||||
'Remote Designator [CSAT]', 'UBF Saif',
|
||||
'Quad Bike', 'HuntIR'
|
||||
];
|
||||
|
||||
const addPlayerIfNotExists = (inputPlayer, steamUUID) => {
|
||||
const player = getPlayerAndFractionFromString(inputPlayer);
|
||||
if (player && player.name && player.fraction && !playerArrayContains(stats.players, player)) {
|
||||
player['warId'] = war._id;
|
||||
player['steamUUID'] = steamUUID;
|
||||
stats.players.push(player);
|
||||
}
|
||||
};
|
||||
|
@ -37,15 +50,29 @@ const parseWarLog = (lineArray, war) => {
|
|||
}
|
||||
|
||||
/**
|
||||
* KILLS
|
||||
* KILLS & VEHICLE KILLS
|
||||
*/
|
||||
if (line.includes('(Abschuss)') && !line.includes('Fahrzeug')) {
|
||||
if (line.includes('(Abschuss)')) {
|
||||
stats.clean.push(line);
|
||||
|
||||
const shooterString = line.substring(line.lastIndexOf(' von: ') + 6, line.lastIndexOf('."'));
|
||||
const shooter = getPlayerAndFractionFromString(shooterString);
|
||||
|
||||
if (line.includes('Fahrzeug:')) {
|
||||
const targetString = line.substring(line.lastIndexOf(' --- Fahrzeug: ') + 15, line.lastIndexOf(' von:'));
|
||||
const target = getVehicleAndFractionFromString(targetString);
|
||||
if (target && shooter && target.fraction !== shooter.fraction) {
|
||||
stats.vehicles.push({
|
||||
war: war._id,
|
||||
time: getFullTimeDate(war.date, line.split(WHITESPACE)[5]),
|
||||
shooter: shooter ? shooter.name : null,
|
||||
target: target ? target.name : null,
|
||||
fraction: shooter ? shooter.fraction : 'NONE'
|
||||
})
|
||||
}
|
||||
} else {
|
||||
const targetString = line.substring(line.lastIndexOf(' --- ') + 5, line.lastIndexOf(' von:'));
|
||||
const target = getPlayerAndFractionFromString(targetString);
|
||||
|
||||
stats.kills.push({
|
||||
war: war._id,
|
||||
time: getFullTimeDate(war.date, line.split(WHITESPACE)[5]),
|
||||
|
@ -55,6 +82,7 @@ const parseWarLog = (lineArray, war) => {
|
|||
fraction: shooter ? shooter.fraction : 'NONE'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* BUDGET
|
||||
|
@ -171,7 +199,8 @@ const parseWarLog = (lineArray, war) => {
|
|||
*/
|
||||
else if (line.includes('(Fraktionsuebersicht)')) {
|
||||
const playerString = line.substring(line.lastIndexOf('--- ') + 4, line.lastIndexOf(', PUID'));
|
||||
addPlayerIfNotExists(playerString)
|
||||
const playerUUID = line.substring(line.lastIndexOf('PUID ') + 5, line.lastIndexOf('"'));
|
||||
addPlayerIfNotExists(playerString, playerUUID)
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -179,6 +208,7 @@ const parseWarLog = (lineArray, war) => {
|
|||
const playerName = stats.players[i].name;
|
||||
stats.players[i]['respawn'] = stats.respawn.filter(res => res.player === playerName).length;
|
||||
stats.players[i]['kill'] = stats.kills.filter(kill => kill.shooter === playerName && !kill.friendlyFire).length;
|
||||
stats.players[i]['vehicle'] = stats.vehicles.filter(vehicle => vehicle.shooter === playerName && vehicleBlacklist.indexOf(vehicle.target) < 0).length;
|
||||
stats.players[i]['friendlyFire'] = stats.kills.filter(kill => kill.shooter === playerName && kill.friendlyFire).length;
|
||||
stats.players[i]['death'] = stats.kills.filter(kill => kill.target === playerName).length;
|
||||
stats.players[i]['revive'] = stats.revive.filter(rev => rev.medic === playerName && !rev.stabilized).length;
|
||||
|
@ -231,6 +261,21 @@ const getPlayerAndFractionFromString = (nameAndFractionString) => {
|
|||
}
|
||||
};
|
||||
|
||||
const getVehicleAndFractionFromString = (nameAndFractionString) => {
|
||||
const nameArray = nameAndFractionString.trim().split(WHITESPACE);
|
||||
const fractionPart = nameArray[nameArray.length - 1];
|
||||
|
||||
// escape it is some parachute fraction identifier
|
||||
if (fractionPart === 'OPF_F' || fractionPart === 'BLU_F') {
|
||||
return;
|
||||
}
|
||||
|
||||
const fraction = fractionPart === '(OPT_NATO)' || fractionPart === '(OPT_NATO_T)' ? 'BLUFOR' : 'OPFOR';
|
||||
const name = nameAndFractionString.substring(0, nameAndFractionString.indexOf(fractionPart) - 1);
|
||||
|
||||
return {name: name, fraction: fraction};
|
||||
};
|
||||
|
||||
const transformMoneyString = (budgetString) => {
|
||||
if (!budgetString.includes('e+')) {
|
||||
return parseInt(budgetString);
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
"use strict";
|
||||
|
||||
const isSteamUUID = (input) => {
|
||||
const steamUIDPattern = new RegExp("[0-9]{17}");
|
||||
return steamUIDPattern.test(input)
|
||||
};
|
||||
|
||||
const sortCollectionBy = (collection, key) => {
|
||||
collection.sort((a, b) => {
|
||||
a = a[key].toLowerCase();
|
||||
|
@ -44,6 +49,7 @@ const decimalToTimeString = (decimal) => {
|
|||
(seconds < 10 ? '0' + seconds : seconds);
|
||||
};
|
||||
|
||||
exports.isSteamUUID = isSteamUUID;
|
||||
exports.sortCollection = sortCollectionBy;
|
||||
exports.playerArrayContains = playerArrayContains;
|
||||
exports.timeStringToDecimal = timeStringToDecimal;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "opt-cc",
|
||||
"version": "1.6.12",
|
||||
"version": "1.7.0",
|
||||
"author": "Florian Hartwich <hardi@noarch.de>",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.overview {
|
||||
padding: 80px 0 0 10%!important;
|
||||
padding: 80px 0 0 10% !important;
|
||||
}
|
||||
|
||||
.trash {
|
||||
|
|
|
@ -30,7 +30,7 @@ li {
|
|||
}
|
||||
|
||||
.version-label {
|
||||
display:block;
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 32px;
|
||||
left: 106px;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
.army-member-view-container {
|
||||
width: 90%;
|
||||
min-width: 870px;
|
||||
margin:auto
|
||||
margin: auto
|
||||
}
|
||||
|
||||
.return-button {
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
<div class="army-member-view-container">
|
||||
<div class="return-button">
|
||||
<span class="btn btn-default" style="position:absolute;" (click)="backToOverview()">< zurück zur Übersicht</span>
|
||||
<h3 class="text-center" style="font-weight: 600" [style.color]="user.squadId?.fraction === 'BLUFOR' ? fraction.COLOR_BLUFOR : fraction.COLOR_OPFOR">
|
||||
<h3 class="text-center" style="font-weight: 600"
|
||||
[style.color]="user.squadId?.fraction === 'BLUFOR' ? fraction.COLOR_BLUFOR : fraction.COLOR_OPFOR">
|
||||
Auszeichnungen von {{user.username}}
|
||||
</h3>
|
||||
</div>
|
||||
|
|
|
@ -24,6 +24,7 @@ export interface Player {
|
|||
name?: string;
|
||||
warId?: War;
|
||||
kill?: number;
|
||||
vehicle?: number;
|
||||
death?: number;
|
||||
friendlyFire?: number;
|
||||
revive?: number;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.overview {
|
||||
width: 100%!important;
|
||||
margin-left: 25px!important;
|
||||
width: 100% !important;
|
||||
margin-left: 25px !important;
|
||||
}
|
||||
|
||||
.decoration-preview {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.overview {
|
||||
margin-left: 25px!important;
|
||||
margin-left: 25px !important;
|
||||
}
|
||||
|
||||
.decoration-preview {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.overview {
|
||||
margin-left: 25px!important;
|
||||
margin-left: 25px !important;
|
||||
}
|
||||
|
||||
.decoration-preview {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.overview {
|
||||
margin-left: 25px!important;
|
||||
margin-left: 25px !important;
|
||||
}
|
||||
|
||||
.decoration-preview {
|
||||
|
|
|
@ -38,7 +38,8 @@ export class UserService {
|
|||
}
|
||||
}).map(res => res.json()).do((users) => {
|
||||
this.userStore.dispatch({type: action, data: users});
|
||||
}).subscribe(_ => {});
|
||||
}).subscribe(_ => {
|
||||
});
|
||||
|
||||
return this.users$;
|
||||
}
|
||||
|
|
|
@ -81,6 +81,26 @@
|
|||
</ngx-charts-line-chart>
|
||||
</div>
|
||||
|
||||
<div class="chart-container">
|
||||
<ngx-charts-line-chart
|
||||
[results]="vehicleKillData"
|
||||
[showRefLines]="showRefLines"
|
||||
[showRefLabels]="showRefLabels"
|
||||
[referenceLines]="killRefLines"
|
||||
[scheme]="colorScheme"
|
||||
[gradient]="gradient"
|
||||
[xAxis]="xAxis"
|
||||
[yAxis]="yAxis"
|
||||
[legend]="legend"
|
||||
[showXAxisLabel]="showXAxisLabel"
|
||||
[showYAxisLabel]="showYAxisLabel"
|
||||
[yAxisLabel]="yAxisVehicleKill"
|
||||
[autoScale]="autoscale"
|
||||
[timeline]="timeline"
|
||||
[roundDomains]="roundDomains">
|
||||
</ngx-charts-line-chart>
|
||||
</div>
|
||||
|
||||
<div class="chart-container">
|
||||
<ngx-charts-line-chart
|
||||
[results]="deathData"
|
||||
|
|
|
@ -25,6 +25,7 @@ export class CampaignPlayerDetailComponent {
|
|||
sumData: any[] = [];
|
||||
killData: any[] = [];
|
||||
friendlyFireData: any[] = [];
|
||||
vehicleKillData: any[] = [];
|
||||
deathData: any[] = [];
|
||||
respawnData: any[] = [];
|
||||
reviveData: any[] = [];
|
||||
|
@ -32,6 +33,7 @@ export class CampaignPlayerDetailComponent {
|
|||
|
||||
yAxisKill = 'Kills';
|
||||
yAxisFriendlyFire = 'FriendlyFire';
|
||||
yAxisVehicleKill = 'Farzeug-Kills';
|
||||
yAxisDeath = 'Tode';
|
||||
yAxisRespawn = 'Respawn';
|
||||
yAxisRevive = 'Revive';
|
||||
|
@ -49,6 +51,7 @@ export class CampaignPlayerDetailComponent {
|
|||
showRefLines = true;
|
||||
showRefLabels = true;
|
||||
killRefLines = [];
|
||||
vehicleKillRefLines = [];
|
||||
deathRefLines = [];
|
||||
captureRefLines = [];
|
||||
friendlyFireRefLines = [];
|
||||
|
@ -67,6 +70,7 @@ export class CampaignPlayerDetailComponent {
|
|||
|
||||
totalKills;
|
||||
totalFriendlyFire;
|
||||
totalVehicleKills;
|
||||
totalDeath;
|
||||
totalRespawn;
|
||||
totalRevive;
|
||||
|
@ -87,6 +91,7 @@ export class CampaignPlayerDetailComponent {
|
|||
.subscribe(campaignPlayer => {
|
||||
this.campaignPlayer = campaignPlayer;
|
||||
this.killData = this.assignData(this.yAxisKill, "kill");
|
||||
this.vehicleKillData = this.assignData(this.yAxisVehicleKill, "vehicle");
|
||||
this.friendlyFireData = this.assignData(this.yAxisFriendlyFire, "friendlyFire");
|
||||
this.deathData = this.assignData(this.yAxisDeath, "death");
|
||||
this.respawnData = this.assignData(this.yAxisRespawn, "respawn");
|
||||
|
@ -107,6 +112,10 @@ export class CampaignPlayerDetailComponent {
|
|||
name: this.yAxisFriendlyFire,
|
||||
value: this.totalFriendlyFire
|
||||
},
|
||||
{
|
||||
name: this.yAxisVehicleKill,
|
||||
value: this.totalVehicleKills
|
||||
},
|
||||
{
|
||||
name: this.yAxisDeath,
|
||||
value: this.totalDeath
|
||||
|
@ -125,7 +134,7 @@ export class CampaignPlayerDetailComponent {
|
|||
}
|
||||
];
|
||||
|
||||
Object.assign(this, [this.sumData, this.killData, this.friendlyFireData, this.deathData, this.respawnData, this.reviveData, this.captureData]);
|
||||
Object.assign(this, [this.sumData, this.killData, this.friendlyFireData, this.vehicleKillData, this.deathData, this.respawnData, this.reviveData, this.captureData]);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -138,12 +147,12 @@ export class CampaignPlayerDetailComponent {
|
|||
let total = 0;
|
||||
for (let i = 0; i < playerLength; i++) {
|
||||
const warDateString = ChartUtils.getShortDateString(this.campaignPlayer.players[i].warId.date);
|
||||
const warKills = this.campaignPlayer.players[i][field];
|
||||
const value = this.campaignPlayer.players[i][field];
|
||||
killObj.series.push({
|
||||
name: warDateString,
|
||||
value: warKills
|
||||
value: value
|
||||
});
|
||||
total += warKills;
|
||||
total += value;
|
||||
}
|
||||
switch (field) {
|
||||
case 'kill':
|
||||
|
@ -154,6 +163,10 @@ export class CampaignPlayerDetailComponent {
|
|||
this.friendlyFireRefLines.push({value: total / playerLength, name: this.avgLabel});
|
||||
this.totalFriendlyFire = total;
|
||||
break;
|
||||
case 'vehicle':
|
||||
this.vehicleKillRefLines.push({value: total / playerLength, name: this.avgLabel});
|
||||
this.totalVehicleKills = total;
|
||||
break;
|
||||
case 'death':
|
||||
this.deathRefLines.push({value: total / playerLength, name: this.avgLabel});
|
||||
this.totalDeath = total;
|
||||
|
|
|
@ -18,12 +18,10 @@ ngx-datatable {
|
|||
float: left;
|
||||
border: solid #dfdfdf 1px;
|
||||
border-radius: 10px 10px 2px 2px;
|
||||
border-right-style: none;
|
||||
border-top-style: none;
|
||||
}
|
||||
|
||||
:host /deep/ .datatable-header {
|
||||
width: 350px!important;
|
||||
width: 350px !important;
|
||||
background: #222222;
|
||||
font-weight: 700;
|
||||
border-radius: 10px 10px 0 0;
|
||||
|
@ -74,5 +72,4 @@ ngx-datatable {
|
|||
background: #4b4b4b;
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
/* Table Scrollbar END */
|
||||
|
|
|
@ -36,6 +36,48 @@
|
|||
<ngx-datatable-column [width]="valueColWidth" name="Kills" prop="kill"></ngx-datatable-column>
|
||||
</ngx-datatable>
|
||||
|
||||
<ngx-datatable
|
||||
[rows]="players.friendlyFire"
|
||||
[messages]="emptyMessage"
|
||||
[headerHeight]="cellHeight"
|
||||
[rowHeight]="cellHeight"
|
||||
[cssClasses]='customClasses'
|
||||
[columnMode]="'force'"
|
||||
[scrollbarV]="true"
|
||||
[selectionType]="'single'">
|
||||
<ngx-datatable-column [width]="numberColWidth" name="#" prop="num"></ngx-datatable-column>
|
||||
<ngx-datatable-column name="Spieler" prop="name" [width]="nameColWidth" style="padding-left:10px">
|
||||
<ng-template ngx-datatable-cell-template let-row="row" let-value="value">
|
||||
<span class="player-name"
|
||||
[style.color]="row['fraction'] === 'BLUFOR' ? fraction.COLOR_BLUFOR : fraction.COLOR_OPFOR">
|
||||
{{value}}
|
||||
</span>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column [width]="valueColWidth" name="FriendlyFire" prop="friendlyFire"></ngx-datatable-column>
|
||||
</ngx-datatable>
|
||||
|
||||
<ngx-datatable
|
||||
[rows]="players.vehicle"
|
||||
[messages]="emptyMessage"
|
||||
[headerHeight]="cellHeight"
|
||||
[rowHeight]="cellHeight"
|
||||
[cssClasses]='customClasses'
|
||||
[columnMode]="'force'"
|
||||
[scrollbarV]="true"
|
||||
[selectionType]="'single'">
|
||||
<ngx-datatable-column [width]="numberColWidth" name="#" prop="num"></ngx-datatable-column>
|
||||
<ngx-datatable-column name="Spieler" prop="name" [width]="nameColWidth" style="padding-left:10px">
|
||||
<ng-template ngx-datatable-cell-template let-row="row" let-value="value">
|
||||
<span class="player-name"
|
||||
[style.color]="row['fraction'] === 'BLUFOR' ? fraction.COLOR_BLUFOR : fraction.COLOR_OPFOR">
|
||||
{{value}}
|
||||
</span>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column [width]="valueColWidth" name="Fahrzeug-Kills" prop="vehicle"></ngx-datatable-column>
|
||||
</ngx-datatable>
|
||||
|
||||
<ngx-datatable
|
||||
[rows]="players.death"
|
||||
[messages]="emptyMessage"
|
||||
|
@ -78,27 +120,6 @@
|
|||
<ngx-datatable-column [width]="valueColWidth" name="Respawn" prop="respawn"></ngx-datatable-column>
|
||||
</ngx-datatable>
|
||||
|
||||
<ngx-datatable
|
||||
[rows]="players.friendlyFire"
|
||||
[messages]="emptyMessage"
|
||||
[headerHeight]="cellHeight"
|
||||
[rowHeight]="cellHeight"
|
||||
[cssClasses]='customClasses'
|
||||
[columnMode]="'force'"
|
||||
[scrollbarV]="true"
|
||||
[selectionType]="'single'">
|
||||
<ngx-datatable-column [width]="numberColWidth" name="#" prop="num"></ngx-datatable-column>
|
||||
<ngx-datatable-column name="Spieler" prop="name" [width]="nameColWidth" style="padding-left:10px">
|
||||
<ng-template ngx-datatable-cell-template let-row="row" let-value="value">
|
||||
<span class="player-name"
|
||||
[style.color]="row['fraction'] === 'BLUFOR' ? fraction.COLOR_BLUFOR : fraction.COLOR_OPFOR">
|
||||
{{value}}
|
||||
</span>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column [width]="valueColWidth" name="FriendlyFire" prop="friendlyFire"></ngx-datatable-column>
|
||||
</ngx-datatable>
|
||||
|
||||
<ngx-datatable
|
||||
[rows]="players.revive"
|
||||
[messages]="emptyMessage"
|
||||
|
|
|
@ -22,7 +22,7 @@ export class StatisticHighScoreComponent {
|
|||
|
||||
searchTerm = new FormControl();
|
||||
|
||||
players : Player = {};
|
||||
players: Player = {};
|
||||
|
||||
playersStored = {};
|
||||
|
||||
|
@ -86,6 +86,7 @@ export class StatisticHighScoreComponent {
|
|||
this.players = {
|
||||
kill: this.filterPlayerAttribute('kill'),
|
||||
friendlyFire: this.filterPlayerAttribute('friendlyFire'),
|
||||
vehicle: this.filterPlayerAttribute('vehicle'),
|
||||
death: this.filterPlayerAttribute('death'),
|
||||
respawn: this.filterPlayerAttribute('respawn'),
|
||||
revive: this.filterPlayerAttribute('revive'),
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
btnRadio="{{labelKill}}">{{labelKill}}</label>
|
||||
<label class="btn btn-default btn-dark" [(ngModel)]="chartSelectModel"
|
||||
btnRadio="{{labelFriendlyFire}}">{{labelFriendlyFire}}</label>
|
||||
<label class="btn btn-default btn-dark" [(ngModel)]="chartSelectModel"
|
||||
btnRadio="{{labelVehicle}}">{{labelVehicle}}</label>
|
||||
<label class="btn btn-default btn-dark" [(ngModel)]="chartSelectModel"
|
||||
btnRadio="{{labelRevive}}">{{labelRevive}}</label>
|
||||
<label class="btn btn-default btn-dark" [(ngModel)]="chartSelectModel"
|
||||
|
|
|
@ -34,6 +34,7 @@ export class FractionStatsComponent {
|
|||
tmpBudgetData;
|
||||
tmpKillData;
|
||||
tmpFrienlyFireData;
|
||||
tmpVehicleData;
|
||||
tmpTransportData;
|
||||
tmpReviveData;
|
||||
tmpStabilizeData;
|
||||
|
@ -47,6 +48,7 @@ export class FractionStatsComponent {
|
|||
labelBudget = 'Budget';
|
||||
labelKill = 'Kills';
|
||||
labelFriendlyFire = 'FriendlyFire';
|
||||
labelVehicle = 'Fahrzeug-Kills';
|
||||
labelTransport = 'Lufttransport';
|
||||
labelRevive = 'Revive';
|
||||
labelStabilize = 'Stabilisiert';
|
||||
|
@ -111,6 +113,10 @@ export class FractionStatsComponent {
|
|||
this.initKillData();
|
||||
this.lineChartData = this.tmpFrienlyFireData;
|
||||
break;
|
||||
case this.labelVehicle:
|
||||
this.initVehicleData();
|
||||
this.lineChartData = this.tmpVehicleData;
|
||||
break;
|
||||
case this.labelRevive:
|
||||
this.initRevive();
|
||||
this.lineChartData = this.tmpReviveData;
|
||||
|
@ -250,6 +256,30 @@ export class FractionStatsComponent {
|
|||
this.initialized.revive = true;
|
||||
}
|
||||
|
||||
initVehicleData() {
|
||||
if (this.initialized.vehicle) {
|
||||
return;
|
||||
}
|
||||
let vehicleKillCountBlufor = 0, vehicleKillCountOpfor = 0;
|
||||
for (const {transportEntry: vehicleEntry, index} of this.logData.vehicle.map((transportEntry, index) => ({
|
||||
transportEntry,
|
||||
index
|
||||
}))) {
|
||||
const vehicleEntryDate = new Date(vehicleEntry.time);
|
||||
if (vehicleEntry.fraction === 'BLUFOR') {
|
||||
vehicleKillCountBlufor++;
|
||||
} else {
|
||||
vehicleKillCountOpfor++;
|
||||
}
|
||||
if (this.isTwoMinutesAhead(vehicleEntryDate, this.tmpVehicleData) || index === this.logData.vehicle.length - 1) {
|
||||
this.tmpVehicleData[0].series.push(ChartUtils.getSeriesEntry(vehicleEntryDate, vehicleKillCountBlufor));
|
||||
this.tmpVehicleData[1].series.push(ChartUtils.getSeriesEntry(vehicleEntryDate, vehicleKillCountOpfor));
|
||||
}
|
||||
}
|
||||
this.addFinalTimeData(this.tmpVehicleData);
|
||||
this.initialized.vehicle = true;
|
||||
}
|
||||
|
||||
initTransportData() {
|
||||
if (this.initialized.transport) {
|
||||
return;
|
||||
|
@ -272,7 +302,6 @@ export class FractionStatsComponent {
|
|||
}
|
||||
this.addFinalTimeData(this.tmpTransportData);
|
||||
this.initialized.transport = true;
|
||||
|
||||
}
|
||||
|
||||
initFlagHoldData() {
|
||||
|
@ -308,12 +337,13 @@ export class FractionStatsComponent {
|
|||
this.tmpBudgetData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR);
|
||||
this.tmpKillData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR);
|
||||
this.tmpFrienlyFireData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR);
|
||||
this.tmpVehicleData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR);
|
||||
this.tmpTransportData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR);
|
||||
this.tmpReviveData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR);
|
||||
this.tmpStabilizeData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR);
|
||||
this.tmpFlagCaptureData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR);
|
||||
|
||||
[this.tmpKillData, this.tmpFrienlyFireData, this.tmpReviveData, this.tmpStabilizeData, this.tmpTransportData].forEach(tmp => {
|
||||
[this.tmpKillData, this.tmpFrienlyFireData, this.tmpVehicleData, this.tmpReviveData, this.tmpStabilizeData, this.tmpTransportData].forEach(tmp => {
|
||||
[0, 1].forEach(index => {
|
||||
tmp[index].series.push(ChartUtils.getSeriesEntry(this.startDateObj, 0));
|
||||
})
|
||||
|
|
|
@ -11,7 +11,7 @@ ngx-datatable {
|
|||
}
|
||||
|
||||
:host /deep/ .datatable-header {
|
||||
width: 1100px!important;
|
||||
width: 1100px !important;
|
||||
background: #222222;
|
||||
font-weight: 700;
|
||||
border-radius: 10px 10px 0 0;
|
||||
|
|
|
@ -25,18 +25,22 @@
|
|||
</ngx-datatable-column>
|
||||
<ngx-datatable-column [width]="90" name="Kills" prop="kill"></ngx-datatable-column>
|
||||
<ngx-datatable-column [width]="104" name="FriendlyFire" prop="friendlyFire"></ngx-datatable-column>
|
||||
<ngx-datatable-column [width]="90" name="Fahrzeug" prop="vehicle"></ngx-datatable-column>
|
||||
<ngx-datatable-column [width]="80" name="Revive" prop="revive"></ngx-datatable-column>
|
||||
<ngx-datatable-column [width]="100" name="Eroberung" prop="flagTouch"></ngx-datatable-column>
|
||||
<ngx-datatable-column [width]="70" name="Tod" prop="death"></ngx-datatable-column>
|
||||
<ngx-datatable-column [width]="90" name="Respawn" prop="respawn"></ngx-datatable-column>
|
||||
<ngx-datatable-column [width]="80" name="" prop="name">
|
||||
<ng-template ngx-datatable-cell-template let-value="value">
|
||||
<span class="btn btn-sm btn-default in-table-btn disabled">Detail</span>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column [width]="80" name="" prop="name">
|
||||
<ng-template ngx-datatable-cell-template let-value="value">
|
||||
<span class="btn btn-sm btn-default in-table-btn" (click)="selectPlayerDetail(1, value)">Gesamt</span>
|
||||
<!--<ngx-datatable-column [width]="80" name="" prop="name">-->
|
||||
<!--<ng-template ngx-datatable-cell-template let-value="value">-->
|
||||
<!--<span class="btn btn-sm btn-default in-table-btn disabled">Detail</span>-->
|
||||
<!--</ng-template>-->
|
||||
<!--</ngx-datatable-column>-->
|
||||
<ngx-datatable-column [width]="80">
|
||||
<ng-template ngx-datatable-cell-template let-row="row">
|
||||
<span class="btn btn-sm btn-default in-table-btn"
|
||||
(click)="selectPlayerDetail(1, isSteamUUID(row['steamUUID']) ? row['steamUUID'] : row['name'])">
|
||||
Gesamt
|
||||
</span>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
</ngx-datatable>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {Component, EventEmitter, SimpleChanges} from "@angular/core";
|
||||
import {Component, ElementRef, EventEmitter, SimpleChanges} from "@angular/core";
|
||||
import {War} from "../../../models/model-interfaces";
|
||||
import {Fraction} from "../../../utils/fraction.enum";
|
||||
import {PlayerUtils} from "../../../utils/player-utils";
|
||||
|
||||
@Component({
|
||||
selector: 'scoreboard',
|
||||
|
@ -17,6 +18,8 @@ export class ScoreboardComponent {
|
|||
|
||||
war: War;
|
||||
|
||||
isSteamUUID = PlayerUtils.isSteamUUID;
|
||||
|
||||
fractionFilterSelected: string;
|
||||
|
||||
cellHeight = 40;
|
||||
|
@ -30,19 +33,22 @@ export class ScoreboardComponent {
|
|||
sortDescending: 'glyphicon glyphicon-triangle-bottom',
|
||||
};
|
||||
|
||||
constructor() {
|
||||
constructor(private elRef: ElementRef) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
selectPlayerDetail(view: number, playerName: string) {
|
||||
this.playerTabSwitch.emit({view: view, player: playerName})
|
||||
selectPlayerDetail(view: number, player) {
|
||||
this.playerTabSwitch.emit({
|
||||
view: view,
|
||||
player: player
|
||||
})
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes.war) {
|
||||
this.rows = changes.war.currentValue.players;
|
||||
this.elRef.nativeElement
|
||||
.querySelector('.datatable-body')
|
||||
.scrollTo(0, 0);
|
||||
}
|
||||
if (changes.fractionFilterSelected) {
|
||||
this.filterPlayersByFraction(this.fractionFilterSelected)
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
}
|
||||
|
||||
.nav-tabs {
|
||||
width: 980px;
|
||||
margin: auto;
|
||||
clear: both;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<ul class="nav nav-tabs" style="width:980px; margin:auto">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="nav-item" [ngClass]="{active :tab === 0}" (click)="switchTab(0)">
|
||||
<a class="nav-link"><img src="../../../assets/scoreboard-btn.png"> Scoreboard</a>
|
||||
</li>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.overview {
|
||||
overflow: hidden!important;
|
||||
padding-top: 80px!important;
|
||||
overflow: hidden !important;
|
||||
padding-top: 80px !important;
|
||||
width: 20%;
|
||||
min-width: 280px;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ div.user-list-entry, a.user-list-entry {
|
|||
background: lightgrey;
|
||||
}
|
||||
|
||||
span > a, span.glyphicon, span.icon-award{
|
||||
span > a, span.glyphicon, span.icon-award {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ export class ChartUtils {
|
|||
};
|
||||
}
|
||||
|
||||
public static getMultiDataArray(...args: string[]) : any[] {
|
||||
public static getMultiDataArray(...args: string[]): any[] {
|
||||
const obj = [];
|
||||
for (let i = 0, arg; arg = args[i]; i++) {
|
||||
obj.push({
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
export class PlayerUtils {
|
||||
|
||||
public static isSteamUUID(input: string): boolean {
|
||||
const steamUIDPattern = new RegExp("[0-9]{17}");
|
||||
return steamUIDPattern.test(input)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue