From 1406a970eaad4837fa2175bd5b8b52384e094e38 Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Mon, 25 Aug 2014 20:34:46 -0700 Subject: [PATCH] Bunch of fixes to get the level editor working again. --- app/lib/world/world.coffee | 2 +- app/models/Level.coffee | 6 +- app/schemas/models/level.coffee | 2 +- app/schemas/models/level_component.coffee | 2 +- .../thang-component-config-view.sass | 3 + .../component/thang-components-edit-view.sass | 3 + .../thang-component-config-view.jade | 2 +- app/treema-ext.coffee | 2 +- .../component/ThangComponentConfigView.coffee | 10 +++ .../component/ThangComponentsEditView.coffee | 77 +++++++++++++------ .../level/settings/SettingsTabView.coffee | 2 +- config.coffee | 2 +- .../ThangComponentsEditView.demo.coffee | 26 ++++++- 13 files changed, 102 insertions(+), 37 deletions(-) diff --git a/app/lib/world/world.coffee b/app/lib/world/world.coffee index e76ab2707..4611e0930 100644 --- a/app/lib/world/world.coffee +++ b/app/lib/world/world.coffee @@ -209,7 +209,7 @@ module.exports = class World @thangMap = {} # Load new Thangs - toAdd = (@loadThangFromLevel thangConfig, level.levelComponents, level.thangTypes for thangConfig in level.thangs) + toAdd = (@loadThangFromLevel thangConfig, level.levelComponents, level.thangTypes for thangConfig in level.thangs ? []) @extraneousThangs = consolidateThangs toAdd if willSimulate # Combine walls, for example; serialize the leftovers later @addThang thang for thang in toAdd null diff --git a/app/models/Level.coffee b/app/models/Level.coffee index 9214556df..9a967f7a4 100644 --- a/app/models/Level.coffee +++ b/app/models/Level.coffee @@ -95,7 +95,7 @@ module.exports = class Level extends CocoModel #console.log 'sorted systems adding', systemModel.name sorted.push {model: systemModel, config: _.cloneDeep system.config} originalsSeen[system.original] = true - visit system for system in levelSystems + visit system for system in levelSystems ? [] sorted sortThangComponents: (thangs, levelComponents, parentType) -> @@ -106,7 +106,7 @@ module.exports = class Level extends CocoModel # Decision? Just special case the sort logic in here until we have more examples than these two and decide how best to handle most of the cases then, since we don't really know the whole of the problem yet. # TODO: anything that depends on Programmable will break right now. - for thang in thangs + for thang in thangs ? [] sorted = [] visit = (c) -> return if c in sorted @@ -137,7 +137,7 @@ module.exports = class Level extends CocoModel # TODO DEFAULTS fillInDefaultComponentConfiguration: (thangs, levelComponents) -> - for thang in thangs + for thang in thangs ? [] for component in thang.components or [] continue unless lc = _.find levelComponents, {original: component.original} component.config ?= {} diff --git a/app/schemas/models/level.coffee b/app/schemas/models/level.coffee index ae05899c2..f1bfb29a5 100644 --- a/app/schemas/models/level.coffee +++ b/app/schemas/models/level.coffee @@ -207,7 +207,7 @@ GeneralArticleSchema = c.object { LevelSchema = c.object { title: 'Level' description: 'A spectacular level which will delight and educate its stalwart players with the sorcery of coding.' - required: ['name', 'description', 'scripts', 'thangs', 'documentation'] + required: ['name'] 'default': name: 'Ineffable Wizardry' description: 'This level is indescribably flarmy.' diff --git a/app/schemas/models/level_component.coffee b/app/schemas/models/level_component.coffee index fdef02787..9907210a6 100644 --- a/app/schemas/models/level_component.coffee +++ b/app/schemas/models/level_component.coffee @@ -103,7 +103,7 @@ LevelComponentSchema = c.object { title: 'Component' description: 'A Component which can affect Thang behavior.' required: ['system', 'name', 'description', 'code', 'dependencies', 'propertyDocumentation', 'codeLanguage'] - 'default': + default: system: 'ai' name: 'AttacksSelf' description: 'This Component makes the Thang attack itself.' diff --git a/app/styles/editor/component/thang-component-config-view.sass b/app/styles/editor/component/thang-component-config-view.sass index e2670469b..ab8da8432 100644 --- a/app/styles/editor/component/thang-component-config-view.sass +++ b/app/styles/editor/component/thang-component-config-view.sass @@ -4,3 +4,6 @@ .treema-root border: 0 padding: 0 5px + + .is-default-component + background-color: lightgray \ No newline at end of file diff --git a/app/styles/editor/component/thang-components-edit-view.sass b/app/styles/editor/component/thang-components-edit-view.sass index 77b57132d..c10c7c23f 100644 --- a/app/styles/editor/component/thang-components-edit-view.sass +++ b/app/styles/editor/component/thang-components-edit-view.sass @@ -29,6 +29,9 @@ bottom: 0 overflow: scroll + .treema-key, .treema-description + display: none + .dependent background-color: rgba(128, 64, 255, 0.10) diff --git a/app/templates/editor/component/thang-component-config-view.jade b/app/templates/editor/component/thang-component-config-view.jade index c1ef8c916..80535c740 100644 --- a/app/templates/editor/component/thang-component-config-view.jade +++ b/app/templates/editor/component/thang-component-config-view.jade @@ -1,5 +1,5 @@ .panel.panel-default - .panel-heading + .panel-heading(class=isDefaultComponent ? "is-default-component" : "") em #{component.system}. strong.panel-title.spr= component.name span#description.text-muted= component.description diff --git a/app/treema-ext.coffee b/app/treema-ext.coffee index 909237d5e..cbdc5e579 100644 --- a/app/treema-ext.coffee +++ b/app/treema-ext.coffee @@ -416,7 +416,7 @@ class LevelComponentReferenceNode extends LatestVersionReferenceNode # supermodels. buildSearchURL: (term) -> "#{@url}?term=#{term}&project=name,system,original,version,dependencies,configSchema,description" modelToString: (model) -> model.get('system') + '.' + model.get('name') - canEdit: -> not @data.original # only allow editing if the row's data hasn't been set yet + canEdit: -> not @getData().original # only allow editing if the row's data hasn't been set yet LatestVersionReferenceNode.prototype.search = _.debounce(LatestVersionReferenceNode.prototype.search, 200) diff --git a/app/views/editor/component/ThangComponentConfigView.coffee b/app/views/editor/component/ThangComponentConfigView.coffee index b27ddb177..eda43b494 100644 --- a/app/views/editor/component/ThangComponentConfigView.coffee +++ b/app/views/editor/component/ThangComponentConfigView.coffee @@ -17,6 +17,7 @@ module.exports = class ThangComponentConfigView extends CocoView super options @component = options.component @config = options.config or {} + @additionalDefaults = options.additionalDefaults @world = options.world @level = options.level @callback = options.callback @@ -25,12 +26,18 @@ module.exports = class ThangComponentConfigView extends CocoView context = super(context) context.component = @component.attributes context.configProperties = [] + context.isDefaultComponent = @isDefaultComponent context afterRender: -> super() @buildTreema() + setIsDefaultComponent: (isDefaultComponent) -> + changed = @isDefaultComponent isnt isDefaultComponent + @isDefaultComponent = isDefaultComponent + @render() if changed + buildTreema: -> thangs = if @level? then @level.get('thangs') else [] thangIDs = _.filter(_.pluck(thangs, 'id')) @@ -39,6 +46,9 @@ module.exports = class ThangComponentConfigView extends CocoView superteams = _.union(teams, superteams) config = $.extend true, {}, @config schema = $.extend true, {}, @component.get('configSchema') + schema.default ?= {} + _.merge schema.default, @additionalDefaults if @additionalDefaults + if @level?.get('type') is 'hero' schema.required = [] treemaOptions = diff --git a/app/views/editor/component/ThangComponentsEditView.coffee b/app/views/editor/component/ThangComponentsEditView.coffee index 9c5678694..02eba88cf 100644 --- a/app/views/editor/component/ThangComponentsEditView.coffee +++ b/app/views/editor/component/ThangComponentsEditView.coffee @@ -28,13 +28,18 @@ module.exports = class ThangComponentsEditView extends CocoView @originalsLoaded = {} @components = options.components or [] @components = $.extend true, [], @components # just to be sure + @setThangType options.thangType @lastComponentLength = @components.length @world = options.world @level = options.level @loadComponents(@components) # Need to grab the ThangTypes so that we can autocomplete items in inventory based on them. @itemThangTypes = @supermodel.loadCollection(new ItemThangTypeSearchCollection(), 'thangs').model - + + setThangType: (@thangType) -> + return unless componentRefs = @thangType?.get('components') + @loadComponents(componentRefs) + loadComponents: (components) -> for componentRef in components # just to handle if ever somehow the same component is loaded twice, through bad data and alike @@ -59,26 +64,20 @@ module.exports = class ThangComponentsEditView extends CocoView @addThangComponentConfigViews() buildComponentsTreema: -> + components = _.zipObject((c.original for c in @components), @components) + defaultValue = undefined + if thangTypeComponents = @thangType?.get('components', true) + defaultValue = _.zipObject((c.original for c in thangTypeComponents), thangTypeComponents) + treemaOptions = supermodel: @supermodel - schema: Level.schema.properties.thangs.items.properties.components - data: $.extend true, [], @components + schema: { + type: 'object' + default: defaultValue + additionalProperties: Level.schema.properties.thangs.items.properties.components.items + }, + data: $.extend true, {}, components callbacks: {select: @onSelectComponent, change: @onComponentsTreemaChanged} - noSortable: true - nodeClasses: - 'thang-components-array': ThangComponentsArrayNode - 'point2d': nodes.WorldPointNode - 'viewport': nodes.WorldViewportNode - 'bounds': nodes.WorldBoundsNode - 'radians': nodes.RadiansNode - 'team': nodes.TeamNode - 'superteam': nodes.SuperteamNode - 'meters': nodes.MetersNode - 'kilograms': nodes.KilogramsNode - 'seconds': nodes.SecondsNode - 'speed': nodes.SpeedNode - 'acceleration': nodes.AccelerationNode - 'item-thang-type': nodes.ItemThangTypeNode @componentsTreema = @$el.find('#thang-components-column .treema').treema treemaOptions @componentsTreema.build() @@ -91,7 +90,7 @@ module.exports = class ThangComponentsEditView extends CocoView componentMap[component.original] = component newComponentsList = [] - for component in @componentsTreema.data + for component in _.values(@componentsTreema.data) newComponentsList.push(componentMap[component.original] or component) @components = newComponentsList @@ -204,12 +203,26 @@ module.exports = class ThangComponentsEditView extends CocoView # Put back config views into the DOM based on the component list ordering, # adding and registering new ones as needed. configsEl = @$el.find('#thang-component-configs') - for componentRef in @componentsTreema.data + + componentRefs = _.merge {}, @componentsTreema.data + if thangTypeComponents = @thangType?.get('components') + thangComponentRefs = _.zipObject((c.original for c in thangTypeComponents), thangTypeComponents) + for thangTypeComponent in thangTypeComponents + if componentRef = componentRefs[thangTypeComponent.original] + componentRef.additionalDefaults = thangTypeComponent.config + else + modifiedRef = _.merge {}, thangTypeComponent + modifiedRef.additionalDefaults = modifiedRef.config + delete modifiedRef.additionalDefaults + componentRefs[thangTypeComponent.original] = modifiedRef + + for componentRef in _.values(componentRefs) subview = componentConfigViews[componentRef.original] if not subview subview = @makeThangComponentConfigView(componentRef) continue unless subview @registerSubView(subview) + subview.setIsDefaultComponent(not @componentsTreema.data[componentRef.original]) configsEl.append(subview.$el) makeThangComponentConfigView: (thangComponent) -> @@ -222,15 +235,29 @@ module.exports = class ThangComponentsEditView extends CocoView world: @world config: config component: component + additionalDefaults: thangComponent.additionalDefaults }) configView.render() @listenTo configView, 'changed', @onConfigChanged configView onConfigChanged: (e) -> + foundComponent = false for thangComponent in @components if thangComponent.original is e.component.get('original') thangComponent.config = e.config + foundComponent = true + break + + if not foundComponent + @components.push({ + original: e.component.get('original') + majorVersion: e.component.get('version').major + config: e.config + }) + @onComponentsChanged() + + @updateComponentsList() @reportChanges() onSelectComponent: (e, nodes) => @@ -239,28 +266,28 @@ module.exports = class ThangComponentsEditView extends CocoView # find dependent components dependents = {} - dependents[nodes[0].data.original] = true - componentsToCheck = [nodes[0].data.original] + dependents[nodes[0].getData().original] = true + componentsToCheck = [nodes[0].getData().original] while componentsToCheck.length componentOriginal = componentsToCheck.pop() for otherComponentRef in @components continue if otherComponentRef.original is componentOriginal continue if dependents[otherComponentRef.original] otherComponent = @supermodel.getModelByOriginal(LevelComponent, otherComponentRef.original) - for dependency in otherComponent.get('dependencies') + for dependency in otherComponent.get('dependencies', true) if dependents[dependency.original] dependents[otherComponentRef.original] = true componentsToCheck.push otherComponentRef.original # highlight them for child in _.values(@componentsTreema.childrenTreemas) - if dependents[child.data.original] + if dependents[child.getData().original] child.$el.addClass('dependent') # scroll to the config for subview in _.values(@subviews) continue unless subview instanceof ThangComponentConfigView - if subview.component.get('original') is nodes[0].data.original + if subview.component.get('original') is nodes[0].getData().original subview.$el[0].scrollIntoView() break diff --git a/app/views/editor/level/settings/SettingsTabView.coffee b/app/views/editor/level/settings/SettingsTabView.coffee index cf2c57196..04fd12b16 100644 --- a/app/views/editor/level/settings/SettingsTabView.coffee +++ b/app/views/editor/level/settings/SettingsTabView.coffee @@ -47,7 +47,7 @@ module.exports = class SettingsTabView extends CocoView @settingsTreema.open() getThangIDs: -> - (t.id for t in @level.get('thangs') when t.id isnt 'Interface') + (t.id for t in @level.get('thangs') ? [] when t.id isnt 'Interface') onSettingsChanged: (e) => $('.level-title').text @settingsTreema.data.name diff --git a/config.coffee b/config.coffee index 26c7687ca..62d05b3d8 100644 --- a/config.coffee +++ b/config.coffee @@ -7,7 +7,7 @@ exports.config = 'public': 'public' conventions: ignored: (path) -> startsWith(sysPath.basename(path), '_') - sourceMaps: false + sourceMaps: true files: javascripts: defaultExtension: 'coffee' diff --git a/test/demo/views/editor/component/ThangComponentsEditView.demo.coffee b/test/demo/views/editor/component/ThangComponentsEditView.demo.coffee index e8be1b896..3d081bb0e 100644 --- a/test/demo/views/editor/component/ThangComponentsEditView.demo.coffee +++ b/test/demo/views/editor/component/ThangComponentsEditView.demo.coffee @@ -1,4 +1,5 @@ ThangComponentEditView = require('views/editor/component/ThangComponentsEditView') +ThangType = require 'models/ThangType' responses = '/db/level.component/A/version/0': { @@ -6,8 +7,13 @@ responses = original: 'A' version: { major: 0, minor: 0 } name: 'A' - configSchema: { type: 'object', properties: { propA: { type: 'number' }, propB: { type: 'string' }} } - + configSchema: { + type: 'object' + properties: { + propA: { type: 'number' } + propB: { type: 'string' } + } + } } '/db/level.component/B/version/0': { system: 'System' @@ -22,6 +28,16 @@ responses = version: { major: 0, minor: 0 } name: 'C (depends on B)' dependencies: [{original:'B', majorVersion: 0}] + configSchema: { + type: 'object' + default: { propC: 'Default property from component config' } + } + } + '/db/level.component/D/version/0': { + system: 'System' + original: 'D' + version: { major: 0, minor: 0 } + name: 'D (comes from ThangType components)' } '/db/thang.type': [] @@ -32,6 +48,12 @@ module.exports = -> { original: 'B', majorVersion: 0 } { original: 'C', majorVersion: 0 } ] + thangType: new ThangType({ + components: [ + { original: 'C', majorVersion: 0, config: {propD: 'Default property from thang type component.'} } + { original: 'D', majorVersion: 0 } + ] + }) }) view.render()