mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-18 07:07:35 +01:00
[API v3] add CRON_SAFE_MODE (#7286)
* add CRON_SAFE_MODE to example config file, fix some bugs, add an unrelated low-priority TODO * create CRON_SAFE_MODE to disable parts of cron for use after extended outage - fixes https://github.com/HabitRPG/habitrpg/issues/7161 * fix a bug with CRON_SAFE_MODE, remove duplicated code, remove completed TODO comment * fix check for CRON_SAFE_MODE
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
"NODE_DB_URI":"mongodb://localhost/habitrpg",
|
"NODE_DB_URI":"mongodb://localhost/habitrpg",
|
||||||
"TEST_DB_URI":"mongodb://localhost/habitrpg_test",
|
"TEST_DB_URI":"mongodb://localhost/habitrpg_test",
|
||||||
"NODE_ENV":"development",
|
"NODE_ENV":"development",
|
||||||
|
"CRON_SAFE_MODE":"false",
|
||||||
"SESSION_SECRET":"YOUR SECRET HERE",
|
"SESSION_SECRET":"YOUR SECRET HERE",
|
||||||
"ADMIN_EMAIL": "you@example.com",
|
"ADMIN_EMAIL": "you@example.com",
|
||||||
"SMTP_USER":"user@example.com",
|
"SMTP_USER":"user@example.com",
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ import moment from 'moment';
|
|||||||
import common from '../../../../common/';
|
import common from '../../../../common/';
|
||||||
import { preenUserHistory } from '../../libs/api-v3/preening';
|
import { preenUserHistory } from '../../libs/api-v3/preening';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import nconf from 'nconf';
|
||||||
|
|
||||||
|
const CRON_SAFE_MODE = nconf.get('CRON_SAFE_MODE') === 'true';
|
||||||
const shouldDo = common.shouldDo;
|
const shouldDo = common.shouldDo;
|
||||||
const scoreTask = common.ops.scoreTask;
|
const scoreTask = common.ops.scoreTask;
|
||||||
// const maxPMs = 200;
|
// const maxPMs = 200;
|
||||||
@@ -68,6 +70,7 @@ function performSleepTasks (user, tasksByType, now) {
|
|||||||
let thatDay = moment(now).subtract({days: 1});
|
let thatDay = moment(now).subtract({days: 1});
|
||||||
|
|
||||||
if (shouldDo(thatDay.toDate(), daily, user.preferences) || completed) {
|
if (shouldDo(thatDay.toDate(), daily, user.preferences) || completed) {
|
||||||
|
// TODO also untick checklists if the Daily was due on previous missed days, if two or more days were missed at once -- https://github.com/HabitRPG/habitrpg/pull/7218#issuecomment-219256016
|
||||||
daily.checklist.forEach(box => box.completed = false);
|
daily.checklist.forEach(box => box.completed = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +93,7 @@ export function cron (options = {}) {
|
|||||||
|
|
||||||
if (user.isSubscribed()) {
|
if (user.isSubscribed()) {
|
||||||
grantEndOfTheMonthPerks(user, now);
|
grantEndOfTheMonthPerks(user, now);
|
||||||
removeTerminatedSubscription(user);
|
if (!CRON_SAFE_MODE) removeTerminatedSubscription(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
// User is resting at the inn.
|
// User is resting at the inn.
|
||||||
@@ -150,31 +153,36 @@ export function cron (options = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (scheduleMisses > EvadeTask) {
|
if (scheduleMisses > EvadeTask) {
|
||||||
perfect = false;
|
// The user did not complete this due Daily (but no penalty if cron is running in safe mode).
|
||||||
|
if (CRON_SAFE_MODE) {
|
||||||
if (task.checklist && task.checklist.length > 0) { // Partially completed checklists dock fewer mana points
|
dailyChecked += 1; // allows full allotment of mp to be gained
|
||||||
let fractionChecked = _.reduce(task.checklist, (m, i) => m + (i.completed ? 1 : 0), 0) / task.checklist.length;
|
|
||||||
dailyDueUnchecked += 1 - fractionChecked;
|
|
||||||
dailyChecked += fractionChecked;
|
|
||||||
} else {
|
} else {
|
||||||
dailyDueUnchecked += 1;
|
perfect = false;
|
||||||
|
|
||||||
|
if (task.checklist && task.checklist.length > 0) { // Partially completed checklists dock fewer mana points
|
||||||
|
let fractionChecked = _.reduce(task.checklist, (m, i) => m + (i.completed ? 1 : 0), 0) / task.checklist.length;
|
||||||
|
dailyDueUnchecked += 1 - fractionChecked;
|
||||||
|
dailyChecked += fractionChecked;
|
||||||
|
} else {
|
||||||
|
dailyDueUnchecked += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let delta = scoreTask({
|
||||||
|
user,
|
||||||
|
task,
|
||||||
|
direction: 'down',
|
||||||
|
times: multiDaysCountAsOneDay ? 1 : scheduleMisses - EvadeTask,
|
||||||
|
cron: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Apply damage from a boss, less damage for Trivial priority (difficulty)
|
||||||
|
user.party.quest.progress.down += delta * (task.priority < 1 ? task.priority : 1);
|
||||||
|
// NB: Medium and Hard priorities do not increase damage from boss. This was by accident
|
||||||
|
// initially, and when we realised, we could not fix it because users are used to
|
||||||
|
// their Medium and Hard Dailies doing an Easy amount of damage from boss.
|
||||||
|
// Easy is task.priority = 1. Anything < 1 will be Trivial (0.1) or any future
|
||||||
|
// setting between Trivial and Easy.
|
||||||
}
|
}
|
||||||
|
|
||||||
let delta = scoreTask({
|
|
||||||
user,
|
|
||||||
task,
|
|
||||||
direction: 'down',
|
|
||||||
times: multiDaysCountAsOneDay ? 1 : scheduleMisses - EvadeTask,
|
|
||||||
cron: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Apply damage from a boss, less damage for Trivial priority (difficulty)
|
|
||||||
user.party.quest.progress.down += delta * (task.priority < 1 ? task.priority : 1);
|
|
||||||
// NB: Medium and Hard priorities do not increase damage from boss. This was by accident
|
|
||||||
// initially, and when we realised, we could not fix it because users are used to
|
|
||||||
// their Medium and Hard Dailies doing an Easy amount of damage from boss.
|
|
||||||
// Easy is task.priority = 1. Anything < 1 will be Trivial (0.1) or any future
|
|
||||||
// setting between Trivial and Easy.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +193,7 @@ export function cron (options = {}) {
|
|||||||
task.completed = false;
|
task.completed = false;
|
||||||
|
|
||||||
if (completed || scheduleMisses > 0) {
|
if (completed || scheduleMisses > 0) {
|
||||||
task.checklist.forEach(i => i.completed = false); // TODO this should not happen for grey tasks unless they are completed
|
task.checklist.forEach(i => i.completed = false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -231,14 +239,9 @@ export function cron (options = {}) {
|
|||||||
|
|
||||||
// Add 10 MP, or 10% of max MP if that'd be more. Perform this after Perfect Day for maximum benefit
|
// Add 10 MP, or 10% of max MP if that'd be more. Perform this after Perfect Day for maximum benefit
|
||||||
// Adjust for fraction of dailies completed
|
// Adjust for fraction of dailies completed
|
||||||
user.stats.mp += _.max([10, 0.1 * user._statsComputed.maxMP]) * dailyChecked / (dailyDueUnchecked + dailyChecked);
|
|
||||||
if (user.stats.mp > user._statsComputed.maxMP) user.stats.mp = user._statsComputed.maxMP;
|
|
||||||
|
|
||||||
if (dailyDueUnchecked === 0 && dailyChecked === 0) dailyChecked = 1;
|
if (dailyDueUnchecked === 0 && dailyChecked === 0) dailyChecked = 1;
|
||||||
user.stats.mp += _.max([10, 0.1 * user._statsComputed.maxMP]) * dailyChecked / (dailyDueUnchecked + dailyChecked);
|
user.stats.mp += _.max([10, 0.1 * user._statsComputed.maxMP]) * dailyChecked / (dailyDueUnchecked + dailyChecked);
|
||||||
if (user.stats.mp > user._statsComputed.maxMP) {
|
if (user.stats.mp > user._statsComputed.maxMP) user.stats.mp = user._statsComputed.maxMP;
|
||||||
user.stats.mp = user._statsComputed.maxMP;
|
|
||||||
}
|
|
||||||
|
|
||||||
// After all is said and done, progress up user's effect on quest, return those values & reset the user's
|
// After all is said and done, progress up user's effect on quest, return those values & reset the user's
|
||||||
let progress = user.party.quest.progress;
|
let progress = user.party.quest.progress;
|
||||||
|
|||||||
@@ -515,8 +515,10 @@ schema.statics.bossQuest = async function bossQuest (user, progress) {
|
|||||||
let down = progress.down * quest.boss.str; // multiply by boss strength
|
let down = progress.down * quest.boss.str; // multiply by boss strength
|
||||||
|
|
||||||
group.quest.progress.hp -= progress.up;
|
group.quest.progress.hp -= progress.up;
|
||||||
// TODO Create a party preferred language option so emits like this can be localized
|
// TODO Create a party preferred language option so emits like this can be localized. Suggestion: Always display the English version too. Or, if English is not displayed to the players, at least include it in a new field in the chat object that's visible in the database - essential for admins when troubleshooting quests!
|
||||||
group.sendChat(`\`${user.profile.name} attacks ${quest.boss.name('en')} for ${progress.up.toFixed(1)} damage.\` \`${quest.boss.name('en')} attacks party for ${Math.abs(down).toFixed(1)} damage.\``);
|
let playerAttack = `${user.profile.name} attacks ${quest.boss.name('en')} for ${progress.up.toFixed(1)} damage.`;
|
||||||
|
let bossAttack = nconf.get('CRON_SAFE_MODE') === 'true' ? `${quest.boss.name('en')} did not attack the party because it was asleep while maintenance was happening.` : `${quest.boss.name('en')} attacks party for ${Math.abs(down).toFixed(1)} damage.`;
|
||||||
|
group.sendChat(`\`${playerAttack}\` \`${bossAttack}\``);
|
||||||
|
|
||||||
// If boss has Rage, increment Rage as well
|
// If boss has Rage, increment Rage as well
|
||||||
if (quest.boss.rage) {
|
if (quest.boss.rage) {
|
||||||
|
|||||||
Reference in New Issue
Block a user