mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-03-14 07:00:01 -04:00
Significantly reduced memory usage and simulation time by further limiting the amount of Thangs which even start tracking ThangState in the first place.
This commit is contained in:
parent
95dca575d1
commit
bf71893ddf
5 changed files with 47 additions and 19 deletions
|
@ -392,20 +392,29 @@ self.onWorldLoaded = function onWorldLoaded() {
|
|||
self.postMessage({type: 'end-load-frames', goalStates: goalStates, overallStatus: overallStatus});
|
||||
var t1 = new Date();
|
||||
var diff = t1 - self.t0;
|
||||
if (self.world.headless)
|
||||
if(self.world.headless)
|
||||
return console.log('Headless simulation completed in ' + diff + 'ms.');
|
||||
|
||||
var worldEnded = self.world.ended;
|
||||
var totalFrames = self.world.totalFrames;
|
||||
var transferableSupported = self.transferableSupported();
|
||||
try {
|
||||
var serialized = self.world.serialize();
|
||||
}
|
||||
catch(error) {
|
||||
console.log("World serialization error:", error.toString() + "\n" + error.stack || error.stackTrace);
|
||||
self.destroyWorld();
|
||||
return;
|
||||
}
|
||||
//self.serialized = serialized; // Testing peak memory usage
|
||||
//return; // Testing peak memory usage
|
||||
if(worldEnded)
|
||||
// Make sure we clean up memory as soon as possible, since we just used the most ever and don't want to crash.
|
||||
self.destroyWorld();
|
||||
|
||||
var t2 = new Date();
|
||||
//console.log("About to transfer", serialized.serializedWorld.trackedPropertiesPerThangValues, serialized.transferableObjects);
|
||||
var messageType = self.world.ended ? 'new-world' : 'some-frames-serialized';
|
||||
var messageType = worldEnded ? 'new-world' : 'some-frames-serialized';
|
||||
try {
|
||||
var message = {type: messageType, serialized: serialized.serializedWorld, goalStates: goalStates, startFrame: serialized.startFrame, endFrame: serialized.endFrame};
|
||||
if(transferableSupported)
|
||||
|
@ -417,15 +426,18 @@ self.onWorldLoaded = function onWorldLoaded() {
|
|||
console.log("World delivery error:", error.toString() + "\n" + error.stack || error.stackTrace);
|
||||
}
|
||||
|
||||
if(self.world.ended) {
|
||||
if(worldEnded) {
|
||||
var t3 = new Date();
|
||||
console.log("And it was so: (" + (diff / self.world.totalFrames).toFixed(3) + "ms per frame,", self.world.totalFrames, "frames)\nSimulation :", diff + "ms \nSerialization:", (t2 - t1) + "ms\nDelivery :", (t3 - t2) + "ms");
|
||||
self.world.goalManager.destroy();
|
||||
self.world.destroy();
|
||||
self.world = null;
|
||||
console.log("And it was so: (" + (diff / totalFrames).toFixed(3) + "ms per frame,", totalFrames, "frames)\nSimulation :", diff + "ms \nSerialization:", (t2 - t1) + "ms\nDelivery :", (t3 - t2) + "ms");
|
||||
}
|
||||
};
|
||||
|
||||
self.destroyWorld = function destroyWorld() {
|
||||
self.world.goalManager.destroy();
|
||||
self.world.destroy();
|
||||
self.world = null;
|
||||
};
|
||||
|
||||
self.onWorldPreloaded = function onWorldPreloaded() {
|
||||
self.goalManager.worldGenerationEnded();
|
||||
var goalStates = self.goalManager.getGoalStates();
|
||||
|
|
|
@ -17,6 +17,7 @@ REAL_TIME_BUFFER_MAX = 3 * PROGRESS_UPDATE_INTERVAL
|
|||
REAL_TIME_BUFFERED_WAIT_INTERVAL = 0.5 * PROGRESS_UPDATE_INTERVAL
|
||||
REAL_TIME_COUNTDOWN_DELAY = 3000 # match CountdownScreen
|
||||
ITEM_ORIGINAL = '53e12043b82921000051cdf9'
|
||||
EXISTS_ORIGINAL = '524b4150ff92f1f4f8000024'
|
||||
COUNTDOWN_LEVELS = ['sky-span']
|
||||
|
||||
module.exports = class World
|
||||
|
@ -237,13 +238,19 @@ module.exports = class World
|
|||
|
||||
loadThangFromLevel: (thangConfig, levelComponents, thangTypes, equipBy=null) ->
|
||||
components = []
|
||||
for component in thangConfig.components
|
||||
for component, componentIndex in thangConfig.components
|
||||
componentModel = _.find levelComponents, (c) ->
|
||||
c.original is component.original and c.version.major is (component.majorVersion ? 0)
|
||||
componentClass = @loadClassFromCode componentModel.js, componentModel.name, 'component'
|
||||
components.push [componentClass, component.config]
|
||||
if equipBy and component.original is ITEM_ORIGINAL
|
||||
component.config.ownerID = equipBy
|
||||
if component.original is ITEM_ORIGINAL
|
||||
isItem = true
|
||||
component.config.ownerID = equipBy if equipBy
|
||||
else if component.original is EXISTS_ORIGINAL
|
||||
existsConfigIndex = componentIndex
|
||||
if isItem and existsConfigIndex?
|
||||
# For memory usage performance, make sure these don't get any tracked properties assigned.
|
||||
components[existsConfigIndex][1] = {exists: false, stateless: true}
|
||||
thangTypeOriginal = thangConfig.thangType
|
||||
thangTypeModel = _.find thangTypes, (t) -> t.original is thangTypeOriginal
|
||||
return console.error thangConfig.id ? equipBy, 'could not find ThangType for', thangTypeOriginal unless thangTypeModel
|
||||
|
@ -347,6 +354,7 @@ module.exports = class World
|
|||
|
||||
serialize: ->
|
||||
# Code hotspot; optimize it
|
||||
@freeMemoryBeforeFinalSerialization() if @ended
|
||||
startFrame = @framesSerializedSoFar
|
||||
endFrame = @frames.length
|
||||
#console.log "... world serializing frames from", startFrame, "to", endFrame, "of", @totalFrames
|
||||
|
@ -437,6 +445,7 @@ module.exports = class World
|
|||
o.scriptNotes = (sn.serialize() for sn in @scriptNotes)
|
||||
if o.scriptNotes.length > 200
|
||||
console.log 'Whoa, serializing a lot of WorldScriptNotes here:', o.scriptNotes.length
|
||||
@freeMemoryAfterEachSerialization() unless @ended
|
||||
{serializedWorld: o, transferableObjects: [o.storageBuffer], startFrame: startFrame, endFrame: endFrame}
|
||||
|
||||
@deserialize: (o, classMap, oldSerializedWorldFrames, finishedWorldCallback, startFrame, endFrame, level, streamingWorld) ->
|
||||
|
@ -535,6 +544,13 @@ module.exports = class World
|
|||
console.log 'No frames were changed out of all', @frames.length
|
||||
firstChangedFrame
|
||||
|
||||
freeMemoryBeforeFinalSerialization: ->
|
||||
@levelComponents = null
|
||||
@thangTypes = null
|
||||
|
||||
freeMemoryAfterEachSerialization: ->
|
||||
@frames[i] = null for frame, i in @frames when i < @frames.length - 1
|
||||
|
||||
pointsForThang: (thangID, frameStart=0, frameEnd=null, camera=null, resolution=4) ->
|
||||
# Optimized
|
||||
@pointsForThangCache ?= {}
|
||||
|
|
|
@ -17,7 +17,7 @@ module.exports = class WorldFrame
|
|||
return nextFrame
|
||||
|
||||
setState: ->
|
||||
for thang in @world.thangs
|
||||
for thang in @world.thangs when not thang.stateless
|
||||
@thangStateMap[thang.id] = thang.getState()
|
||||
|
||||
restoreState: ->
|
||||
|
|
|
@ -97,7 +97,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
|
||||
@isEditorPreview = @getQueryVariable 'dev'
|
||||
@sessionID = @getQueryVariable 'session'
|
||||
|
||||
|
||||
@opponentSessionID = @getQueryVariable('opponent')
|
||||
@opponentSessionID ?= @options.opponent
|
||||
|
||||
|
@ -369,7 +369,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
return if @alreadyLoadedState
|
||||
@alreadyLoadedState = true
|
||||
state = @originalSessionState
|
||||
if @level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop']
|
||||
if not @level or @level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop']
|
||||
Backbone.Mediator.publish 'level:suppress-selection-sounds', suppress: true
|
||||
Backbone.Mediator.publish 'tome:select-primary-sprite', {}
|
||||
Backbone.Mediator.publish 'level:suppress-selection-sounds', suppress: false
|
||||
|
@ -552,7 +552,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
return if @destroyed
|
||||
# TODO: Show a victory dialog specific to hero-ladder level
|
||||
if @goalManager.checkOverallStatus() is 'success' and not @options.realTimeMultiplayerSessionID?
|
||||
Backbone.Mediator.publish 'level:show-victory', showModal: true
|
||||
Backbone.Mediator.publish 'level:show-victory', showModal: true
|
||||
|
||||
destroy: ->
|
||||
@levelLoader?.destroy()
|
||||
|
@ -753,7 +753,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
if @realTimeOpponent.get('state') is 'ready'
|
||||
@realTimeOpponent.off 'change', @realTimeOpponentMaybeReady
|
||||
@realTimeOpponentIsReady()
|
||||
|
||||
|
||||
realTimeOpponentIsReady: =>
|
||||
console.info 'All real-time multiplayer players are ready!'
|
||||
@realTimeSession.set 'state', 'running'
|
||||
|
@ -840,7 +840,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
# TODO: This isn't always getting updated where the random seed generation uses it.
|
||||
sessionState.submissionCount = parseInt newSubmissionCount
|
||||
console.info 'Got multiplayer submissionCount', sessionState.submissionCount
|
||||
@session.set 'state', sessionState
|
||||
@session.set 'state', sessionState
|
||||
@session.patch()
|
||||
|
||||
# Reload this level so the opponent session can easily be wired up
|
||||
|
@ -862,7 +862,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
return if me.id is @realTimeSession.get('creator')
|
||||
|
||||
oldTeam = @realTimeOpponent.get('team')
|
||||
return unless oldTeam is @session.get('team')
|
||||
return unless oldTeam is @session.get('team')
|
||||
|
||||
# Need to switch to other team
|
||||
newTeam = if oldTeam is 'humans' then 'ogres' else 'humans'
|
||||
|
@ -898,7 +898,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
if sessionState?
|
||||
# TODO: Don't hard code thangID
|
||||
sessionState.selected = if newTeam is 'humans' then 'Hero Placeholder' else 'Hero Placeholder 1'
|
||||
@session.set 'state', sessionState
|
||||
@session.set 'state', sessionState
|
||||
@session.set 'code', code
|
||||
@session.patch()
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ module.exports.getTwoGames = (req, res) ->
|
|||
#if userIsAnonymous req then return errors.unauthorized(res, 'You need to be logged in to get games.')
|
||||
humansGameID = req.body.humansGameID
|
||||
ogresGameID = req.body.ogresGameID
|
||||
ladderGameIDs = ['greed', 'criss-cross', 'brawlwood', 'dungeon-arena', 'gold-rush', 'sky-span', 'dueling-grounds', 'cavern-survival', 'intuit-tf2014']
|
||||
ladderGameIDs = ['greed', 'criss-cross', 'brawlwood', 'dungeon-arena', 'gold-rush', 'sky-span', 'dueling-grounds', 'cavern-survival', 'multiplayer-treasure-grove']
|
||||
levelID = _.sample ladderGameIDs
|
||||
unless ogresGameID and humansGameID
|
||||
#fetch random games here
|
||||
|
|
Loading…
Reference in a new issue