mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-02-17 08:50:58 -05:00
Fixed a ton of memory leaks, but not all of them.
This commit is contained in:
parent
b696a3f188
commit
6af2d34f59
10 changed files with 56 additions and 17 deletions
|
@ -20,7 +20,7 @@ elementAcceptsKeystrokes = (el) ->
|
|||
# not radio, checkbox, range, or color
|
||||
return (tag is 'textarea' or (tag is 'input' and type in textInputTypes) or el.contentEditable in ["", "true"]) and not (el.readOnly or el.disabled)
|
||||
|
||||
COMMON_FILES = ['/images/modal_background.png', '/images/level/code_palette_background.png']
|
||||
COMMON_FILES = ['/images/pages/base/modal_background.png', '/images/level/code_palette_background.png']
|
||||
preload = (arrayOfImages) ->
|
||||
$(arrayOfImages).each ->
|
||||
$('<img/>')[0].src = @
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
## Uncomment to imitate IE9 (and in world_utils.coffee)
|
||||
#window.Worker = null
|
||||
#window.Float32Array = null
|
||||
# (except that we won't have included vendor_with_box2d.js, so Collision won't run, things won't move, etc.)
|
||||
# Also uncomment vendor_with_box2d.js in index.html if you want Collision to run and things to move.
|
||||
|
||||
module.exports = class God
|
||||
@ids: ['Athena', 'Baldr', 'Crom', 'Dagr', 'Eris', 'Freyja', 'Great Gish', 'Hades', 'Ishtar', 'Janus', 'Khronos', 'Loki', 'Marduk', 'Negafook', 'Odin', 'Poseidon', 'Quetzalcoatl', 'Ra', 'Shiva', 'Thor', 'Umvelinqangi', 'Týr', 'Vishnu', 'Wepwawet', 'Xipe Totec', 'Yahweh', 'Zeus', '上帝', 'Tiamat', '盘古', 'Phoebe', 'Artemis', 'Osiris', "嫦娥", 'Anhur', 'Teshub', 'Enlil', 'Perkele', 'Aether', 'Chaos', 'Hera', 'Iris', 'Theia', 'Uranus', 'Stribog', 'Sabazios', 'Izanagi', 'Ao', 'Tāwhirimātea', 'Tengri', 'Inmar', 'Torngarsuk', 'Centzonhuitznahua', 'Hunab Ku', 'Apollo', 'Helios', 'Thoth', 'Hyperion', 'Alectrona', 'Eos', 'Mitra', 'Saranyu', 'Freyr', 'Koyash', 'Atropos', 'Clotho', 'Lachesis', 'Tyche', 'Skuld', 'Urðr', 'Verðandi', 'Camaxtli', 'Huhetotl', 'Set', 'Anu', 'Allah', 'Anshar', 'Hermes', 'Lugh', 'Brigit', 'Manannan Mac Lir', 'Persephone', 'Mercury', 'Venus', 'Mars', 'Azrael', 'He-Man', 'Anansi', 'Issek', 'Mog', 'Kos', 'Amaterasu Omikami', 'Raijin', 'Susanowo', 'Blind Io', 'The Lady', 'Offler', 'Ptah', 'Anubis', 'Ereshkigal', 'Nergal', 'Thanatos', 'Macaria', 'Angelos', 'Erebus', 'Hecate', 'Hel', 'Orcus', 'Ishtar-Deela Nakh', 'Prometheus', 'Hephaestos', 'Sekhmet', 'Ares', 'Enyo', 'Otrera', 'Pele', 'Hadúr', 'Hachiman', 'Dayisun Tngri', 'Ullr', 'Lua', 'Minerva']
|
||||
|
@ -25,17 +25,22 @@ module.exports = class God
|
|||
@createWorld()
|
||||
|
||||
getAngel: ->
|
||||
freeAngel = null
|
||||
for angel in @angels
|
||||
return angel.enslave() unless angel.busy
|
||||
if angel.busy
|
||||
angel.abort()
|
||||
else
|
||||
freeAngel ?= angel
|
||||
return freeAngel.enslave() if freeAngel
|
||||
maxedOut = @angels.length is @maxAngels
|
||||
if not maxedOut
|
||||
angel = new Angel @
|
||||
@angels.push angel
|
||||
return angel.enslave()
|
||||
oldestAngel = {started: new Date(2099, 1, 1)}
|
||||
for angel in @angels
|
||||
oldestAngel = angel if angel.started < oldestAngel.started
|
||||
oldestAngel.abort()
|
||||
#oldestAngel = {started: new Date(2099, 1, 1)}
|
||||
#for angel in @angels
|
||||
# oldestAngel = angel if angel.started < oldestAngel.started
|
||||
#oldestAngel.abort()
|
||||
null
|
||||
|
||||
angelInfinitelyLooped: (angel) ->
|
||||
|
@ -65,6 +70,13 @@ module.exports = class God
|
|||
else
|
||||
@worldWaiting = true
|
||||
return
|
||||
console.log "about to post message", @getUserCodeMap(), @level, @firstWorld, @goalManager?.getGoals(), JSON.stringify({
|
||||
worldName: @world.name
|
||||
userCodeMap: @getUserCodeMap()
|
||||
level: @level
|
||||
firstWorld: @firstWorld
|
||||
goals: @goalManager?.getGoals()
|
||||
}).length
|
||||
angel.worker.postMessage {func: 'runWorld', args: {
|
||||
worldName: @world.name
|
||||
userCodeMap: @getUserCodeMap()
|
||||
|
@ -91,8 +103,11 @@ module.exports = class God
|
|||
Backbone.Mediator.publish('god:new-world-created', world: @world, firstWorld: @firstWorld, errorCount: errorCount, goalStates: @latestGoalStates)
|
||||
for scriptNote in @world.scriptNotes
|
||||
Backbone.Mediator.publish scriptNote.channel, scriptNote.event
|
||||
@goalManager?.world = newWorld
|
||||
@firstWorld = false
|
||||
@testWorld = null
|
||||
unless _.find @angels, 'busy'
|
||||
@spells = null # Don't hold onto old spells; memory leaks
|
||||
|
||||
getUserCodeMap: ->
|
||||
userCodeMap = {}
|
||||
|
@ -171,6 +186,7 @@ class Angel
|
|||
@busy = true
|
||||
@started = new Date()
|
||||
@purgatoryTimer = setInterval @testWorker, @infiniteLoopIntervalDuration
|
||||
@spawnWorker() unless @worker
|
||||
@
|
||||
|
||||
free: ->
|
||||
|
@ -178,6 +194,8 @@ class Angel
|
|||
@started = null
|
||||
clearInterval @purgatoryTimer
|
||||
@purgatoryTimer = null
|
||||
@worker.terminate()
|
||||
@worker = null
|
||||
@
|
||||
|
||||
abort: ->
|
||||
|
@ -186,8 +204,8 @@ class Angel
|
|||
|
||||
terminate: =>
|
||||
@worker.terminate()
|
||||
@worker = null
|
||||
return if @dead
|
||||
@spawnWorker()
|
||||
@free()
|
||||
@god.angelAborted @
|
||||
|
||||
|
@ -219,7 +237,9 @@ class Angel
|
|||
clearTimeout @abortTimeout
|
||||
@free()
|
||||
@god.angelAborted @
|
||||
@worker.terminate() if @god.dead
|
||||
if @god.dead
|
||||
@worker.terminate()
|
||||
@worker = null
|
||||
when 'reportIn'
|
||||
clearTimeout @condemnTimeout
|
||||
else
|
||||
|
|
|
@ -116,7 +116,8 @@ module.exports = class LevelLoader extends CocoClass
|
|||
# World init
|
||||
|
||||
initWorld: ->
|
||||
return if @world
|
||||
return if @initialized
|
||||
@initialized = true
|
||||
@world = new World @level.get('name')
|
||||
serializedLevel = @level.serialize(@supermodel)
|
||||
@world.loadFromLevel serializedLevel, false
|
||||
|
@ -203,9 +204,9 @@ module.exports = class LevelLoader extends CocoClass
|
|||
notifyProgress: ->
|
||||
Backbone.Mediator.publish 'level-loader:progress-changed', progress: @progress()
|
||||
@initWorld() if @allDone()
|
||||
# @trigger 'ready-to-init-world' if @allDone()
|
||||
@trigger 'loaded-all' if @progress() is 1
|
||||
|
||||
destroy: ->
|
||||
@world = null # don't hold onto garbage
|
||||
@supermodel.off 'loaded-one', @onSupermodelLoadedOne
|
||||
super()
|
||||
|
|
|
@ -19,6 +19,7 @@ module.exports = class SpriteBoss extends CocoClass
|
|||
'level-suppress-selection-sounds': 'onSuppressSelectionSounds'
|
||||
'level-lock-select': 'onSetLockSelect'
|
||||
'level:restarted': 'onLevelRestarted'
|
||||
'god:new-world-created': 'onNewWorld'
|
||||
|
||||
constructor: (@options) ->
|
||||
super()
|
||||
|
@ -87,7 +88,7 @@ module.exports = class SpriteBoss extends CocoClass
|
|||
@selectionMark = new Mark name: 'selection', camera: @camera, layer: @spriteLayers["Ground"], thangType: @thangTypeFor("Selection")
|
||||
|
||||
createSpriteOptions: (options) ->
|
||||
_.extend options, camera: @camera, resolutionFactor: 4, groundLayer: @spriteLayers["Ground"], textLayer: @surfaceTextLayer, floatingLayer: @spriteLayers["Floating"], markThangTypes: @markThangTypes(), spriteSheetCache: @spriteSheetCache, showInvisible: @options.showInvisible, world: @world
|
||||
_.extend options, camera: @camera, resolutionFactor: 4, groundLayer: @spriteLayers["Ground"], textLayer: @surfaceTextLayer, floatingLayer: @spriteLayers["Floating"], markThangTypes: @markThangTypes(), spriteSheetCache: @spriteSheetCache, showInvisible: @options.showInvisible
|
||||
|
||||
createIndieSprites: (indieSprites, withWizards) ->
|
||||
unless @indieSprites
|
||||
|
@ -195,6 +196,9 @@ module.exports = class SpriteBoss extends CocoClass
|
|||
|
||||
spriteFor: (thangID) -> @sprites[thangID]
|
||||
|
||||
onNewWorld: (e) ->
|
||||
@world = @options.world = e.world
|
||||
|
||||
# Selection
|
||||
|
||||
onSuppressSelectionSounds: (e) -> @suppressSelectionSounds = e.suppress
|
||||
|
|
|
@ -90,6 +90,7 @@ module.exports = class GoalManager extends CocoClass
|
|||
# passes the word along
|
||||
onNewWorldCreated: (e) =>
|
||||
@updateGoalStates(e.goalStates) if e.goalStates?
|
||||
@world = e.world
|
||||
|
||||
updateGoalStates: (newGoalStates) ->
|
||||
for goalID, goalState of newGoalStates
|
||||
|
|
|
@ -78,7 +78,7 @@ module.exports = class World
|
|||
(@runtimeErrors ?= []).push error
|
||||
(@unhandledRuntimeErrors ?= []).push error
|
||||
|
||||
loadFrames: (loadedCallback, errorCallback, loadProgressCallback) =>
|
||||
loadFrames: (loadedCallback, errorCallback, loadProgressCallback) ->
|
||||
return if @aborted
|
||||
unless @thangs.length
|
||||
console.log "Warning: loadFrames called on empty World (no thangs)."
|
||||
|
|
|
@ -28,7 +28,10 @@ module.exports = class Spell
|
|||
@tabView.render()
|
||||
|
||||
addThang: (thang) ->
|
||||
@thangs[thang.id] ?= {thang: thang, aether: @createAether(thang), castAether: null}
|
||||
if @thangs[thang.id]
|
||||
@thangs[thang.id].thang = thang
|
||||
else
|
||||
@thangs[thang.id] = {thang: thang, aether: @createAether(thang), castAether: null}
|
||||
|
||||
removeThangID: (thangID) ->
|
||||
delete @thangs[thangID]
|
||||
|
|
|
@ -134,3 +134,7 @@ module.exports = class ThangListEntryView extends View
|
|||
return unless currentThang = e.world.thangMap[@thang.id]
|
||||
@$el.toggle Boolean(currentThang.exists)
|
||||
@$el.toggleClass 'dead', currentThang.health <= 0 if currentThang.exists
|
||||
|
||||
destroy: ->
|
||||
super()
|
||||
@avatar.destroy()
|
||||
|
|
|
@ -65,6 +65,7 @@ module.exports = class TomeView extends View
|
|||
else
|
||||
@cast()
|
||||
console.warn "Warning: There are no Programmable Thangs in this level, which makes it unplayable."
|
||||
delete @options.thangs
|
||||
|
||||
onNewWorld: (e) ->
|
||||
thangs = _.filter e.world.thangs, 'isSelectable'
|
||||
|
@ -95,7 +96,7 @@ module.exports = class TomeView extends View
|
|||
@spells[spellKey].addThang thang for spellKey in spellKeys
|
||||
else
|
||||
delete @thangSpells[thangID]
|
||||
@spells[spellKey].removeThangID thangID for spellKey in spellKeys
|
||||
spell.removeThangID thangID for spell in @spells
|
||||
null
|
||||
|
||||
onSpellLoaded: (e) ->
|
||||
|
|
|
@ -50,6 +50,7 @@ module.exports = class PlayLevelView extends View
|
|||
'level-focus-dom': 'onFocusDom'
|
||||
'level-disable-controls': 'onDisableControls'
|
||||
'level-enable-controls': 'onEnableControls'
|
||||
'god:new-world-created': 'onNewWorld'
|
||||
'god:infinite-loop': 'onInfiniteLoop'
|
||||
'bus:connected': 'onBusConnected'
|
||||
'level-reload-from-data': 'onLevelReloadFromData'
|
||||
|
@ -102,7 +103,6 @@ module.exports = class PlayLevelView extends View
|
|||
|
||||
load: ->
|
||||
@levelLoader = new LevelLoader(@levelID, @supermodel, @sessionID)
|
||||
@levelLoader.once 'ready-to-init-world', @onReadyToInitWorld
|
||||
@levelLoader.once 'loaded-all', @onLevelLoaderLoaded
|
||||
|
||||
getRenderData: ->
|
||||
|
@ -120,6 +120,8 @@ module.exports = class PlayLevelView extends View
|
|||
@session = @levelLoader.session
|
||||
@level = @levelLoader.level
|
||||
@world = @levelLoader.world
|
||||
@levelLoader.destroy()
|
||||
@levelLoader = null
|
||||
@loadingScreen.destroy()
|
||||
@setTeam @world.teamForPlayer 1 # We don't know which player we are; this will go away--temp TODO
|
||||
@initSurface()
|
||||
|
@ -206,6 +208,9 @@ module.exports = class PlayLevelView extends View
|
|||
$('#level-done-button', @$el).hide()
|
||||
window.tracker?.trackEvent 'Confirmed Restart', level: @world.name, label: @world.name
|
||||
|
||||
onNewWorld: (e) ->
|
||||
@world = e.world
|
||||
|
||||
onInfiniteLoop: (e) ->
|
||||
return unless e.firstWorld
|
||||
@openModalView new InfiniteLoopModal()
|
||||
|
@ -378,7 +383,7 @@ module.exports = class PlayLevelView extends View
|
|||
|
||||
destroy: ->
|
||||
super()
|
||||
@levelLoader.destroy()
|
||||
@levelLoader?.destroy()
|
||||
@surface?.destroy()
|
||||
@god?.destroy()
|
||||
@goalManager?.destroy()
|
||||
|
|
Loading…
Reference in a new issue