Spec Oracle Editor

Jump to: navigation, search



The Spec Oracle Editor is a way to edit Spec Oracles, which are lists of definitions for different types of objects or concepts (for instance, game objects, abilities, loot types, or whatever your game needs). There are some implementations of Spec Oracles that are included with HeroEngine (such as the Fx System, which has a customized Fx Spec Editor), and you can leverage the Spec Oracle system to create your own. Essentially this serves as the foundation of building blocks for your game system editors, and takes care of a lot of the busy work for you.

The Spec Oracle Editor is comprised of two basic controls:


The Spec Selector Control

The Spec Selector Control is accessed via the HotSpot Menu. Click on the "Tools" tab, and then choose the Oracle you wish to edit under the "Spec Oracles" heading. That will launch the Spec Selector Control, with which you can Add, Edit (View), Glom, or Clone the individual Specs. The list can be sorted by Key, Name, or Description, by clicking on the appropriate heading.

The menu for Fx Specs

Alternately, it may be launched using the chat command /heoracle.

/heoracle open <specoraclename> example: /heoracle open _fxspecoracle

The Spec Editor Control

Field Type Control
string _nodePropertyEditorCellTextInputBox
integer _nodePropertyEditorCellNumericInputBox
id _nodePropertyEditorCellNumericInputBox
noderef _nodePropertyEditorCellNumericInputBox
vector3 _nodePropertyEditorCellTextInputBox
scriptref _nodePropertyEditorCellTextInputBox
timeinterval _nodePropertyEditorCellTextInputBox
datetime _nodePropertyEditorCellTextInputBox
list of <scaler> _nodePropertyEditorCellList note: editing existing values only, adding new is not currently supported
lookuplist indexed by <X> of <scalar> _nodePropertyEditorCellTextInputBox note: editing existing values only, adding new is not currently supported
boolean _nodePropertyEditorCellBooleanField
enum <X> _nodePropertyEditorCellEnum
class <X> _nodePropertyEditorCellClass

When the Spec Selector Control initiates editing for a spec , the control calls the method InvokeSpecEditorGUI() on the spec and if not overridden the fundamental parent class for all specs 'baseSpec handles it by invoking the generic editor. Consequently, every spec has the opportunity to override this method to invoke a custom GUI, and example of which would be FX Specs which invoke the highly customized FX Editor.

By default, specs use the generic node property editor control (GUI prototype: _NodePropertyEditorWindow) which knows how to dynamically construct a property grid of controls using the external functions for DOM reflection (i.e. analyzing the class and field definitions of your data object model). Each field is represented by a row control which contains two cells, one for the field name and one for the field value. The behaviors for this control are implemented in the _GUINodePropertyEditorClassMethods script and a number of _GUINodePropertyEditorCell<type> classes.

Many specs eventually have field types that are not handled by default necessitating the creation of custom cell controls to display and edit the field.

Creating Custom Value Cells


The method _getCollectionCellHeight() is often overridden because the custom editor cell requires a complex calculation to determine the necessary space for the control.

method _getCollectionCellHeight() as Float  
  return 20.0

The _setCollectionCellValueFromNodeRefByField() method is called by the node property editor to notify the cell it needs to update its displayed value (typically during initialization). Custom controls must always override this method because only the control knows how to update its structure.

// Sample code is from boolean cell _GUINodePropertyEditorCellBoolean
method _setCollectionCellValueFromNodeRefByField( fieldName as String )
  theNode as NodeRef = me._getNodePropertyEditorEditNode()
  me._GUINodePropertyEditorCellFieldName = fieldName
  dropDownBox as NodeRef of Class _GUIDropDownBox = FindGUIControlByName( me, "dropDownBox" )
  values as List of String = dropDownBox._getDropDownBoxValues()
  if values.length < 2
    // need to init this so add true and false
    add back true to values
    add back false to values
    dropDownBox._populateDropDownBox( values )
  value as Boolean
  var fieldType = GetFieldType( fieldName )
  when tolower( fieldType )
    is "boolean"
      value = theNode.fieldCollection[ fieldName ]
      value = "false"
  dropDownBox._setDropDownBoxValue( value )

The _updateNodeFieldWithCellValue() method is called by the editor to notify the cell that it needs to update the node with the displayed value. Custom controls must always override this method as only the control itself knows how to update the a field (of a particular type) based on the cells structure.

// Sample code is from boolean cell _GUINodePropertyEditorCellBoolean
method _updateNodeFieldWithCellValue()
  dropDownBox as NodeRef of Class _GUIDropDownBox = FindGUIControlByName( me, "dropDownBox" )
  var fieldType = me._getNodePropertyEditorCellLocalFieldType()
  if not me._getNodePropertyEditorCellReadOnly()
    var theNode = me._getNodePropertyEditorEditNode()
    value as Boolean = dropDownBox._getDropDownBoxValue()
    when tolower( fieldType )
      is "boolean"
        b as Boolean = theNode.fieldCollection[ me._GUINodePropertyEditorCellFieldName ]
        if b <> value
          theNode.fieldCollection[ me._GUINodePropertyEditorCellFieldName ] = value

Using a Custom Cell

During the analysis of a spec using DOM Reflection, the generic node property editor provides the classes comprising a node the opportunity to specify alternate editing controls. This is accomplished through a series of shared function calls allowing modification of the default behaviors. A template script (_templateNodePropertyEditorOverrides) is included detailing the shared functions used by the node property editor during its dynamic construction.

To use a custom cell, simply implement the shared function _createNodePropertyEditorCellForField() in the class methods script for the class of which the field is a member.

shared function _createNodePropertyEditorCellForField( fieldName as String ) as NodeRef of Class _GUINodePropertyEditorCell
  editCell as NodeRef of Class _GUINodePropertyEditorCell
  when tolower( fieldName )
    is "<yourFieldName>"
      editCell = CreateNodeFromPrototype( "_NodePropertyEditorCellIDField" )
      editCell.build = true
  return editCell

Replacing the Spec Editor Control

For some types of specs, the generic editor (while extremely extensible) may simply not fit requirements. Replacing the generic editor with a custom one requires you implement the method InvokeSpecEditorGUI() in the spec class(es) used by your spec oracle. The FX Specs use this mechanic to replace the default editor with the highly customized FX Editor.

// This displays the code used by default and is implemented in the baseSpecClassMethods script
method InvokeSpecEditorGUI( parentGUI as ID ) as NodeRef of Class GUIControl
// Invokes the Edit GUI for a particular spec, override this method if you want to invoke a gui other than the generic
//   specOracle property editor
  window as NodeRef of Class GUIControl = CreateNodeFromPrototype("_NodePropertyEditorWindow")
  window.build = true
  glomClass("SpecOraclePropertyEditor", window)
  where window is kindof SpecOraclePropertyEditor
    window.SOPEparentGUI = parentGUI
    window.SOPEtype = me.GetMySpecOracle().getSpecOracleClass()
    window.NPEnode = me
  window._changeWindowTitleText( "Spec Editor - " + getPrimaryClassOnNode( me ) + "(" + me.SpecKey + ")" )
  var editor = FindGUIControlByName(window.getClientarea(), "nodepropertyeditor")
  return editor

See also

Personal tools