back to updating a batch user object manually. interesting thing, batch.obj loses its properties (like batch.obj.stats) unless returned as the value of a function...

This commit is contained in:
Tyler Renelle 2013-02-04 00:50:02 -05:00
parent 29bb99373e
commit fac802cddb
2 changed files with 84 additions and 68 deletions

View file

@ -65,22 +65,25 @@ module.exports.updateUser = (batch) ->
module.exports.BatchUpdate = BatchUpdate = (model) ->
user = model.at("_user")
transactionInProgress = false
obj = {}
updates = {}
{
user: user
obj: -> obj
startTransaction: ->
# start a batch transaction - nothing between now and @commit() will be set immediately
transactionInProgress = true
model._dontPersist = true
# Really strange, user.get() seems to only return attributes which have previously been accessed. So in
# many cases, userObj.tasks.{taskId}.value is undefined - so we manually .get() each attribute here.
# Additionally, for some reason after getting the user object, changing properies manually (userObj.stats.hp = 50)
# seems to actually run user.set('stats.hp',50) which we don't want to do - so we deepClone here
#_.each Object.keys(userSchema), (key) -> userObj[key] = lodash.cloneDeep user.get(key)
model._dontPersist = true
obj = user.get()
###
Handles updating the user model. If this is an en-mass operation (eg, server cron), changes are queued
@ -91,6 +94,23 @@ module.exports.BatchUpdate = BatchUpdate = (model) ->
updates[path] = val if transactionInProgress
user.set(path, val)
###
Hack to get around dom bindings being lost if parent objects are replaced whole-sale
eg, user.set('stats', {hp:50, exp:10...}) will break dom bindings, but user.set('stats.hp',50) is ok
###
setStats: ->
that = @
_.each Object.keys(obj.stats), (key) -> that.set "stats.#{key}", obj.stats[key]
# queue: (path, val) ->
# # Special function for setting object properties by string dot-notation. See http://stackoverflow.com/a/6394168/362790
# arr = path.split('.')
# arr.reduce (curr, next, index) ->
# if (arr.length - 1) == index
# curr[next] = val
# curr[next]
# , obj
commit: ->
model._dontPersist = false
# some hackery in our own branched racer-db-mongo, see findAndModify of lefnire/racer-db-mongo#habitrpg index.js

View file

@ -59,61 +59,57 @@ taskDeltaFormula = (currentValue, direction) ->
{update} if aggregated changes, pass in userObj as update. otherwise commits will be made immediately
###
updateStats = (newStats, batch) ->
user = batch.user
stats = batch.user.get('stats')
obj = batch.obj()
# if user is dead, dont do anything
return if stats.lvl == 0
return if obj.stats.lvl == 0
if newStats.hp?
# Game Over
if newStats.hp <= 0
batch.set 'stats.lvl', 0 # signifies dead
batch.set 'stats.hp', 0
obj.stats.lvl = 0 # signifies dead
obj.stats.hp = 0
return
else
batch.set 'stats.hp', newStats.hp
obj.stats.hp = newStats.hp
if newStats.exp?
# level up & carry-over exp
tnl = user.get '_tnl'
if newStats.exp >= tnl
newStats.exp -= tnl
batch.set 'stats.lvl', stats.lvl + 1
batch.set 'stats.hp', 50
newStats.lvl = stats.lvl
if !user.get('items.itemsEnabled') and newStats.lvl >= 2
batch.set 'items.itemsEnabled', true #bit of trouble using userSet here
if !user.get('flags.partyEnabled') and newStats.lvl >= 3
batch.set 'flags.partyEnabled', true
batch.set 'stats.exp', newStats.exp
obj.stats.lvl++
obj.stats.hp = 50
if !obj.items.itemsEnabled and obj.stats.lvl >= 2
obj.items.itemsEnabled = true #bit of trouble using userSet here
if !obj.flags.partyEnabled and obj.stats.lvl >= 3
obj.flags.partyEnabled = true
obj.stats.exp = newStats.exp
if newStats.money?
#FIXME what was I doing here? I can't remember, money isn't defined
money = 0.0 if (!money? or money<0)
batch.set 'stats.money', newStats.money
obj.stats.money = newStats.money
# {taskId} task you want to score
# {direction} 'up' or 'down'
# {times} # times to call score on this task (1 unless cron, usually)
# {update} if we're running updates en-mass (eg, cron on server) pass in userObj
score = (taskId, direction, times, batch, cron) ->
times ?= 1
commit = false
unless batch?
console.log("HI")
commit = true
batch = new schema.BatchUpdate(model)
batch.startTransaction()
obj = batch.obj()
{money, hp, exp, lvl} = user.get('stats')
{money, hp, exp, lvl} = obj.stats
taskPath = "tasks.#{taskId}"
taskObj = user.get(taskPath)
taskObj = obj.tasks[taskId]
{type, value} = taskObj
delta = 0
times ?= 1
calculateDelta = (adjustvalue=true) ->
# If multiple days have passed, multiply times days missed
_.times times, (n) ->
@ -142,13 +138,15 @@ score = (taskId, direction, times, batch, cron) ->
historyEntry = { date: +new Date, value: value }
if (delta > 0) then addPoints() else subtractPoints()
taskObj.history ?= []
taskObj.history.push historyEntry
batch.set "#{taskPath}.history", taskObj.history if taskObj.value != value
taskObj.history.push historyEntry if taskObj.value != value
when 'daily'
calculateDelta()
if cron? # cron
subtractPoints()
taskObj.history ?= []
taskObj.history.push { date: +new Date, value: value }
taskObj.completed = false
else
addPoints() # obviously for delta>0, but also a trick to undo accidental checkboxes
@ -168,9 +166,12 @@ score = (taskId, direction, times, batch, cron) ->
hp += money # hp - money difference
money = 0
batch.set "#{taskPath}.value", value
taskObj.value = value
batch.set "tasks.#{taskId}", taskObj
updateStats {hp: hp, exp: exp, money: money}, batch
batch.commit() if commit
if commit
batch.setStats()
batch.commit()
return delta
###
@ -184,13 +185,15 @@ cron = (resetDom_cb) ->
batch = new schema.BatchUpdate(model)
batch.startTransaction()
batch.set 'lastCron', today
user = batch.user
hpBefore = user.get('stats.hp') #we'll use this later so we can animate hp loss
obj = batch.obj()
hpBefore = obj.stats.hp #we'll use this later so we can animate hp loss
# Tally each task
todoTally = 0
_.each user.get('tasks'), (taskObj) ->
#FIXME remove broken tasks
if taskObj.id? # a task had a null id during cron, this should not be happening
_.each obj.tasks, (taskObj) ->
unless taskObj.id?
console.error "a task had a null id during cron, this should not be happening"
return
{id, type, completed, repeat} = taskObj
if type in ['todo', 'daily']
# Deduct experience for missed Daily tasks,
@ -208,33 +211,26 @@ cron = (resetDom_cb) ->
daysFailed++
score id, 'down', daysFailed, batch, true
value = taskObj.value #get updated value
if type == 'daily'
taskObj.history ?= []
taskObj.history.push { date: today, value: value }
taskObj.completed = false
else
if type == 'todo'
value = obj.tasks[taskObj.id].value #get updated value
absVal = if (completed) then Math.abs(value) else value
todoTally += absVal
batch.set('tasks.' + taskObj.id, taskObj)
# Finished tallying
history = user.get('history') || {}
history.todos ?= []; history.exp ?= []
history.todos.push { date: today, value: todoTally }
obj.history ?= {}; obj.history.todos ?= []; obj.history.exp ?= []
obj.history.todos.push { date: today, value: todoTally }
# tally experience
expTally = user.get('stats.exp')
expTally = obj.stats.exp
lvl = 0 #iterator
while lvl < (user.get('stats.lvl')-1)
while lvl < (obj.stats.lvl-1)
lvl++
expTally += (lvl*100)/5
history.exp.push { date: today, value: expTally }
obj.history.exp.push { date: today, value: expTally }
# Set the new user specs, and animate HP loss
stats = user.get('stats')
[hpAfter, stats.hp] = [stats.hp, hpBefore]
batch.set('stats', stats)
batch.set('history', history)
[hpAfter, obj.stats.hp] = [obj.stats.hp, hpBefore]
batch.setStats()
batch.set('history', obj.history)
batch.commit()
resetDom_cb(model)
setTimeout (-> user.set 'stats.hp', hpAfter), 1000 # animate hp loss