mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-27 09:35:39 -05:00
Bunch of fixes to get the level editor working again.
This commit is contained in:
parent
d392994a83
commit
1406a970ea
13 changed files with 102 additions and 37 deletions
|
@ -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
|
||||
|
|
|
@ -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 ?= {}
|
||||
|
|
|
@ -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.'
|
||||
|
|
|
@ -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.'
|
||||
|
|
|
@ -4,3 +4,6 @@
|
|||
.treema-root
|
||||
border: 0
|
||||
padding: 0 5px
|
||||
|
||||
.is-default-component
|
||||
background-color: lightgray
|
|
@ -29,6 +29,9 @@
|
|||
bottom: 0
|
||||
overflow: scroll
|
||||
|
||||
.treema-key, .treema-description
|
||||
display: none
|
||||
|
||||
.dependent
|
||||
background-color: rgba(128, 64, 255, 0.10)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -7,7 +7,7 @@ exports.config =
|
|||
'public': 'public'
|
||||
conventions:
|
||||
ignored: (path) -> startsWith(sysPath.basename(path), '_')
|
||||
sourceMaps: false
|
||||
sourceMaps: true
|
||||
files:
|
||||
javascripts:
|
||||
defaultExtension: '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()
|
||||
|
|
Loading…
Reference in a new issue