mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-23 23:58:02 -05:00
Began streaming a mighty stream.
This commit is contained in:
parent
9a116d81be
commit
d55afa77b7
16 changed files with 115 additions and 51 deletions
|
@ -2,7 +2,7 @@ var window = self;
|
|||
var Global = self;
|
||||
|
||||
importScripts("/javascripts/lodash.js", "/javascripts/aether.js");
|
||||
console.log("Aether Tome worker has finished importing scripts.");
|
||||
//console.log("Aether Tome worker has finished importing scripts.");
|
||||
var aethers = {};
|
||||
|
||||
var createAether = function (spellKey, options)
|
||||
|
|
|
@ -300,7 +300,7 @@ self.setupDebugWorldToRunUntilFrame = function (args) {
|
|||
}
|
||||
Math.random = self.debugWorld.rand.randf; // so user code is predictable
|
||||
Aether.replaceBuiltin("Math", Math);
|
||||
replacedLoDash = _.runInContext(self);
|
||||
var replacedLoDash = _.runInContext(self);
|
||||
for(var key in replacedLoDash)
|
||||
_[key] = replacedLoDash[key];
|
||||
}
|
||||
|
@ -358,13 +358,34 @@ self.runWorld = function runWorld(args) {
|
|||
}
|
||||
Math.random = self.world.rand.randf; // so user code is predictable
|
||||
Aether.replaceBuiltin("Math", Math);
|
||||
replacedLoDash = _.runInContext(self);
|
||||
var replacedLoDash = _.runInContext(self);
|
||||
for(var key in replacedLoDash)
|
||||
_[key] = replacedLoDash[key];
|
||||
self.postMessage({type: 'start-load-frames'});
|
||||
self.world.loadFrames(self.onWorldLoaded, self.onWorldError, self.onWorldLoadProgress);
|
||||
};
|
||||
|
||||
self.serializeFramesSoFar = function serializeFramesSoFar() {
|
||||
if(!self.world) return console.error("hmm, no world when we went to serialize some frames?");
|
||||
var goalStates = self.goalManager.getGoalStates();
|
||||
var transferableSupported = self.transferableSupported();
|
||||
var serialized = self.world.serializeFramesSoFar();
|
||||
if(!serialized) {
|
||||
console.log("Tried to serialize some frames, but none have been simulated since last time; still at", self.world.framesSerializedSoFar);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var message = {type: 'some-frames-serialized', serialized: serialized.serializedWorld, goalStates: goalStates, startFrame: serialized.startFrame, endFrame: serialized.endFrame};
|
||||
if(transferableSupported)
|
||||
self.postMessage(message, serialized.transferableObjects);
|
||||
else
|
||||
self.postMessage(message);
|
||||
}
|
||||
catch(error) {
|
||||
console.log("World delivery error:", error.toString() + "\n" + error.stack || error.stackTrace);
|
||||
}
|
||||
};
|
||||
|
||||
self.onWorldLoaded = function onWorldLoaded() {
|
||||
self.goalManager.worldGenerationEnded();
|
||||
var goalStates = self.goalManager.getGoalStates();
|
||||
|
@ -384,7 +405,7 @@ self.onWorldLoaded = function onWorldLoaded() {
|
|||
var t2 = new Date();
|
||||
//console.log("About to transfer", serialized.serializedWorld.trackedPropertiesPerThangValues, serialized.transferableObjects);
|
||||
try {
|
||||
var message = {type: 'new-world', serialized: serialized.serializedWorld, goalStates: goalStates};
|
||||
var message = {type: 'new-world', serialized: serialized.serializedWorld, goalStates: goalStates, startFrame: serialized.startFrame, endFrame: serialized.endFrame};
|
||||
if(transferableSupported)
|
||||
self.postMessage(message, serialized.transferableObjects);
|
||||
else
|
||||
|
|
|
@ -27,7 +27,8 @@ init = ->
|
|||
# Set up Backbone.Mediator schemas
|
||||
setUpDefinitions()
|
||||
setUpChannels()
|
||||
Backbone.Mediator.setValidationEnabled document.location.href.search(/codecombat.com/) is -1
|
||||
#Backbone.Mediator.setValidationEnabled document.location.href.search(/codecombat.com/) is -1
|
||||
Backbone.Mediator.setValidationEnabled false # STREAM: Should change back
|
||||
app.initialize()
|
||||
Backbone.history.start({ pushState: true })
|
||||
handleNormalUrls()
|
||||
|
|
|
@ -67,6 +67,8 @@ module.exports = class Angel extends CocoClass
|
|||
# We pay attention to certain progress indicators as the world loads.
|
||||
when 'world-load-progress-changed'
|
||||
Backbone.Mediator.publish 'god:world-load-progress-changed', event.data
|
||||
unless event.data.progress is 1 or @work.preload or @work.headless or @work.synchronous or @deserializingStreamingFrames
|
||||
@worker.postMessage func: 'serializeFramesSoFar' # Stream it!
|
||||
when 'console-log'
|
||||
@log event.data.args...
|
||||
when 'user-code-problem'
|
||||
|
@ -80,9 +82,16 @@ module.exports = class Angel extends CocoClass
|
|||
else
|
||||
@fireWorker()
|
||||
|
||||
# We have some of the frames serialized, so let's send the partially simulated world to the Surface.
|
||||
when 'some-frames-serialized'
|
||||
console.log "angel received some frames", event.data.serialized, "with goals", event.data.goalStates, "and streaming into world", @shared.streamingWorld
|
||||
@deserializingStreamingFrames = true
|
||||
@beholdWorld event.data.serialized, event.data.goalStates, event.data.startFrame, event.data.endFrame, @shared.streamingWorld
|
||||
|
||||
# Either the world finished simulating successfully, or we abort the worker.
|
||||
when 'new-world'
|
||||
@beholdWorld event.data.serialized, event.data.goalStates
|
||||
console.log "angel received alll frames", event.data.serialized
|
||||
@beholdWorld event.data.serialized, event.data.goalStates, event.data.startFrame, event.data.endFrame
|
||||
when 'abort'
|
||||
@say 'Aborted.', event.data
|
||||
clearTimeout @abortTimeout
|
||||
|
@ -99,26 +108,33 @@ module.exports = class Angel extends CocoClass
|
|||
Backbone.Mediator.publish 'god:goals-calculated', goalStates: goalStates
|
||||
@finishWork() if @shared.headless
|
||||
|
||||
beholdWorld: (serialized, goalStates) ->
|
||||
beholdWorld: (serialized, goalStates, startFrame, endFrame, streamingWorld) ->
|
||||
return if @aborting
|
||||
# Toggle BOX2D_ENABLED during deserialization so that if we have box2d in the namespace, the Collides Components still don't try to create bodies for deserialized Thangs upon attachment.
|
||||
window.BOX2D_ENABLED = false
|
||||
World.deserialize serialized, @shared.worldClassMap, @shared.lastSerializedWorldFrames, @finishBeholdingWorld(goalStates)
|
||||
World.deserialize serialized, @shared.worldClassMap, @shared.lastSerializedWorldFrames, @finishBeholdingWorld(goalStates), startFrame, endFrame, streamingWorld
|
||||
window.BOX2D_ENABLED = true
|
||||
@shared.lastSerializedWorldFrames = serialized.frames
|
||||
|
||||
finishBeholdingWorld: (goalStates) -> (world) =>
|
||||
return if @aborting
|
||||
world.findFirstChangedFrame @shared.world
|
||||
@shared.world = world
|
||||
errorCount = (t for t in @shared.world.thangs when t.errorsOut).length
|
||||
Backbone.Mediator.publish 'god:new-world-created', world: world, firstWorld: @shared.firstWorld, errorCount: errorCount, goalStates: goalStates, team: me.team
|
||||
for scriptNote in @shared.world.scriptNotes
|
||||
Backbone.Mediator.publish scriptNote.channel, scriptNote.event
|
||||
@shared.goalManager?.world = world
|
||||
@finishWork()
|
||||
finished = world.frames.length is world.totalFrames
|
||||
if finished
|
||||
world.findFirstChangedFrame @shared.world
|
||||
@shared.world = world
|
||||
Backbone.Mediator.publish 'god:new-world-created', world: world, firstWorld: @shared.firstWorld, goalStates: goalStates, team: me.team if @shared.firstWorld
|
||||
for scriptNote in @shared.world.scriptNotes
|
||||
Backbone.Mediator.publish scriptNote.channel, scriptNote.event
|
||||
@shared.goalManager?.world = world
|
||||
@finishWork()
|
||||
else
|
||||
@shared.streamingWorld = world
|
||||
#Backbone.Mediator.publish 'god:new-world-created', world: world, firstWorld: @shared.firstWorld, goalStates: goalStates, team: me.team
|
||||
#Backbone.Mediator.publish 'god:streaming-world-updated', world: world, firstWorld: @shared.firstWorld, goalStates: goalStates, team: me.team
|
||||
@deserializingStreamingFrames = false
|
||||
|
||||
finishWork: ->
|
||||
@shared.streamingWorld = null
|
||||
@shared.firstWorld = false
|
||||
@running = false
|
||||
_.remove @shared.busyAngels, @
|
||||
|
@ -127,6 +143,7 @@ module.exports = class Angel extends CocoClass
|
|||
finalizePreload: ->
|
||||
@say 'Finalize preload.'
|
||||
@worker.postMessage func: 'finalizePreload'
|
||||
@work.preload = false
|
||||
|
||||
infinitelyLooped: =>
|
||||
@say 'On infinitely looped! Aborting?', @aborting
|
||||
|
|
|
@ -14,7 +14,7 @@ module.exports = LinkedInHandler = class LinkedInHandler extends CocoClass
|
|||
onLinkedInLoaded: (e) ->
|
||||
IN.Event.on IN, 'auth', @onLinkedInAuth
|
||||
|
||||
onLinkedInAuth: (e) => console.log 'Authorized with LinkedIn'
|
||||
onLinkedInAuth: (e) => #console.log 'Authorized with LinkedIn'
|
||||
|
||||
constructEmployerAgreementObject: (cb) =>
|
||||
IN.API.Profile('me')
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
module.exports = initializeLinkedIn = ->
|
||||
window.linkedInAsyncInit = ->
|
||||
console.log 'Linkedin async init success!'
|
||||
#console.log 'Linkedin async init success!'
|
||||
Backbone.Mediator.publish 'linkedin-loaded'
|
||||
|
||||
linkedInSnippet =
|
||||
|
|
|
@ -19,6 +19,7 @@ module.exports = class SpriteBoss extends CocoClass
|
|||
'level-lock-select': 'onSetLockSelect'
|
||||
'level:restarted': 'onLevelRestarted'
|
||||
'god:new-world-created': 'onNewWorld'
|
||||
'god:streaming-world-updated': 'onNewWorld'
|
||||
'camera:dragged': 'onCameraDragged'
|
||||
'sprite:loaded': -> @update(true)
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
'level-set-surface-camera': 'onSetCamera'
|
||||
'level:restarted': 'onLevelRestarted'
|
||||
'god:new-world-created': 'onNewWorld'
|
||||
'god:streaming-world-updated': 'onNewWorld'
|
||||
'tome:cast-spells': 'onCastSpells'
|
||||
'level-set-letterbox': 'onSetLetterbox'
|
||||
'application:idle-changed': 'onIdleChanged'
|
||||
|
@ -413,7 +414,7 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
@surfaceLayer.addChild @cameraBorder = new CameraBorder bounds: @camera.bounds
|
||||
@screenLayer.addChild new Letterbox canvasWidth: canvasWidth, canvasHeight: canvasHeight
|
||||
@spriteBoss = new SpriteBoss camera: @camera, surfaceLayer: @surfaceLayer, surfaceTextLayer: @surfaceTextLayer, world: @world, thangTypes: @options.thangTypes, choosing: @options.choosing, navigateToSelection: @options.navigateToSelection, showInvisible: @options.showInvisible
|
||||
@castingScreen ?= new CastingScreen camera: @camera, layer: @screenLayer
|
||||
#@castingScreen ?= new CastingScreen camera: @camera, layer: @screenLayer # Not needed with world streaming.
|
||||
@playbackOverScreen ?= new PlaybackOverScreen camera: @camera, layer: @screenLayer
|
||||
@stage.enableMouseOver(10)
|
||||
@stage.addEventListener 'stagemousemove', @onMouseMove
|
||||
|
|
|
@ -10,7 +10,7 @@ WorldScriptNote = require './world_script_note'
|
|||
{now, consolidateThangs, typedArraySupport} = require './world_utils'
|
||||
Component = require 'lib/world/component'
|
||||
System = require 'lib/world/system'
|
||||
PROGRESS_UPDATE_INTERVAL = 200
|
||||
PROGRESS_UPDATE_INTERVAL = 100
|
||||
DESERIALIZATION_INTERVAL = 20
|
||||
ITEM_ORIGINAL = '53e12043b82921000051cdf9'
|
||||
|
||||
|
@ -21,11 +21,13 @@ module.exports = class World
|
|||
preloading: false # Whether we are just preloading a world in case we soon cast it
|
||||
debugging: false # Whether we are just rerunning to debug a world we've already cast
|
||||
headless: false # Whether we are just simulating for goal states instead of all serialized results
|
||||
framesSerializedSoFar: 0
|
||||
apiProperties: ['age', 'dt']
|
||||
constructor: (@userCodeMap, classMap) ->
|
||||
# classMap is needed for deserializing Worlds, Thangs, and other classes
|
||||
@classMap = classMap ? {Vector: Vector, Rectangle: Rectangle, Thang: Thang, Ellipse: Ellipse, LineSegment: LineSegment}
|
||||
Thang.resetThangIDs()
|
||||
@aRandomID = Math.random()
|
||||
|
||||
@userCodeMap ?= {}
|
||||
@thangs = []
|
||||
|
@ -66,7 +68,6 @@ module.exports = class World
|
|||
@thangMap[thang.id] = thang
|
||||
|
||||
thangDialogueSounds: ->
|
||||
if @frames.length < @totalFrames then throw new Error('World should be over before grabbing dialogue')
|
||||
[sounds, seen] = [[], {}]
|
||||
for frame in @frames
|
||||
for thangID, state of frame.thangStateMap
|
||||
|
@ -287,9 +288,17 @@ module.exports = class World
|
|||
addTrackedProperties: (props...) ->
|
||||
@trackedProperties = (@trackedProperties ? []).concat props
|
||||
|
||||
serialize: ->
|
||||
serializeFramesSoFar: ->
|
||||
return null if @frames.length is @framesSerializedSoFar
|
||||
serialized = @serialize @framesSerializedSoFar, @frames.length
|
||||
@framesSerializedSoFar = @frames.length
|
||||
serialized
|
||||
|
||||
serialize: (startFrame=0, endFrame=null) ->
|
||||
# Code hotspot; optimize it
|
||||
if @frames.length < @totalFrames then throw new Error('World Should Be Over Before Serialization')
|
||||
if not endFrame? and @frames.length < @totalFrames then throw new Error('World Should Be Over Before Serialization')
|
||||
endFrame ?= @totalFrames
|
||||
console.log "... world serializing frames from", startFrame, "to", endFrame
|
||||
[transferableObjects, nontransferableObjects] = [0, 0]
|
||||
o = {totalFrames: @totalFrames, maxTotalFrames: @maxTotalFrames, frameRate: @frameRate, dt: @dt, victory: @victory, userCodeMap: {}, trackedProperties: {}}
|
||||
o.trackedProperties[prop] = @[prop] for prop in @trackedProperties or []
|
||||
|
@ -305,19 +314,20 @@ module.exports = class World
|
|||
o.trackedPropertiesPerThangKeys = []
|
||||
o.trackedPropertiesPerThangTypes = []
|
||||
trackedPropertiesPerThangValues = [] # We won't send these, just the offsets and the storage buffer
|
||||
o.trackedPropertiesPerThangValuesOffsets = [] # Needed to reconstruct ArrayBufferViews on other end, since Firefox has bugs transfering those: https://bugzilla.mozilla.org/show_bug.cgi?id=841904 and https://bugzilla.mozilla.org/show_bug.cgi?id=861925
|
||||
o.trackedPropertiesPerThangValuesOffsets = [] # Needed to reconstruct ArrayBufferViews on other end, since Firefox has bugs transfering those: https://bugzilla.mozilla.org/show_bug.cgi?id=841904 and https://bugzilla.mozilla.org/show_bug.cgi?id=861925 # Actually, as of January 2014, it should be fixed.
|
||||
transferableStorageBytesNeeded = 0
|
||||
nFrames = @frames.length
|
||||
nFrames = endFrame - startFrame
|
||||
streaming = nFrames < @totalFrames
|
||||
for thang in @thangs
|
||||
# Don't serialize empty trackedProperties for stateless Thangs which haven't changed (like obstacles).
|
||||
# Check both, since sometimes people mark stateless Thangs but don't change them, and those should still be tracked, and the inverse doesn't work on the other end (we'll just think it doesn't exist then).
|
||||
continue if thang.stateless and not _.some(thang.trackedPropertiesUsed, Boolean)
|
||||
continue if thang.stateless and not _.some(thang.trackedPropertiesUsed, Boolean) and not streaming
|
||||
o.trackedPropertiesThangIDs.push thang.id
|
||||
trackedPropertiesIndices = []
|
||||
trackedPropertiesKeys = []
|
||||
trackedPropertiesTypes = []
|
||||
for used, propIndex in thang.trackedPropertiesUsed
|
||||
continue unless used
|
||||
continue unless used or streaming
|
||||
trackedPropertiesIndices.push propIndex
|
||||
trackedPropertiesKeys.push thang.trackedPropertiesKeys[propIndex]
|
||||
trackedPropertiesTypes.push thang.trackedPropertiesTypes[propIndex]
|
||||
|
@ -357,8 +367,8 @@ module.exports = class World
|
|||
|
||||
t1 = now()
|
||||
o.frameHashes = []
|
||||
for frame, frameIndex in @frames
|
||||
o.frameHashes.push frame.serialize(frameIndex, o.trackedPropertiesThangIDs, o.trackedPropertiesPerThangIndices, o.trackedPropertiesPerThangTypes, trackedPropertiesPerThangValues, o.specialValuesToKeys, o.specialKeysToValues)
|
||||
for frameIndex in [startFrame ... endFrame]
|
||||
o.frameHashes.push @frames[frameIndex].serialize(frameIndex, o.trackedPropertiesThangIDs, o.trackedPropertiesPerThangIndices, o.trackedPropertiesPerThangTypes, trackedPropertiesPerThangValues, o.specialValuesToKeys, o.specialKeysToValues)
|
||||
t2 = now()
|
||||
|
||||
unless typedArraySupport
|
||||
|
@ -368,28 +378,29 @@ module.exports = class World
|
|||
flattened.push value
|
||||
o.storageBuffer = flattened
|
||||
|
||||
#console.log 'Allocating memory:', (t1 - t0).toFixed(0), 'ms; assigning values:', (t2 - t1).toFixed(0), 'ms, so', ((t2 - t1) / @frames.length).toFixed(3), 'ms per frame'
|
||||
#console.log 'Allocating memory:', (t1 - t0).toFixed(0), 'ms; assigning values:', (t2 - t1).toFixed(0), 'ms, so', ((t2 - t1) / nFrames).toFixed(3), 'ms per frame for', nFrames, 'frames'
|
||||
#console.log 'Got', transferableObjects, 'transferable objects and', nontransferableObjects, 'nontransferable; stored', transferableStorageBytesNeeded, 'bytes transferably'
|
||||
|
||||
o.thangs = (t.serialize() for t in @thangs.concat(@extraneousThangs ? []))
|
||||
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
|
||||
{serializedWorld: o, transferableObjects: [o.storageBuffer]}
|
||||
{serializedWorld: o, transferableObjects: [o.storageBuffer], startFrame: startFrame, endFrame: endFrame}
|
||||
|
||||
@deserialize: (o, classMap, oldSerializedWorldFrames, finishedWorldCallback) ->
|
||||
@deserialize: (o, classMap, oldSerializedWorldFrames, finishedWorldCallback, startFrame, endFrame, streamingWorld) ->
|
||||
# Code hotspot; optimize it
|
||||
#console.log 'Deserializing', o, 'length', JSON.stringify(o).length
|
||||
#console.log JSON.stringify(o)
|
||||
#console.log 'Got special keys and values:', o.specialValuesToKeys, o.specialKeysToValues
|
||||
perf = {}
|
||||
perf.t0 = now()
|
||||
w = new World o.userCodeMap, classMap
|
||||
nFrames = endFrame - startFrame
|
||||
w = streamingWorld ? new World o.userCodeMap, classMap
|
||||
[w.totalFrames, w.maxTotalFrames, w.frameRate, w.dt, w.scriptNotes, w.victory] = [o.totalFrames, o.maxTotalFrames, o.frameRate, o.dt, o.scriptNotes ? [], o.victory]
|
||||
w[prop] = val for prop, val of o.trackedProperties
|
||||
|
||||
perf.t1 = now()
|
||||
w.thangs = (Thang.deserialize(thang, w, classMap) for thang in o.thangs)
|
||||
w.thangs = (Thang.deserialize(thang, w, classMap) for thang in o.thangs) # TODO: just do the new ones?
|
||||
w.setThang thang for thang in w.thangs
|
||||
w.scriptNotes = (WorldScriptNote.deserialize(sn, w, classMap) for sn in o.scriptNotes)
|
||||
perf.t2 = now()
|
||||
|
@ -400,7 +411,7 @@ module.exports = class World
|
|||
o.trackedPropertiesPerThangValues.push (trackedPropertiesValues = [])
|
||||
trackedPropertiesValuesOffsets = o.trackedPropertiesPerThangValuesOffsets[thangIndex]
|
||||
for type, propIndex in trackedPropertyTypes
|
||||
storage = ThangState.createArrayForType(type, o.totalFrames, o.storageBuffer, trackedPropertiesValuesOffsets[propIndex])[0]
|
||||
storage = ThangState.createArrayForType(type, nFrames, o.storageBuffer, trackedPropertiesValuesOffsets[propIndex])[0]
|
||||
unless typedArraySupport
|
||||
# This could be more efficient
|
||||
i = trackedPropertiesValuesOffsets[propIndex]
|
||||
|
@ -409,26 +420,30 @@ module.exports = class World
|
|||
perf.t3 = now()
|
||||
|
||||
perf.batches = 0
|
||||
w.frames = []
|
||||
_.delay @deserializeSomeFrames, 1, o, w, finishedWorldCallback, perf
|
||||
w.frames = [] unless streamingWorld
|
||||
clearTimeout @deserializationTimeout if @deserializationTimeout
|
||||
@deserializationTimeout = _.delay @deserializeSomeFrames, 1, o, w, finishedWorldCallback, perf, startFrame, endFrame
|
||||
|
||||
# Spread deserialization out across multiple calls so the interface stays responsive
|
||||
@deserializeSomeFrames: (o, w, finishedWorldCallback, perf) =>
|
||||
@deserializeSomeFrames: (o, w, finishedWorldCallback, perf, startFrame, endFrame) =>
|
||||
++perf.batches
|
||||
startTime = now()
|
||||
for frameIndex in [w.frames.length ... o.totalFrames]
|
||||
for frameIndex in [w.frames.length ... endFrame]
|
||||
w.frames.push WorldFrame.deserialize(w, frameIndex, o.trackedPropertiesThangIDs, o.trackedPropertiesThangs, o.trackedPropertiesPerThangKeys, o.trackedPropertiesPerThangTypes, o.trackedPropertiesPerThangValues, o.specialKeysToValues, o.frameHashes[frameIndex])
|
||||
if (now() - startTime) > DESERIALIZATION_INTERVAL
|
||||
_.delay @deserializeSomeFrames, 1, o, w, finishedWorldCallback, perf
|
||||
console.log " Deserialization not finished, let's do it again soon. Have:", w.frames.length, ", wanted from", startFrame, "to", endFrame
|
||||
@deserializationTimeout = _.delay @deserializeSomeFrames, 1, o, w, finishedWorldCallback, perf, startFrame, endFrame
|
||||
return
|
||||
@finishDeserializing w, finishedWorldCallback, perf
|
||||
@deserializationTimeout = null
|
||||
@finishDeserializing w, finishedWorldCallback, perf, startFrame, endFrame
|
||||
|
||||
@finishDeserializing: (w, finishedWorldCallback, perf) ->
|
||||
@finishDeserializing: (w, finishedWorldCallback, perf, startFrame, endFrame) ->
|
||||
perf.t4 = now()
|
||||
nFrames = endFrame - startFrame
|
||||
w.ended = true
|
||||
w.getFrame(w.totalFrames - 1).restoreState()
|
||||
w.getFrame(endFrame - 1).restoreState()
|
||||
perf.t5 = now()
|
||||
console.log 'Deserialization:', (perf.t5 - perf.t0).toFixed(0) + 'ms (' + ((perf.t5 - perf.t0) / w.frames.length).toFixed(3) + 'ms per frame).', perf.batches, 'batches.'
|
||||
console.log 'Deserialization:', (perf.t5 - perf.t0).toFixed(0) + 'ms (' + ((perf.t5 - perf.t0) / nFrames).toFixed(3) + 'ms per frame).', perf.batches, 'batches.'
|
||||
if false
|
||||
console.log ' Deserializing--constructing new World:', (perf.t1 - perf.t0).toFixed(2) + 'ms'
|
||||
console.log ' Deserializing--Thangs and ScriptNotes:', (perf.t2 - perf.t1).toFixed(2) + 'ms'
|
||||
|
|
|
@ -111,7 +111,7 @@ module.exports = class Level extends CocoModel
|
|||
visit = (c) ->
|
||||
return if c in sorted
|
||||
lc = _.find levelComponents, {original: c.original}
|
||||
console.error thang.id or thang.name, 'couldn\'t find lc for', c, 'of', levelComponents unless lc
|
||||
#console.error thang.id or thang.name, 'couldn\'t find lc for', c, 'of', levelComponents unless lc # STREAM: uncomment
|
||||
return unless lc
|
||||
if lc.name is 'Programmable'
|
||||
# Programmable always comes last
|
||||
|
|
|
@ -188,7 +188,7 @@ module.exports = class ThangType extends CocoModel
|
|||
portrait = if portrait then '(Portrait)' else ''
|
||||
name = _.string.rpad @get('name'), 20
|
||||
time = _.string.lpad '' + new Date().getTime() - startTime, 6
|
||||
console.debug "Built sheet: #{name} #{time}ms #{kind} #{portrait}"
|
||||
#console.debug "Built sheet: #{name} #{time}ms #{kind} #{portrait}" # STREAM: uncomment
|
||||
|
||||
spriteSheetKey: (options) ->
|
||||
colorConfigs = []
|
||||
|
@ -276,7 +276,7 @@ module.exports = class ThangType extends CocoModel
|
|||
@get('components') or [],
|
||||
(compRef) -> compRef.original is LevelComponent.ItemID)
|
||||
return itemComponentRef?.config?.slots or []
|
||||
|
||||
|
||||
getFrontFacingStats: ->
|
||||
stats = []
|
||||
for component in @get('components') or []
|
||||
|
@ -317,4 +317,4 @@ module.exports = class ThangType extends CocoModel
|
|||
snippets = config.programmableSnippets
|
||||
if snippets.length
|
||||
stats.push { name: 'Snippets', value: snippets.join(', ') }
|
||||
stats
|
||||
stats
|
||||
|
|
|
@ -11,5 +11,8 @@ module.exports =
|
|||
'god:new-world-created':
|
||||
{} # TODO schema
|
||||
|
||||
'god:streaming-world-updated':
|
||||
{} # TODO schema
|
||||
|
||||
'god:world-load-progress-changed':
|
||||
{} # TODO schema
|
||||
|
|
|
@ -55,6 +55,7 @@ module.exports = class SpectateLevelView extends RootView
|
|||
'surface:world-set-up': 'onSurfaceSetUpNewWorld'
|
||||
'level:set-team': 'setTeam'
|
||||
'god:new-world-created': 'loadSoundsForWorld'
|
||||
'god:streaming-world-updated': 'loadSoundsForWorld'
|
||||
'next-game-pressed': 'onNextGamePressed'
|
||||
'level:started': 'onLevelStarted'
|
||||
'level:loading-view-unveiled': 'onLoadingViewUnveiled'
|
||||
|
|
|
@ -22,6 +22,7 @@ module.exports = class LevelPlaybackView extends CocoView
|
|||
'level-toggle-grid': 'onToggleGrid'
|
||||
'surface:frame-changed': 'onFrameChanged'
|
||||
'god:new-world-created': 'onNewWorld'
|
||||
'god:streaming-world-updated': 'onNewWorld' # Maybe?
|
||||
'level-set-letterbox': 'onSetLetterbox'
|
||||
'tome:cast-spells': 'onCastSpells'
|
||||
|
||||
|
@ -329,7 +330,9 @@ module.exports = class LevelPlaybackView extends CocoView
|
|||
return if @shouldIgnore()
|
||||
Backbone.Mediator.publish 'level-set-time', ratio: ratio, scrubDuration: duration
|
||||
|
||||
shouldIgnore: -> return @disabled or @casting or false
|
||||
shouldIgnore: ->
|
||||
#return @disabled or @casting or false # STREAM: figure this out
|
||||
return false
|
||||
|
||||
onTogglePlay: (e) ->
|
||||
e?.preventDefault()
|
||||
|
|
|
@ -53,6 +53,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
'level-disable-controls': 'onDisableControls'
|
||||
'level-enable-controls': 'onEnableControls'
|
||||
'god:new-world-created': 'onNewWorld'
|
||||
'god:streaming-world-updated': 'onNewWorld'
|
||||
'god:infinite-loop': 'onInfiniteLoop'
|
||||
'level-reload-from-data': 'onLevelReloadFromData'
|
||||
'level-reload-thang-type': 'onLevelReloadThangType'
|
||||
|
|
|
@ -128,10 +128,10 @@ module.exports = class SpellView extends CocoView
|
|||
# passEvent: true # https://github.com/ajaxorg/ace/blob/master/lib/ace/keyboard/keybinding.js#L114
|
||||
# No easy way to selectively cancel shift+space, since we don't get access to the event.
|
||||
# Maybe we could temporarily set ourselves to read-only if we somehow know that a script is active?
|
||||
exec: =>
|
||||
exec: =>
|
||||
if @scriptRunning
|
||||
Backbone.Mediator.publish 'level:shift-space-pressed'
|
||||
else
|
||||
else
|
||||
@ace.insert ' '
|
||||
|
||||
addCommand
|
||||
|
|
Loading…
Reference in a new issue