forked from ppfun/pixelplanet
add punishment for dominating country
This commit is contained in:
parent
ccdf670291
commit
057f60f049
|
@ -11,6 +11,8 @@ import {
|
||||||
storeOnlinUserAmount,
|
storeOnlinUserAmount,
|
||||||
getCountryDailyHistory,
|
getCountryDailyHistory,
|
||||||
getCountryRanks,
|
getCountryRanks,
|
||||||
|
getHourlyCountryStats,
|
||||||
|
storeHourlyCountryStats,
|
||||||
getTopDailyHistory,
|
getTopDailyHistory,
|
||||||
storeHourlyPixelsPlaced,
|
storeHourlyPixelsPlaced,
|
||||||
getHourlyPixelStats,
|
getHourlyPixelStats,
|
||||||
|
@ -20,30 +22,38 @@ import socketEvents from '../socket/socketEvents';
|
||||||
import logger from './logger';
|
import logger from './logger';
|
||||||
|
|
||||||
import { MINUTE } from './constants';
|
import { MINUTE } from './constants';
|
||||||
|
import { PUNISH_DOMINATOR } from './config';
|
||||||
import { DailyCron, HourlyCron } from '../utils/cron';
|
import { DailyCron, HourlyCron } from '../utils/cron';
|
||||||
|
|
||||||
class Ranks {
|
class Ranks {
|
||||||
|
ranks = {
|
||||||
|
// ranking today of users by pixels
|
||||||
|
dailyRanking: [],
|
||||||
|
// ranking of users by pixels
|
||||||
|
ranking: [],
|
||||||
|
// ranking today of countries by pixels
|
||||||
|
dailyCRanking: [],
|
||||||
|
// ranking hourly of countries by pixels
|
||||||
|
cHourlyStats: [],
|
||||||
|
// yesterdays ranking of users by pixels
|
||||||
|
prevTop: [],
|
||||||
|
// online user amount by hour
|
||||||
|
onlineStats: [],
|
||||||
|
// ranking of countries by day
|
||||||
|
cHistStats: [],
|
||||||
|
// ranking of users by day
|
||||||
|
histStats: { users: [], stats: [] },
|
||||||
|
// pixels placed by hour
|
||||||
|
pHourlyStats: [],
|
||||||
|
// pixels placed by day
|
||||||
|
pDailyStats: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
// if a country dominates, adjust its cooldown
|
||||||
|
#punishedCountry;
|
||||||
|
#punishmentFactor;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.ranks = {
|
|
||||||
// ranking today of users by pixels
|
|
||||||
dailyRanking: [],
|
|
||||||
// ranking of users by pixels
|
|
||||||
ranking: [],
|
|
||||||
// ranking today of countries by pixels
|
|
||||||
dailyCRanking: [],
|
|
||||||
// yesterdays ranking of users by pixels
|
|
||||||
prevTop: [],
|
|
||||||
// online user amount by hour
|
|
||||||
onlineStats: [],
|
|
||||||
// ranking of countries by day
|
|
||||||
cHistStats: [],
|
|
||||||
// ranking of users by day
|
|
||||||
histStats: { users: [], stats: [] },
|
|
||||||
// pixels placed by hour
|
|
||||||
pHourlyStats: [],
|
|
||||||
// pixels placed by day
|
|
||||||
pDailyStats: [],
|
|
||||||
};
|
|
||||||
/*
|
/*
|
||||||
* we go through socketEvents for sharding
|
* we go through socketEvents for sharding
|
||||||
*/
|
*/
|
||||||
|
@ -70,12 +80,59 @@ class Ranks {
|
||||||
if (!newRanks) {
|
if (!newRanks) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (newRanks.cHourlyStats) {
|
||||||
|
this.setPunishments(newRanks.cHourlyStats);
|
||||||
|
}
|
||||||
this.ranks = {
|
this.ranks = {
|
||||||
...this.ranks,
|
...this.ranks,
|
||||||
...newRanks,
|
...newRanks,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setPunishments(cHourlyStats) {
|
||||||
|
if (!cHourlyStats.length || !PUNISH_DOMINATOR) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let outnumbered = 0;
|
||||||
|
const { cc: leadingCountry } = cHourlyStats[0];
|
||||||
|
let { px: margin } = cHourlyStats[0];
|
||||||
|
for (let i = 1; i < cHourlyStats.length; i += 1) {
|
||||||
|
margin -= cHourlyStats[i].px;
|
||||||
|
if (margin < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
outnumbered += 1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* if the leading country places more pixels
|
||||||
|
* than the fellowing 2+ countries after,
|
||||||
|
* 20% gets added to the cooldown for every following
|
||||||
|
* country, cailed at 200%;
|
||||||
|
*/
|
||||||
|
if (outnumbered > 2) {
|
||||||
|
this.#punishedCountry = leadingCountry;
|
||||||
|
let punishmentFactor = 1 + 0.2 * (outnumbered - 1);
|
||||||
|
if (punishmentFactor > 2) {
|
||||||
|
punishmentFactor = 2;
|
||||||
|
}
|
||||||
|
this.#punishmentFactor = punishmentFactor;
|
||||||
|
logger.info(
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
`Punishment for dominating country ${leadingCountry} of ${punishmentFactor}`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.#punishedCountry = null;
|
||||||
|
this.#punishmentFactor = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCountryCoolDownFactor(country) {
|
||||||
|
if (this.#punishedCountry === country) {
|
||||||
|
return this.#punishmentFactor;
|
||||||
|
}
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
static async updateRanking() {
|
static async updateRanking() {
|
||||||
// only main shard does it
|
// only main shard does it
|
||||||
if (!socketEvents.amIImportant()) {
|
if (!socketEvents.amIImportant()) {
|
||||||
|
@ -107,10 +164,12 @@ class Ranks {
|
||||||
const onlineStats = await getOnlineUserStats();
|
const onlineStats = await getOnlineUserStats();
|
||||||
const cHistStats = await getCountryDailyHistory();
|
const cHistStats = await getCountryDailyHistory();
|
||||||
const pHourlyStats = await getHourlyPixelStats();
|
const pHourlyStats = await getHourlyPixelStats();
|
||||||
|
const cHourlyStats = await getHourlyCountryStats(1, 100);
|
||||||
const ret = {
|
const ret = {
|
||||||
onlineStats,
|
onlineStats,
|
||||||
cHistStats,
|
cHistStats,
|
||||||
pHourlyStats,
|
pHourlyStats,
|
||||||
|
cHourlyStats,
|
||||||
};
|
};
|
||||||
if (socketEvents.amIImportant()) {
|
if (socketEvents.amIImportant()) {
|
||||||
// only main shard sends to others
|
// only main shard sends to others
|
||||||
|
@ -148,6 +207,7 @@ class Ranks {
|
||||||
const amount = socketEvents.onlineCounter.total;
|
const amount = socketEvents.onlineCounter.total;
|
||||||
await storeOnlinUserAmount(amount);
|
await storeOnlinUserAmount(amount);
|
||||||
await storeHourlyPixelsPlaced();
|
await storeHourlyPixelsPlaced();
|
||||||
|
await storeHourlyCountryStats(1, 100);
|
||||||
await Ranks.hourlyUpdateRanking();
|
await Ranks.hourlyUpdateRanking();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,9 @@ export const BACKUP_DIR = process.env.BACKUP_DIR || null;
|
||||||
|
|
||||||
export const OUTGOING_ADDRESS = process.env.OUTGOING_ADDRESS || null;
|
export const OUTGOING_ADDRESS = process.env.OUTGOING_ADDRESS || null;
|
||||||
|
|
||||||
|
// Punish when a country dominates
|
||||||
|
export const PUNISH_DOMINATOR = !!process.env.PUNISH_DOMINATOR;
|
||||||
|
|
||||||
// Proxycheck
|
// Proxycheck
|
||||||
export const USE_PROXYCHECK = parseInt(process.env.USE_PROXYCHECK, 10) || false;
|
export const USE_PROXYCHECK = parseInt(process.env.USE_PROXYCHECK, 10) || false;
|
||||||
export const { PROXYCHECK_KEY } = process.env;
|
export const { PROXYCHECK_KEY } = process.env;
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
import logger, { pixelLogger } from './logger';
|
import logger, { pixelLogger } from './logger';
|
||||||
import allowPlace from '../data/redis/cooldown';
|
import allowPlace from '../data/redis/cooldown';
|
||||||
import socketEvents from '../socket/socketEvents';
|
import socketEvents from '../socket/socketEvents';
|
||||||
|
import rankings from './Ranks';
|
||||||
import { setPixelByOffset } from './setPixel';
|
import { setPixelByOffset } from './setPixel';
|
||||||
import isIPAllowed from './isAllowed';
|
import isIPAllowed from './isAllowed';
|
||||||
import canvases from './canvases';
|
import canvases from './canvases';
|
||||||
|
@ -127,6 +128,8 @@ export default async function drawByOffsets(
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
factor *= rankings.getCountryCoolDownFactor(user.country);
|
||||||
|
|
||||||
factor *= 0.75;
|
factor *= 0.75;
|
||||||
|
|
||||||
const bcd = canvas.bcd * factor;
|
const bcd = canvas.bcd * factor;
|
||||||
|
|
|
@ -7,6 +7,9 @@ import { getDateKeyOfTs } from '../../core/utils';
|
||||||
export const RANKED_KEY = 'rank';
|
export const RANKED_KEY = 'rank';
|
||||||
export const DAILY_RANKED_KEY = 'rankd';
|
export const DAILY_RANKED_KEY = 'rankd';
|
||||||
export const DAILY_CRANKED_KEY = 'crankd';
|
export const DAILY_CRANKED_KEY = 'crankd';
|
||||||
|
export const HOURLY_CRANKED_KEY = 'crankh';
|
||||||
|
export const PREV_DAILY_CRANKED_KEY = 'pcrankd';
|
||||||
|
export const PREV_DAILY_CRANKED_TS_KEY = 'pcrankdts';
|
||||||
export const PREV_DAY_TOP_KEY = 'prankd';
|
export const PREV_DAY_TOP_KEY = 'prankd';
|
||||||
const DAY_STATS_RANKS_KEY = 'ds';
|
const DAY_STATS_RANKS_KEY = 'ds';
|
||||||
const CDAY_STATS_RANKS_KEY = 'cds';
|
const CDAY_STATS_RANKS_KEY = 'cds';
|
||||||
|
@ -100,6 +103,61 @@ export async function getCountryRanks(start, amount) {
|
||||||
return ranks;
|
return ranks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get previous daily country ranking (one hour before cranks)
|
||||||
|
*/
|
||||||
|
export async function getHourlyCountryStats(start, amount) {
|
||||||
|
start -= 1;
|
||||||
|
amount -= 1;
|
||||||
|
let ranks = await client.zRangeWithScores(
|
||||||
|
HOURLY_CRANKED_KEY, start, start + amount, {
|
||||||
|
REV: true,
|
||||||
|
});
|
||||||
|
ranks = ranks.map((r) => ({
|
||||||
|
cc: r.value,
|
||||||
|
px: Number(r.score),
|
||||||
|
}));
|
||||||
|
return ranks;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function storeHourlyCountryStats(start, amount) {
|
||||||
|
start -= 1;
|
||||||
|
amount -= 1;
|
||||||
|
const tsNow = Date.now();
|
||||||
|
const prevTs = Number(await client.get(PREV_DAILY_CRANKED_TS_KEY));
|
||||||
|
const prevData = await client.zRangeWithScores(
|
||||||
|
PREV_DAILY_CRANKED_KEY, start, start + amount, {
|
||||||
|
REV: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
await client.copy(DAILY_CRANKED_KEY, PREV_DAILY_CRANKED_KEY, {
|
||||||
|
REAPLACE: true,
|
||||||
|
});
|
||||||
|
await client.set(PREV_DAILY_CRANKED_TS_KEY, String(tsNow));
|
||||||
|
await client.del(HOURLY_CRANKED_KEY);
|
||||||
|
|
||||||
|
if (prevTs && prevTs > tsNow - 1000 * 3600 * 1.5) {
|
||||||
|
const curData = await client.zRangeWithScores(
|
||||||
|
DAILY_CRANKED_KEY, start, start + amount, {
|
||||||
|
REV: true,
|
||||||
|
});
|
||||||
|
const prevRanks = new Map();
|
||||||
|
prevData.forEach(({ value, score }) => prevRanks.set(value, score));
|
||||||
|
const addArr = [];
|
||||||
|
curData.forEach(({ value: cc, score: curPx }) => {
|
||||||
|
const prevPx = prevData.get(cc) || 0;
|
||||||
|
const px = (curPx > prevPx) ? curPx - prevPx : curPx;
|
||||||
|
addArr.push({
|
||||||
|
score: cc,
|
||||||
|
value: px,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (addArr.length) {
|
||||||
|
await client.zAdd(HOURLY_CRANKED_KEY, addArr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get top 10 from previous day
|
* get top 10 from previous day
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue
Block a user