init
This commit is contained in:
123
matches/matches.controller.js
Normal file
123
matches/matches.controller.js
Normal file
@@ -0,0 +1,123 @@
|
||||
const MatchModel = require('./matches.model');
|
||||
const MatchTool = require('./matches.tool');
|
||||
const UserModel = require('../users/users.model');
|
||||
const DateTool = require('../tools/date.tool');
|
||||
const config = require('../config');
|
||||
|
||||
exports.addMatch = async(req, res) => {
|
||||
|
||||
var tid = req.body.tid;
|
||||
var players = req.body.players;
|
||||
var ranked = req.body.ranked ? true : false;
|
||||
var mode = req.body.mode || "";
|
||||
|
||||
if (!tid || !players || !Array.isArray(players) || players.length != 2)
|
||||
return res.status(400).send({ error: "Invalid parameters" });
|
||||
|
||||
if (mode && typeof mode !== "string")
|
||||
return res.status(400).send({ error: "Invalid parameters" });
|
||||
|
||||
var fmatch = await MatchModel.get(tid);
|
||||
if(fmatch)
|
||||
return res.status(400).send({error:"Match already exists: " + tid});
|
||||
|
||||
var player0 = await UserModel.getByUsername(players[0]);
|
||||
var player1 = await UserModel.getByUsername(players[1]);
|
||||
if(!player0 || !player1)
|
||||
return res.status(404).send({error:"Can't find players"});
|
||||
|
||||
if(player0.id == player1.id)
|
||||
return res.status(400).send({error:"Can't play against yourself"});
|
||||
|
||||
var match = {};
|
||||
match.tid = tid;
|
||||
match.players = players;
|
||||
match.winner = "";
|
||||
match.completed = false;
|
||||
match.ranked = ranked;
|
||||
match.mode = mode;
|
||||
match.start = Date.now();
|
||||
match.end = Date.now();
|
||||
match.udata = [];
|
||||
match.udata.push(MatchTool.GetPlayerData(player0));
|
||||
match.udata.push(MatchTool.GetPlayerData(player1));
|
||||
|
||||
var match = await MatchModel.create(match);
|
||||
if(!match)
|
||||
return res.status(500).send({error:"Unable to create match"});
|
||||
|
||||
res.status(200).send(match);
|
||||
|
||||
};
|
||||
|
||||
exports.completeMatch = async(req, res) => {
|
||||
|
||||
var matchId = req.body.tid;
|
||||
var winner = req.body.winner;
|
||||
|
||||
if (!matchId || !winner)
|
||||
return res.status(400).send({ error: "Invalid parameters" });
|
||||
|
||||
if(typeof matchId != "string" || typeof winner != "string")
|
||||
return res.status(400).send({error: "Invalid parameters" });
|
||||
|
||||
var match = await MatchModel.get(matchId);
|
||||
if(!match)
|
||||
return res.status(404).send({error: "Match not found"});
|
||||
|
||||
if(match.completed)
|
||||
return res.status(400).send({error: "Match already completed"});
|
||||
|
||||
var player0 = await UserModel.getByUsername(match.players[0]);
|
||||
var player1 = await UserModel.getByUsername(match.players[1]);
|
||||
if(!player0 || !player1)
|
||||
return res.status(404).send({error:"Can't find players"});
|
||||
|
||||
match.end = Date.now();
|
||||
match.winner = winner;
|
||||
match.completed = true;
|
||||
|
||||
//Add Rewards
|
||||
if(match.ranked)
|
||||
{
|
||||
match.udata[0].reward = await MatchTool.GainMatchReward(player0, player1, winner);
|
||||
match.udata[1].reward = await MatchTool.GainMatchReward(player1, player0, winner);
|
||||
match.markModified('udata');
|
||||
}
|
||||
|
||||
//Save match
|
||||
var uMatch = await match.save();
|
||||
|
||||
//Return
|
||||
res.status(200).send(uMatch);
|
||||
};
|
||||
|
||||
exports.getAll = async(req, res) => {
|
||||
|
||||
var start = req.query.start ? DateTool.tagToDate(req.query.start) : null;
|
||||
var end = req.query.end ? DateTool.tagToDate(req.query.end) : null;
|
||||
|
||||
var matches = await MatchModel.list(start, end);
|
||||
if(!matches)
|
||||
return res.status(400).send({error: "Invalid Parameters"});
|
||||
|
||||
return res.status(200).send(matches);
|
||||
};
|
||||
|
||||
exports.getByTid = async(req, res) => {
|
||||
|
||||
var match = await MatchModel.get(req.params.tid);
|
||||
if(!match)
|
||||
return res.status(404).send({error: "Match not found " + req.params.tid});
|
||||
|
||||
return res.status(200).send(match);
|
||||
};
|
||||
|
||||
exports.getLatest = async(req, res) => {
|
||||
|
||||
var match = await MatchModel.getLast(req.params.userId);
|
||||
if(!match)
|
||||
return res.status(404).send({error: "Match not found for user " + req.params.userId});
|
||||
|
||||
return res.status(200).send(match);
|
||||
};
|
||||
87
matches/matches.model.js
Normal file
87
matches/matches.model.js
Normal file
@@ -0,0 +1,87 @@
|
||||
const mongoose = require('mongoose');
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const matchSchema = new Schema({
|
||||
|
||||
tid: { type: String, index: true, default: "" },
|
||||
players: [{type: String, default: []}],
|
||||
winner: {type: String, default: ""},
|
||||
completed: {type: Boolean, default: false},
|
||||
ranked: {type: Boolean, default: false},
|
||||
mode: { type: String, default: "" },
|
||||
|
||||
start: {type: Date, default: null},
|
||||
end: {type: Date, default: null},
|
||||
|
||||
udata: [{ type: Object, _id: false }],
|
||||
});
|
||||
|
||||
matchSchema.methods.toObj = function() {
|
||||
var match = this.toObject();
|
||||
delete match.__v;
|
||||
delete match._id;
|
||||
return match;
|
||||
};
|
||||
|
||||
const Match = mongoose.model('Matches', matchSchema);
|
||||
|
||||
exports.get = async(matchId) => {
|
||||
try{
|
||||
var match = await Match.findOne({tid: matchId});
|
||||
return match;
|
||||
}
|
||||
catch{
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
exports.getAll = async() => {
|
||||
|
||||
try{
|
||||
var matches = await Match.find()
|
||||
return matches || [];
|
||||
}
|
||||
catch{
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
exports.create = async(matchData) => {
|
||||
const match = new Match(matchData);
|
||||
return await match.save();
|
||||
};
|
||||
|
||||
exports.list = async(startTime, endTime, winnerId, completed) => {
|
||||
|
||||
startTime = startTime || new Date(-8640000000000000);
|
||||
endTime = endTime || new Date(8640000000000000);
|
||||
|
||||
var options = {};
|
||||
|
||||
if(startTime && endTime)
|
||||
options.end = { $gte: startTime, $lte: endTime };
|
||||
|
||||
if(winnerId)
|
||||
options.players = winnerId;
|
||||
|
||||
if(completed)
|
||||
options.completed = true;
|
||||
|
||||
try{
|
||||
var matches = await Match.find(options)
|
||||
return matches || [];
|
||||
}
|
||||
catch{
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
exports.remove = async(matchId) => {
|
||||
try{
|
||||
var result = await Match.deleteOne({tid: matchId});
|
||||
return result && result.deletedCount > 0;
|
||||
}
|
||||
catch{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
34
matches/matches.routes.js
Normal file
34
matches/matches.routes.js
Normal file
@@ -0,0 +1,34 @@
|
||||
const MatchesController = require('./matches.controller');
|
||||
const MatchesTool = require('./matches.tool');
|
||||
const AuthTool = require('../authorization/auth.tool');
|
||||
const config = require('../config');
|
||||
|
||||
const ADMIN = config.permissions.ADMIN; //Highest permision, can read and write all users
|
||||
const SERVER = config.permissions.SERVER; //Higher permission, can read all users
|
||||
const USER = config.permissions.USER; //Lowest permision, can only do things on same user
|
||||
|
||||
exports.route = function (app) {
|
||||
|
||||
app.post('/matches/add', app.post_limiter, [
|
||||
AuthTool.isValidJWT,
|
||||
AuthTool.isPermissionLevel(SERVER),
|
||||
MatchesController.addMatch
|
||||
]);
|
||||
app.post('/matches/complete', app.post_limiter, [
|
||||
AuthTool.isValidJWT,
|
||||
AuthTool.isPermissionLevel(SERVER),
|
||||
MatchesController.completeMatch
|
||||
]);
|
||||
|
||||
//-- Getter
|
||||
app.get('/matches', [
|
||||
AuthTool.isValidJWT,
|
||||
AuthTool.isPermissionLevel(SERVER),
|
||||
MatchesController.getAll
|
||||
]);
|
||||
app.get('/matches/:tid', [
|
||||
AuthTool.isValidJWT,
|
||||
AuthTool.isPermissionLevel(USER),
|
||||
MatchesController.getByTid
|
||||
]);
|
||||
};
|
||||
71
matches/matches.tool.js
Normal file
71
matches/matches.tool.js
Normal file
@@ -0,0 +1,71 @@
|
||||
const UserTool = require('../users/users.tool');
|
||||
const config = require('../config.js');
|
||||
|
||||
|
||||
var MatchTool = {};
|
||||
|
||||
|
||||
MatchTool.calculateELO = (player_elo, opponent_elo, progress, won, lost) =>
|
||||
{
|
||||
var p_elo = player_elo || 1000;
|
||||
var o_elo = opponent_elo || 1000;
|
||||
|
||||
var p_elo_log = Math.pow(10.0, p_elo / 400.0);
|
||||
var o_elo_log = Math.pow(10.0, o_elo / 400.0);
|
||||
var p_expected = p_elo_log / (p_elo_log + o_elo_log);
|
||||
var p_score = won ? 1.0 : (lost ? 0.0 : 0.5);
|
||||
|
||||
progress = Math.min(Math.max(progress, 0.0), 1.0);
|
||||
var elo_k = progress * config.elo_k + (1.0 - progress) * config.elo_ini_k;
|
||||
var new_elo = Math.round(p_elo + elo_k * (p_score - p_expected));
|
||||
return new_elo;
|
||||
}
|
||||
|
||||
MatchTool.GetPlayerData = (player) =>
|
||||
{
|
||||
var data = {};
|
||||
data.username = player.username;
|
||||
data.elo = player.elo;
|
||||
data.reward = {};
|
||||
return data;
|
||||
}
|
||||
|
||||
MatchTool.GainMatchReward = async(player, opponent, winner_username) => {
|
||||
|
||||
var player_elo = player.elo;
|
||||
var opponent_elo = opponent.elo;
|
||||
var won = winner_username == player.username;
|
||||
var lost = winner_username == opponent.username;
|
||||
|
||||
//Rewards
|
||||
var xp = won ? config.xp_victory : config.xp_defeat;
|
||||
var coins = won ? config.coins_victory : config.coins_defeat;
|
||||
|
||||
player.xp += xp;
|
||||
player.coins += coins;
|
||||
|
||||
//Match winrate
|
||||
player.matches +=1;
|
||||
|
||||
if(won)
|
||||
player.victories += 1;
|
||||
else if (lost)
|
||||
player.defeats += 1;
|
||||
|
||||
//Calculate elo
|
||||
var match_count = player.matches || 0;
|
||||
var match_progress = Math.min(Math.max(match_count / config.elo_ini_match, 0.0), 1.0);
|
||||
var new_elo = MatchTool.calculateELO(player_elo, opponent_elo, match_progress, won, lost);
|
||||
player.elo = new_elo;
|
||||
player.save();
|
||||
|
||||
var reward = {
|
||||
elo: player.elo,
|
||||
xp: xp,
|
||||
coins: coins
|
||||
};
|
||||
|
||||
return reward;
|
||||
};
|
||||
|
||||
module.exports = MatchTool;
|
||||
Reference in New Issue
Block a user