Achievements are now in 'achievements.hjson'
+ Config.general.achievementFile * Implement (re)caching (aka hot-reload) * Update values a bit
This commit is contained in:
parent
c332b0f3ec
commit
2bd51c0725
|
@ -0,0 +1,53 @@
|
|||
{
|
||||
enabled : true,
|
||||
|
||||
art : {
|
||||
localHeader : 'achievement_local_header',
|
||||
localFooter : 'achievement_local_footer',
|
||||
globalHeader : 'achievement_global_header',
|
||||
globalFooter : 'achievement_global_footer',
|
||||
},
|
||||
|
||||
// :TODO: achievements should be a path/filename -> achievements.hjson & allow override/theming
|
||||
|
||||
achievements : {
|
||||
user_login_count : {
|
||||
type : 'userStat',
|
||||
statName : 'login_count',
|
||||
retroactive : true,
|
||||
|
||||
match : {
|
||||
2 : {
|
||||
title : 'Return Caller',
|
||||
globalText : '{userName} has returned to {boardName}!',
|
||||
text : 'You\'ve returned to {boardName}!',
|
||||
points : 5,
|
||||
},
|
||||
10 : {
|
||||
title : '{achievedValue} Logins',
|
||||
globalText : '{userName} has logged into {boardName} {achievedValue} times!',
|
||||
text : 'You\'ve logged into {boardName} {achievedValue} times!',
|
||||
points : 5,
|
||||
},
|
||||
25 : {
|
||||
title : '{achievedValue} Logins',
|
||||
globalText : '{userName} has logged into {boardName} {achievedValue} times!',
|
||||
text : 'You\'ve logged into {boardName} {achievedValue} times!',
|
||||
points : 10,
|
||||
},
|
||||
100 : {
|
||||
title : '{boardName} Regular',
|
||||
globalText : '{userName} has logged into {boardName} {achievedValue} times!',
|
||||
text : 'You\'ve logged into {boardName} {achievedValue} times!',
|
||||
points : 10,
|
||||
},
|
||||
500 : {
|
||||
title : '{boardName} Addict',
|
||||
globalText : '{userName} the BBS {boardName} addict has logged in {achievedValue} times!',
|
||||
text : 'You\'re a {boardName} addict! You\'ve logged in {achievedValue} times!',
|
||||
points : 25,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,10 @@
|
|||
// ENiGMA½
|
||||
const Events = require('./events.js');
|
||||
const Config = require('./config.js').get;
|
||||
const {
|
||||
getConfigPath,
|
||||
getFullConfig,
|
||||
} = require('./config_util.js');
|
||||
const UserDb = require('./database.js').dbs.user;
|
||||
const {
|
||||
getISOTimestampString
|
||||
|
@ -22,11 +26,13 @@ const { pipeToAnsi } = require('./color_codes.js');
|
|||
const stringFormat = require('./string_format.js');
|
||||
const StatLog = require('./stat_log.js');
|
||||
const Log = require('./logger.js').log;
|
||||
const ConfigCache = require('./config_cache.js');
|
||||
|
||||
// deps
|
||||
const _ = require('lodash');
|
||||
const async = require('async');
|
||||
const moment = require('moment');
|
||||
const paths = require('path');
|
||||
|
||||
class Achievement {
|
||||
constructor(data) {
|
||||
|
@ -107,11 +113,56 @@ class Achievements {
|
|||
}
|
||||
|
||||
init(cb) {
|
||||
let achievementConfigPath = _.get(Config(), 'general.achievementFile');
|
||||
if(!achievementConfigPath) {
|
||||
// :TODO: Log me
|
||||
return cb(null);
|
||||
}
|
||||
achievementConfigPath = getConfigPath(achievementConfigPath); // qualify
|
||||
|
||||
// :TODO: Log enabled
|
||||
|
||||
const configLoaded = (achievementConfig) => {
|
||||
if(true !== achievementConfig.enabled) {
|
||||
this.stopMonitoringUserStatUpdateEvents();
|
||||
delete this.achievementConfig;
|
||||
} else {
|
||||
this.achievementConfig = achievementConfig;
|
||||
this.monitorUserStatUpdateEvents();
|
||||
}
|
||||
};
|
||||
|
||||
const changed = ( { fileName, fileRoot } ) => {
|
||||
const reCachedPath = paths.join(fileRoot, fileName);
|
||||
if(reCachedPath === achievementConfigPath) {
|
||||
getFullConfig(achievementConfigPath, (err, achievementConfig) => {
|
||||
if(err) {
|
||||
return Log.error( { error : err.message }, 'Failed to reload achievement config from cache');
|
||||
}
|
||||
configLoaded(achievementConfig);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
ConfigCache.getConfigWithOptions(
|
||||
{
|
||||
filePath : achievementConfigPath,
|
||||
forceReCache : true,
|
||||
callback : changed,
|
||||
},
|
||||
(err, achievementConfig) => {
|
||||
if(err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
configLoaded(achievementConfig);
|
||||
return cb(null);
|
||||
}
|
||||
);
|
||||
|
||||
// :TODO: if enabled/etc., load achievements.hjson -> if theme achievements.hjson{}, merge @ display time?
|
||||
// merge for local vs global (per theme) clients
|
||||
// ...only merge/override text
|
||||
this.monitorUserStatUpdateEvents();
|
||||
return cb(null);
|
||||
// ...only merge/override text
|
||||
}
|
||||
|
||||
loadAchievementHitCount(user, achievementTag, field, cb) {
|
||||
|
@ -139,7 +190,7 @@ class Achievements {
|
|||
return cb(err);
|
||||
}
|
||||
|
||||
Events.emit(
|
||||
this.events.emit(
|
||||
Events.getSystemEvents().UserAchievementEarned,
|
||||
{
|
||||
user : info.client.user,
|
||||
|
@ -172,7 +223,11 @@ class Achievements {
|
|||
}
|
||||
|
||||
monitorUserStatUpdateEvents() {
|
||||
this.events.on(Events.getSystemEvents().UserStatUpdate, userStatEvent => {
|
||||
if(this.userStatEventListener) {
|
||||
return; // already listening
|
||||
}
|
||||
|
||||
this.userStatEventListener = this.events.on(Events.getSystemEvents().UserStatUpdate, userStatEvent => {
|
||||
if([ UserProps.AchievementTotalCount, UserProps.AchievementTotalPoints ].includes(userStatEvent.statName)) {
|
||||
return;
|
||||
}
|
||||
|
@ -182,10 +237,9 @@ class Achievements {
|
|||
return;
|
||||
}
|
||||
|
||||
const config = Config();
|
||||
// :TODO: Make this code generic - find + return factory created object
|
||||
const achievementTag = _.findKey(
|
||||
_.get(config, 'userAchievements.achievements', {}),
|
||||
_.get(this.achievementConfig, 'achievements', {}),
|
||||
achievement => {
|
||||
if(false === achievement.enabled) {
|
||||
return false;
|
||||
|
@ -199,7 +253,7 @@ class Achievements {
|
|||
return;
|
||||
}
|
||||
|
||||
const achievement = Achievement.factory(config.userAchievements.achievements[achievementTag]);
|
||||
const achievement = Achievement.factory(this.achievementConfig.achievements[achievementTag]);
|
||||
if(!achievement) {
|
||||
return;
|
||||
}
|
||||
|
@ -230,10 +284,11 @@ class Achievements {
|
|||
achievement,
|
||||
details,
|
||||
client,
|
||||
matchField,
|
||||
matchValue,
|
||||
user : userStatEvent.user,
|
||||
timestamp : moment(),
|
||||
matchField, // match - may be in odd format
|
||||
matchValue, // actual value
|
||||
achievedValue : matchField, // achievement value met
|
||||
user : userStatEvent.user,
|
||||
timestamp : moment(),
|
||||
};
|
||||
|
||||
return callback(null, info);
|
||||
|
@ -256,6 +311,13 @@ class Achievements {
|
|||
});
|
||||
}
|
||||
|
||||
stopMonitoringUserStatUpdateEvents() {
|
||||
if(this.userStatEventListener) {
|
||||
this.events.removeListener(Events.getSystemEvents().UserStatUpdate, this.userStatEventListener);
|
||||
delete this.userStatEventListener;
|
||||
}
|
||||
}
|
||||
|
||||
createAchievementInterruptItems(info, cb) {
|
||||
const dateTimeFormat =
|
||||
info.details.dateTimeFormat ||
|
||||
|
@ -291,7 +353,7 @@ class Achievements {
|
|||
const spec =
|
||||
_.get(info.details, `art.${name}`) ||
|
||||
_.get(info.achievement, `art.${name}`) ||
|
||||
_.get(config, `userAchievements.art.${name}`);
|
||||
_.get(this.achievementConfig, `art.${name}`);
|
||||
if(!spec) {
|
||||
return callback(null);
|
||||
}
|
||||
|
@ -351,12 +413,6 @@ class Achievements {
|
|||
let achievements;
|
||||
|
||||
exports.moduleInitialize = (initInfo, cb) => {
|
||||
|
||||
if(false === _.get(Config(), 'userAchievements.enabled')) {
|
||||
// :TODO: Log disabled
|
||||
return cb(null);
|
||||
}
|
||||
|
||||
achievements = new Achievements(initInfo.events);
|
||||
return achievements.init(cb);
|
||||
};
|
||||
|
|
|
@ -175,6 +175,7 @@ function getDefaultConfig() {
|
|||
|
||||
menuFile : 'menu.hjson', // 'oputil.js config new' will set this appropriately in config.hjson; may be full path
|
||||
promptFile : 'prompt.hjson', // 'oputil.js config new' will set this appropriately in config.hjson; may be full path
|
||||
achievementFile : 'achievements.hjson',
|
||||
},
|
||||
|
||||
users : {
|
||||
|
@ -1004,46 +1005,5 @@ function getDefaultConfig() {
|
|||
loginHistoryMax: -1, // set to -1 for forever
|
||||
}
|
||||
},
|
||||
|
||||
userAchievements : {
|
||||
enabled : true,
|
||||
|
||||
art : {
|
||||
localHeader : 'achievement_local_header',
|
||||
localFooter : 'achievement_local_footer',
|
||||
globalHeader : 'achievement_global_header',
|
||||
globalFooter : 'achievement_global_footer',
|
||||
},
|
||||
|
||||
// :TODO: achievements should be a path/filename -> achievements.hjson & allow override/theming
|
||||
|
||||
achievements : {
|
||||
user_login_count : {
|
||||
type : 'userStat',
|
||||
statName : 'login_count',
|
||||
retroactive : true,
|
||||
match : {
|
||||
10 : {
|
||||
title : 'Return Caller',
|
||||
globalText : '{userName} has logged in {matchValue} times!',
|
||||
text : 'You\'ve logged in {matchValue} times!',
|
||||
points : 5,
|
||||
},
|
||||
25 : {
|
||||
title : 'Seems To Like It!',
|
||||
globalText : '{userName} has logged in {matchValue} times!',
|
||||
text : 'You\'ve logged in {matchValue} times!',
|
||||
points : 10,
|
||||
},
|
||||
100 : {
|
||||
title : '{boardName} Addict',
|
||||
globalText : '{userName} the BBS {boardName} addict has logged in {matchValue} times!',
|
||||
text : 'You\'re a {boardName} addict! You\'ve logged in {matchValue} times!',
|
||||
points : 10,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ const paths = require('path');
|
|||
const async = require('async');
|
||||
|
||||
exports.init = init;
|
||||
exports.getConfigPath = getConfigPath;
|
||||
exports.getFullConfig = getFullConfig;
|
||||
|
||||
function getConfigPath(filePath) {
|
||||
|
|
Loading…
Reference in New Issue