From 92b178b4a41eb96e24449f1bef3e379e85590bae Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Tue, 14 May 2013 17:33:15 +0100 Subject: [PATCH] huge cron fixes which should solve streak, dayStart, "timezone" issues --- src/app/helpers.coffee | 31 ++++++++++++++++--------------- src/app/index.coffee | 4 ---- src/app/scoring.coffee | 37 ++++++++++++++++++++----------------- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/app/helpers.coffee b/src/app/helpers.coffee index 184a75738e..2e8924bd85 100644 --- a/src/app/helpers.coffee +++ b/src/app/helpers.coffee @@ -4,13 +4,22 @@ relative = require 'relative-date' algos = require './algos' items = require('./items').items -# Absolute diff between two dates -daysBetween = (yesterday, now, dayStart) -> +sod = (timestamp, dayStart=0) -> #sanity-check reset-time (is it 24h time?) - dayStart = 0 unless (dayStart? and (dayStart = parseInt(dayStart)) and dayStart >= 0 and dayStart <= 24) - Math.abs moment(yesterday).startOf('day').add('h', dayStart).diff(moment(now), 'days') + dayStart = 0 unless (dayStart = parseInt(dayStart)) and (0 <= dayStart <= 24) + moment(timestamp).startOf('day').add('h', dayStart) -dayMapping = dayMapping = {0:'su',1:'m',2:'t',3:'w',4:'th',5:'f',6:'s',7:'su'} +# Absolute diff between two dates +daysBetween = (yesterday, now, dayStart) -> Math.abs sod(yesterday, dayStart).diff(now, 'days') + +dayMapping = {0:'su',1:'m',2:'t',3:'w',4:'th',5:'f',6:'s'} + +shouldDo = (day, repeat, dayStart=0) -> + now = +new Date + selected = repeat[dayMapping[sod(day, dayStart).day()]] + if moment(day).isSame(now,'d') + return selected and dayStart <= moment(now).hour() + return selected # http://stackoverflow.com/questions/2532218/pick-random-property-from-a-javascript-object # obj: object @@ -139,17 +148,9 @@ viewHelpers = (view) -> classes = type - now = moment().day() - - # calculate the current contextual day (e.g. if it's 12 AM Fri and the user's custom day start is 4 AM, then we should still act like it's Thursday) - dayStart = 0 unless (dayStart? and (dayStart = parseInt(dayStart)) and dayStart >= 0 and dayStart <= 24) - hourDiff = Math.abs moment(lastCron).startOf('day').add('h', dayStart).diff(moment(now), 'hours') - dayStamp = moment(now).add('h', hourDiff) - day = dayStamp.day() - # show as completed if completed (naturally) or not required for today if type in ['todo', 'daily'] - if completed or (repeat and (repeat[dayMapping[day]] == false)) + if completed or !shouldDo(+new Date, task.repeat, dayStart) classes += " completed" else classes += " uncompleted" @@ -216,4 +217,4 @@ viewHelpers = (view) -> -module.exports = { viewHelpers, removeWhitespace, randomVal, daysBetween, dayMapping, username } \ No newline at end of file +module.exports = { viewHelpers, removeWhitespace, randomVal, daysBetween, shouldDo, username } diff --git a/src/app/index.coffee b/src/app/index.coffee index ce28247b02..5ef298b46f 100644 --- a/src/app/index.coffee +++ b/src/app/index.coffee @@ -118,10 +118,6 @@ ready (model) -> user = model.at('_user') model.setNull '_user.apiToken', derby.uuid() - #set cron immediately - lastCron = user.get('lastCron') - user.set('lastCron', +new Date) if (!lastCron? or lastCron == 'new') - require('./scoring').cron(model) require('./character').app(exports, model) diff --git a/src/app/scoring.coffee b/src/app/scoring.coffee index e7c108bf5a..5d15faf2bb 100644 --- a/src/app/scoring.coffee +++ b/src/app/scoring.coffee @@ -19,14 +19,13 @@ randomDrop = (model, delta, priority, streak=0) -> user.setNull 'items.lastDrop', date: +moment().subtract('d',1) # trick - set it to yesterday on first run, that way they can get drops today count: 0 - reachedDropLimit = (helpers.daysBetween(user.get('items.lastDrop.date'), +new Date) is 0) and user.get('items.lastDrop.count') >= 2 + reachedDropLimit = (helpers.daysBetween(user.get('items.lastDrop.date'), +new Date, user.get('preferences.dayStart')) is 0) and user.get('items.lastDrop.count') >= 2 return if reachedDropLimit # % chance of getting a pet or meat chanceMultiplier = Math.abs(delta) chanceMultiplier *= algos.priorityValue(priority) # multiply chance by reddness chanceMultiplier += streak # streak bonus - console.log chanceMultiplier if user.get('flags.dropsEnabled') and Math.random() < (.05 * chanceMultiplier) # current breakdown - 3% (adjustable) chance on drop @@ -273,8 +272,15 @@ updateStats = (model, newStats, batch) -> cron = (model) -> user = model.at '_user' today = +new Date - daysPassed = helpers.daysBetween(user.get('lastCron'), today, user.get('preferences.dayStart')) - if daysPassed > 0 + + lastCron = user.get('lastCron') + # New user (!lastCron, lastCron==new) or it got busted somehow, maybe they went to a different timezone + if !lastCron? or lastCron is 'new' or moment(lastCron).isAfter(today) + user.set('lastCron', +new Date) + return + + daysMissed = helpers.daysBetween(user.get('lastCron'), today, user.get('preferences.dayStart')) + if daysMissed > 0 # User is resting at the inn. Used to be we un-checked each daily without performing calculation (see commits before fb29e35) # but to prevent abusing the inn (http://goo.gl/GDb9x) we now do *not* calculate dailies, and simply set lastCron to today @@ -292,20 +298,17 @@ cron = (model) -> _.each obj.tasks, (taskObj) -> {id, type, completed, repeat} = taskObj if type in ['todo', 'daily'] - # Deduct experience for missed Daily tasks, - # but not for Todos (just increase todo's value) + # Deduct experience for missed Daily tasks, but not for Todos (just increase todo's value) unless completed - # for todos & typical dailies, these are equivalent - daysFailed = daysPassed - # however, for dailys which have repeat dates, need - # to calculate how many they've missed according to their own schedule - if type=='daily' && repeat - daysFailed = 0 - _.times daysPassed, (n) -> - thatDay = moment().subtract('days', n+1) - if repeat[helpers.dayMapping[thatDay.day()]]==true - daysFailed++ - score model, id, 'down', daysFailed, batch, true + scheduleMisses = daysMissed + # for dailys which have repeat dates, need to calculate how many they've missed according to their own schedule + if (type is 'daily') and repeat + scheduleMisses = 0 + _.times daysMissed, (n) -> + thatDay = moment(today).subtract('days', n+1) + scheduleMisses++ if helpers.shouldDo(thatDay, repeat, obj.preferences?.dayStart) is true + score(model, id, 'down', scheduleMisses, batch, true) if scheduleMisses > 0 + if type == 'daily' if completed #set OHV for completed dailies newValue = taskObj.value + algos.taskDeltaFormula(taskObj.value,'up')