You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
400 lines
13 KiB
400 lines
13 KiB
const moment = require("moment");
|
|
|
|
const nyoomfactor = {
|
|
//Percentage of original speed to use when nyoom'ing
|
|
1: 1.0,
|
|
2: 1.0,
|
|
3: 1.0,
|
|
4: 1.0,
|
|
5: 1.0,
|
|
6: 1.0,
|
|
7: 1.0,
|
|
8: 1.0,
|
|
9: 1.0,
|
|
10: 1.0,
|
|
11: 1.0,
|
|
12: 0.9,
|
|
13: 0.7,
|
|
14: 0.5,
|
|
15: 0.3,
|
|
16: 0.3,
|
|
17: 0.3,
|
|
18: 0.3,
|
|
19: 0.3,
|
|
20: 0.3,
|
|
50: 0.81,
|
|
100: 0.76,
|
|
500: 0.28,
|
|
1000: 0.24,
|
|
2000: 0.09,
|
|
5000: 0.07,
|
|
10000: 0.04,
|
|
20000: 0.02,
|
|
};
|
|
|
|
const slowdownFactor = {
|
|
//Percentage of slowdown per hour.
|
|
1: 0.00001,
|
|
2: 0.00003,
|
|
3: 0.00003,
|
|
4: 0.00005,
|
|
5: 0.00005,
|
|
6: 0.00005,
|
|
7: 0.00005,
|
|
8: 0.00005,
|
|
9: 0.00005,
|
|
10: 0.00005,
|
|
11: 0.00005,
|
|
12: 0.00006,
|
|
13: 0.00007,
|
|
14: 0.00008,
|
|
15: 0.00009,
|
|
16: 0.0001,
|
|
17: 0.0001,
|
|
18: 0.0001,
|
|
19: 0.0001,
|
|
20: 0.0001,
|
|
50: 0.0002,
|
|
100: 0.0003,
|
|
500: 0.0004,
|
|
1000: 0.0005,
|
|
2000: 0.0005,
|
|
5000: 0.0005,
|
|
10000: 0.0005,
|
|
20000: 0.0005,
|
|
};
|
|
|
|
class Prediction {
|
|
chartData = {};
|
|
predictionChartData = {};
|
|
|
|
diffData = [];
|
|
|
|
maxSpeed = 0;
|
|
|
|
constructor(server) { }
|
|
|
|
SetupPredictionModel(eventStart) {
|
|
this.chartData = {};
|
|
this.predictionChartData = {};
|
|
if (this.chartData["1"] && this.chartData["1"].length > 400) {
|
|
this.maxSpeed = Math.floor(
|
|
this.chartData["1"][400].points /
|
|
(moment(this.chartData["1"][400].date).diff(eventStart, "minutes") / 60)
|
|
);
|
|
} else if (this.chartData["1"] && this.chartData["1"].length > 0) {
|
|
this.maxSpeed = Math.floor(
|
|
this.chartData["1"][this.chartData["1"].length - 1].points /
|
|
(moment(this.chartData["1"][this.chartData["1"].length - 1].date).diff(
|
|
eventStart,
|
|
"minutes"
|
|
) /
|
|
60)
|
|
);
|
|
} else {
|
|
this.maxSpeed = 0;
|
|
}
|
|
}
|
|
|
|
CreatePrediction(precision, rank, eventStart, eventEnd) {
|
|
if (!this.chartData[rank]) return [];
|
|
var startPoint = this.chartData[rank][this.chartData[rank].length - 1];
|
|
if (rank <= 20) startPoint = { points: startPoint.points, date: moment() };
|
|
var startTime = moment(startPoint.date);
|
|
if (
|
|
startTime.diff(eventStart, "hours") > 36 &&
|
|
moment(startPoint.date).diff(eventStart, "hours") >= 36
|
|
) {
|
|
//console.log(this.maxSpeed)
|
|
//Precision is in hours. 1 is default
|
|
var finalChart = [
|
|
{
|
|
y: this.chartData[rank][this.chartData[rank].length - 1].points,
|
|
x: this.chartData[rank][this.chartData[rank].length - 1].date,
|
|
},
|
|
];
|
|
//Start from the time of the last reported rank.
|
|
var myPoints = startPoint.points;
|
|
var pointSpeed = Math.ceil(
|
|
this.GetRank(rank) /
|
|
(moment(startPoint.date).diff(eventStart, "minutes") / 60)
|
|
);
|
|
var speedGoal = this.maxSpeed * nyoomfactor[rank];
|
|
while (startTime < eventEnd) {
|
|
startTime.add(precision, "hours");
|
|
myPoints += Math.floor(pointSpeed);
|
|
if (eventEnd.diff(startTime, "hours") > 11) {
|
|
pointSpeed -= pointSpeed * (slowdownFactor[rank] * 10) /*CONSTANT for adjustment*/;
|
|
} else {
|
|
pointSpeed = Math.max(
|
|
this.GetRank(rank) /
|
|
(moment(startPoint.date).diff(eventStart, "minutes") / 60),
|
|
Math.min(
|
|
(12 - eventEnd.diff(startTime, "hours")) * (speedGoal / 5),
|
|
speedGoal
|
|
)
|
|
);
|
|
//pointSpeed+=(speedGoal-pointSpeed) //Increase towards final goal.
|
|
//console.log(pointSpeed)
|
|
}
|
|
finalChart = [
|
|
...finalChart,
|
|
{
|
|
y: Number.isInteger(myPoints) ? myPoints : "???",
|
|
x: moment(startTime),
|
|
},
|
|
];
|
|
}
|
|
this.predictionChartData[rank] = finalChart;
|
|
return finalChart;
|
|
} else if (startTime.diff(eventStart, "hours") > 24 &&
|
|
moment(startPoint.date).diff(eventStart, "hours") >= 24
|
|
) {
|
|
//console.log(this.maxSpeed)
|
|
//Precision is in hours. 1 is default
|
|
var finalChart = [
|
|
{
|
|
y: this.chartData[rank][this.chartData[rank].length - 1].points,
|
|
x: this.chartData[rank][this.chartData[rank].length - 1].date,
|
|
},
|
|
];
|
|
//Start from the time of the last reported rank.
|
|
var myPoints = startPoint.points;
|
|
var pointSpeed = this.GetRate(rank);
|
|
var speedGoal = this.maxSpeed * nyoomfactor[rank];
|
|
while (startTime < eventEnd) {
|
|
startTime.add(precision, "hours");
|
|
myPoints += Math.floor(pointSpeed);
|
|
if (eventEnd.diff(startTime, "hours") > 11) {
|
|
pointSpeed -=
|
|
pointSpeed *
|
|
(slowdownFactor[rank] * 10) /*CONSTANT for adjustment*/;
|
|
} else {
|
|
pointSpeed = Math.max(
|
|
this.GetRank(rank) /
|
|
(moment(startPoint.date).diff(eventStart, "minutes") / 60),
|
|
Math.min(
|
|
(12 - eventEnd.diff(startTime, "hours")) * (speedGoal / 5),
|
|
speedGoal
|
|
)
|
|
);
|
|
//pointSpeed+=(speedGoal-pointSpeed) //Increase towards final goal.
|
|
//console.log(pointSpeed)
|
|
}
|
|
finalChart = [
|
|
...finalChart,
|
|
{
|
|
y: Number.isInteger(myPoints) ? myPoints : "???",
|
|
x: moment(startTime),
|
|
},
|
|
];
|
|
}
|
|
this.predictionChartData[rank] = finalChart;
|
|
return finalChart;
|
|
} else {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
GetRank(rank) {
|
|
if (this.chartData[rank]) {
|
|
return this.chartData[rank][this.chartData[rank].length - 1].points;
|
|
} else {
|
|
return "???";
|
|
}
|
|
}
|
|
|
|
GetEstimate(rank) {
|
|
if (this.predictionChartData[rank]) {
|
|
var currentEstimate = 0;
|
|
if (
|
|
rank > 20 &&
|
|
moment().diff(
|
|
moment(this.chartData[rank][this.chartData[rank].length - 1].date),
|
|
"hours"
|
|
) > 0.5
|
|
) {
|
|
for (var i = this.predictionChartData[rank].length - 1; i >= 0; i--) {
|
|
if (moment(this.predictionChartData[rank][i].x).isAfter(moment())) {
|
|
currentEstimate = this.predictionChartData[rank][i].y;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return currentEstimate;
|
|
} else {
|
|
if (rank > 20) {
|
|
return this.GetRank(rank);
|
|
} else {
|
|
return "---";
|
|
}
|
|
}
|
|
} else {
|
|
return "???";
|
|
}
|
|
}
|
|
|
|
GetTime(rank) {
|
|
if (this.chartData[rank]) {
|
|
return moment(this.chartData[rank][this.chartData[rank].length - 1].date).fromNow();
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
GetUpdateColor(rank, en) {
|
|
if (this.chartData[rank]) {
|
|
return (
|
|
"rgba(255," +
|
|
Math.max(
|
|
255 -
|
|
moment().diff(
|
|
moment(this.chartData[rank][this.chartData[rank].length - 1].date),
|
|
"hours"
|
|
) *
|
|
3,
|
|
0
|
|
) +
|
|
"," +
|
|
Math.max(
|
|
255 -
|
|
moment().diff(
|
|
moment(this.chartData[rank][this.chartData[rank].length - 1].date),
|
|
"hours"
|
|
) *
|
|
3,
|
|
0
|
|
) +
|
|
",1)"
|
|
);
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
ChartData(rank, eventStart, eventEnd) {
|
|
if (!this.chartData[rank]) {
|
|
return [{ x: 0, y: 0 }];
|
|
}
|
|
if (rank <= 20) {
|
|
return [
|
|
...this.chartData[rank].map((data) => {
|
|
return { x: data.date, y: data.points };
|
|
}),
|
|
{
|
|
x: moment().isBefore(eventEnd) ? moment() : eventEnd,
|
|
y: this.chartData[rank][this.chartData[rank].length - 1].points,
|
|
},
|
|
];
|
|
} else {
|
|
return [
|
|
{ x: eventStart, y: 0 },
|
|
...this.chartData[rank].map((data) => {
|
|
return { x: data.date, y: data.points };
|
|
}),
|
|
];
|
|
}
|
|
}
|
|
|
|
GetPointCount(rank) {
|
|
let pointCount = 1;
|
|
const RATEDURATION = 1;
|
|
if (!this.chartData[rank]) {
|
|
return pointCount;
|
|
}
|
|
if (this.chartData[rank].length > 2) {
|
|
var lastpoint = this.chartData[rank][this.chartData[rank].length - 1];
|
|
for (var i = this.chartData[rank].length - 1; i >= 0; i--) {
|
|
var diff = moment().diff(this.chartData[rank][i].date, "hours");
|
|
if (diff >= RATEDURATION) {
|
|
break;
|
|
} else {
|
|
lastpoint = this.chartData[rank][i];
|
|
pointCount++;
|
|
}
|
|
}
|
|
return pointCount;
|
|
} else {
|
|
if (this.chartData[rank].length > 0) {
|
|
return this.chartData[rank].length;
|
|
} else {
|
|
return pointCount;
|
|
}
|
|
}
|
|
}
|
|
|
|
GetNameData = (t) => {
|
|
var tempname = "";
|
|
if (
|
|
this.chartData[t] &&
|
|
this.chartData[t][this.chartData[t].length - 1] &&
|
|
this.chartData[t][this.chartData[t].length - 1].name
|
|
) {
|
|
tempname = this.chartData[t][this.chartData[t].length - 1].name;
|
|
}
|
|
var tempdesc = "";
|
|
if (
|
|
this.chartData[t] &&
|
|
this.chartData[t][this.chartData[t].length - 1] &&
|
|
this.chartData[t][this.chartData[t].length - 1].description
|
|
) {
|
|
tempdesc = this.chartData[t][this.chartData[t].length - 1].description;
|
|
}
|
|
return { tempname, tempdesc }
|
|
}
|
|
|
|
|
|
GetRate(rank, eventStart) {
|
|
|
|
const RATEDURATION = 1; //In hours. How much EP/hr is shown.
|
|
|
|
if (this.chartData[rank].length > 2) {
|
|
var lastpoint = this.chartData[rank][this.chartData[rank].length - 1];
|
|
for (var i = this.chartData[rank].length - 1; i >= 0; i--) {
|
|
var diff = moment().diff(this.chartData[rank][i].date, "hours");
|
|
if (diff >= RATEDURATION) {
|
|
break;
|
|
} else {
|
|
lastpoint = this.chartData[rank][i];
|
|
}
|
|
}
|
|
var timediff = moment(
|
|
this.chartData[rank][this.chartData[rank].length - 1].date
|
|
).diff(moment(lastpoint.date), "minutes");
|
|
if (timediff < 120) {
|
|
if (lastpoint === this.chartData[rank][this.chartData[rank].length - 1]) {
|
|
return "???";
|
|
} else
|
|
return (
|
|
(this.chartData[rank][this.chartData[rank].length - 1].points -
|
|
lastpoint.points) /
|
|
RATEDURATION
|
|
);
|
|
} else {
|
|
return Math.ceil(
|
|
(this.chartData[rank][this.chartData[rank].length - 1].points -
|
|
lastpoint.points) /
|
|
(moment(this.chartData[rank][this.chartData[rank].length - 1].date).diff(
|
|
moment(lastpoint.date),
|
|
"minutes"
|
|
) /
|
|
60)
|
|
);
|
|
}
|
|
} else {
|
|
if (this.chartData[rank].length > 0) {
|
|
var startPoint = this.chartData[rank][this.chartData[rank].length - 1];
|
|
return Math.ceil(
|
|
this.GetRank(rank) /
|
|
(moment(startPoint.date).diff(eventStart, "minutes") / 60)
|
|
);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
exports.Prediction = Prediction |