Deprecated the following and replaced with a new method. This is so that an Object arg
can be passed into sortFunc
.
Deprecated: extend public MhEngineEntry[] sortedChildren(MhEngine engine, function(MhEngineEntry, MhEngineEntry, Object):int sortFunc) : deprecated { New: extend public MhEngineEntry[] sortedChildren(MhEngine engine, function(MhEngineEntry, MhEngineEntry, Object):int sortFunc, Object arg=null) {
Now MhEngineConstructionEntry
has a field assortmentClassification
, determining which assortment this entry comes from and belongs to.
Added: public LayerSet assortmentClassification : copy=reference; Added: extend public LayerSet assortmentClassification() { Added: extend public LayerSet assortmentClassification=(LayerSet a) {
Thus, exporting entry now at MhRowExportFunction
will check for the entry assortmentClassification
, to get the correct spawner selector and assortment.
Old: s = entry.spawnSnapper(engine.MhEngine, getSpawnerSelector()); New: LayerSet assortClassi = entry.assortmentClassification; if (assortClassi) s = entry.spawnSnapper(engine.MhEngine, assortment.spawnerSelector(assortClassi)); else s = entry.spawnSnapper(engine.MhEngine, configuration.spawnerSelector);
Add assortmentClassification
as an argument on the constructors.
Old: public constructor(box b, Transform t, LayerSet classification=null) : deprecated { Old: public constructor(box b, LayerSet classification) : deprecated { New: public constructor(box b, Transform t, LayerSet classification=null, LayerSet assortClassification=null) { New: public constructor(box b, LayerSet classification, LayerSet assortClassification=null) {
Therefore, all MhEngineConstructionEntry
instantiations now pass in the assortment's classification as an argument.
- Deprecated: public <double, int, double> mhCalculatedBayHeight(MhSystemConfigurationItem this, MhSnapper bay, int stepCount, bool loadWithinLimit=false, SnapperFilter filter=mhBayChildrenFilter, double maxBayHeight=maxDouble, bool xtrace=false) { double maxBayHeight=maxDouble, bool xtrace=false) : deprecated {
This function is no longer needed. It has grown so huge, and very patchy. All instances that call this function should be replaced.
Old: return mhCalculatedBayHeight(bay, stepCount=stepCount, loadWithinLimit=loadWithinBayLimit(), maxBayHeight=maxBayHeight, xtrace=xtrace); new: double h = mhCalculatedBayHeight(bay, stepCount, loadWithinLimit=loadWithinBayLimit()); return <h, stepCount, 0d>;
Instead of using the mhCalculatedBayHeight()
to calculate new bay height at the function calculatedBayHeight()
, we replace it with a similar method, mhCalculatedBayHeight(MhSystemConfigurationItem this, MhSnapper bay, int stepCount, bool loadWithinLimit=false)
, which uses bruteforce to calculate bay height.
Old: max = mhCalculatedBayHeight(getBay(), max, maxBayHeight=maxBayH).v1; New: max = mhCalculatedMaxLevelCount(bay);
Instead of using mhCalculatedBayHeight()
to calculate number of levels domain at the function numLevelsDomain()
, we use mhCalculatedMaxLevelCount()
.
Deprecated the following and replaced with a new method. The deprecated method would loop through and gather all Snappers
in mainWorld that use a unit load. This was too broad for the intention of the method and would gather significantly more snappers than required. The new method will gather all Snappers
in mainWorld that use one of the unit load objects passed in as an argument.
Deprecated: extend public CoreObject{} getAffectedObjects() : deprecated { New: extend public CoreObject{} getAffectedObjects(UnitLoad[] unitLoads) {
Similarly, we have deprecated and replaced the following method as well for the same reason.
Deprecated: extend public bool hasLoad(CoreObject obj) : deprecated { New: extend public bool usesLoad(CoreObject obj, UnitLoad[] unitLoads) {
The method applyAllCallback(UnitLoad[] applyUnitLoads)
has been updated to use the new method getAffectedObjects(UnitLoad[] unitLoads)
so if you have overridden it, check if you need to update your method call as well.
Added additional PropDefs
to MhEngine
during developMode
when getting MhEngine
using MhEngine mhEngine(Space space, bool createIfNone=true, class MhSystemEngineEnvironment environment=null)
for engine visualiser functionality. Additional PropDefs
include:
spaceKey
representing space id stringplugIn
representing a flag if the engine originates from a regular space or a MhDebugPlugInFunctionSpace
plug in function space/** * MH Engine. */ public MhEngine mhEngine(Space space, bool createIfNone=true, class MhSystemEngineEnvironment environment=null) { ... if (developMode) { engine."spaceKey" = space.id; engine."plugIn" = space in MhDebugPlugInFunctionSpace; } ... }
Modified Object exec(CxEngine engine, str key, str->Object args)
to run the engine plug in function replacement process during developMode when the engine visualiser alternate plug in space is enabled and engine is from the plug in function space.
/** * Library of functions for an CxEngine. */ public class MhEngineFunctionLibrary extends CxFunctionLibrary { Old: /** * Run. */ public Object exec(CxEngine engine, str key, str->Object args) { ... if (developMode) appendToRecentRunned(MhEngineFunctionRun(key, args), fun); if (dbg_engineVisualisationEnabled()) engineVisualiserBeforeRun(key, args, fun); Object res = fun.exec(args); if (dbg_engineVisualisationEnabled()) engineVisualiserAfterRun(key, args, fun); return res; ... } New: /** * Run. */ public Object exec(CxEngine engine, str key, str->Object args) { ... if (developMode and dbg_engineVisualisationEnabled) { return dbg_engineVisualisationExecFunction(this, fun, args); } if (developMode) appendToRecentRunned(MhEngineFunctionRun(key, args), fun); return fun.exec(args); } ... }
Modified Object setPropertyValue(str key, Object value, CoreProperty property, CoreProperties properties, Object env=null)
to pipe changes from the main space to the plug in function space when the engine visualiser alternate plug in space is enabled.
/** * Mh snapper shape. */ public class MhSnapperShape extends CorePropObj { /** * Set property value. */ public Object setPropertyValue(str key, Object value, CoreProperty property, CoreProperties properties, Object env=null) { if (dbg_engineVisualisationDebugSpaceEnabled and value and !value.equal(get(key, env))) { mhDebugPlugInFunctionSpaceManager.pipeSetPropertyValue(owner, key, value, property, properties, env); } return super(..); } }
We now use a #engine symbol as a new fetch reason for collection of collision primitives with MhCollisionFetchEnv. This symbol is used specifically in MhSnapper.setEngineEntryCollisionPrimitive(MhEngineEntry entry)
where we collect collision primitives and assign it to an engine entry.
Check for this new fetch reason when appending collision primitives that are meant only for use with engine functions.
/** * Abstract industry (generation 2) snapper base class. */ public class MhSnapper extends Snapper { Old: /** * Update engine entry collision primitive. */ extend public void setEngineEntryCollisionPrimitive(MhEngineEntry entry) { if (entry as MhEngineCollisionEntry) { MhCollisionFetchEnv env(); CollisionPrimitive prim = localCollisionPrimitive(env); CollisionPrimitiveSet set(null, null); set.subPrims <<? prim; entry.setPrim(set); } } New: /** * Update engine entry collision primitive. */ extend public void setEngineEntryCollisionPrimitive(MhEngineEntry entry) { if (entry as MhEngineCollisionEntry) { MhCollisionFetchEnv env(#engine); CollisionPrimitive prim = localCollisionPrimitive(env); CollisionPrimitiveSet set(null, null); set.subPrims <<? prim; entry.setPrim(set); } }
MhLevelArrangeFunction2.arrangeLevelsSteps(MhPopulator populator, MhEngineEntry[] processedEntries)
has been updated so that when there is a collision, instead of just moving the next level above, it will now move all subsequent levels above.
/** * Level Arrange engine (ensure clearance between levels). */ public class MhLevelArrangeFunction2 extends MhSystemEngineFunction { Old: /** * Arrange levels by stepping through populator. */ extend public void arrangeLevelsSteps(MhPopulator populator, MhEngineEntry[] processedEntries) { ... if (!ar and more and MhEngineEntry next = processedEntries[i + 1]) { if (next.pos.z < e.pos.z) next.move(v); } ... } New: /** * Arrange levels by stepping through populator. */ extend public void arrangeLevelsSteps(MhPopulator populator, MhEngineEntry[] processedEntries) { ... if (!ar and more and v.z > 0) { int nextIdx = i; while (processedEntries.count > ++nextIdx and (MhEngineEntry next = processedEntries[nextIdx]) and (MhEngineEntry prev = processedEntries[nextIdx - 1])) { if (next.pos.z < prev.pos.z) { next.move(v); } } } ... }
Important to note: You do not have to make any changes for 15.5 Minor, but they will be required in 16.0 Major. The individual interface changes will also be included in the 16.0 Major migration guide.
See Unit Load Editor Redesign
in the New Features page to learn about how to switch to the new design for your extension. This redesign is opt-in and the dialog will still default to the old design.
As a general rule of thumb, you can search for useV2
in order to find the new code and the old code for each of those methods, where the old code will be in the else block. You can also search for FIXME 16.0 remove
to identify all methods that are used for the old design and will be removed.
The following fields and methods in UnitLoadDialog
are only used for the old design and will be removed in 16.0 Major. Copy them over to your custom class if you wish to maintain the old design in 16.0 Major.
public class UnitLoadDialog extends DialogWindow { // Fields. public TreeView userRegisteredTree; public DropDownTreeView systemRegisteredTree; // Methods. extend public SubWindow buildAddTemplateWin(Window parent) { extend public void buildUserUnitLoadWin(Window sub, Window templateInsert) { extend public void buildApplyButtons() { extend public pointI paneMargin() { extend public void updateUnitLoadSelectorWin() { extend public void updatePreviewWin() { extend public void updatePropsWin() { extend public void updatePanes() { extend public void addSelectedTemplateToUserRegistry(bool refresh) { extend public str propsLabel(UnitLoad unitLoad) { extend public TreeViewItem getSelectedSystemUnitLoad() { }
The following fields and methods in UnitLoadDialog
have been introduced for the new design. Extend these methods in your custom class if you wish to adopt the new design.
public class UnitLoadDialog extends DialogWindow { // Fields. public Window mainSub; public UnitLoadDropDownTreeView registeredUnitLoadTV; public Window buttonSub; public bool useV2; // Will be removed! // Methods. public constructor(bool useV2, Window parent=null, pointI pos=(-1, -1)) { // Will be removed! extend public void buildMenuBar() { extend public void buildMenuBarSubMenus() { extend public void buildMenuBarFileMenu() { extend public void buildMenuBarEditMenu() { extend public void appendMenuBarFileItems() { extend public void appendMenuBarEditItems() { extend public void toggleMenuBarItems() { extend public void buildMainSub() { extend public void buildUnitLoadSelectorWin2() { // Will be renamed to buildUnitLoadSelectorWin extend public void fillInRegisteredUnitLoadTV() { extend public void updateUnitLoadTreeView() { extend public void buildPropertiesWin2() { // Will be renamed to buildPropertiesWin extend public void buildPreviewWin2() { // Will be renamed to buildPreviewWin extend public void buildButtonsSub() { extend public sizeI defaultSize() { extend public void handleEvent(str event) { extend public bool allowModifyUnitLoad() { extend public bool allowRemoveUnitLoad() { extend public void toggleSaveApplyButtons() { extend public bool allowSaveCurrentUnitLoad() { extend public bool allowSaveAllUnitLoads() { extend public bool allowSelectApplyUnitLoad() { extend public void addSelectedTemplateToUserRegistry(UnitLoad ul, UnitLoadGroup grp) { extend public void openTemplateSelectorDialog() { extend public void openRenamePopup() { extend public void renameUnitLoadItem(UnitLoadTreeViewItem2 item, str newName) { extend public void duplicateUnitLoad() { extend public void removeUnitLoad() { extend public int promptUserRemoveUnitLoad() { extend public UnitLoadTreeViewItem2 getSelectedUnitLoadTVI() { }
The following methods in UnitLoadDialog
will remain but have been modified to have different behaviors for the old and new design. If you wish to maintain the old design, override these methods and copy over the old code in the else blocks of the if (useV2)
check.
public class UnitLoadDialog extends DialogWindow { extend public void build() { extend public void unitLoadSelectionChanged() { public void rebuild() { extend public void populatePropsWindow(UnitLoad mtbh) { extend public void removeProps() { extend public void createPropsUI(UnitLoad mtbh) { extend public void animApplyCallback() { extend public void applyAllCallback(UnitLoad[] applyUnitLoads) { extend public void afterPropertyChanged(CoreProperty property, Object oldValue) { extend public void clearModifiedUnitLoads(str->UnitLoad newLoads=null) { extend public UnitLoad getSelectedUserUnitLoad(bool actual=false) { extend public bool selectUserUnitLoad(UnitLoad mtbh) { extend public void validateUserUnitLoadsInUse() { }
Some other details to be mentioned:
registeredUnitLoadTV
instead for the list of unit loads in the drawing.public class UnitLoadDialog extends DialogWindow { Old: public TreeView userRegisteredTree; // To be removed in 16.0 major. New: public UnitLoadDropDownTreeView registeredUnitLoadTV }
systemRegisteredTree
is not used in the new design and has been replaced with a new dialog UnitLoadTemplateSelectorDialog
.public class UnitLoadDialog extends DialogWindow { Old: public DropDownTreeView systemRegisteredTree; // To be removed in 16.0 major. New: /** * Open unit load template selector dialog. */ extend public void openTemplateSelectorDialog() { UnitLoadTemplateSelectorDialog(this); } Old: extend public void addSelectedTemplateToUserRegistry(bool refresh) { // To be removed in 16.0 major. New: extend public void addSelectedTemplateToUserRegistry(UnitLoad ul, UnitLoadGroup grp) { }
UnitLoadTreeViewItem
into UnitLoadDialog
for the new design. If you have extended UnitLoadTreeViewItem
and modified these features, considering extending these methods in your UnitLoadDialog
class.public class UnitLoadDialog extends DialogWindow { // Methods. extend public bool allowModifyUnitLoad() { extend public bool allowRemoveUnitLoad() { extend public void openRenamePopup() { extend public void renameUnitLoadItem(UnitLoadTreeViewItem2 item, str newName) { extend public void duplicateUnitLoad() { extend public void removeUnitLoad() { extend public int promptUserRemoveUnitLoad() { }
Due to this, in 16.0 Major we will be removing the following fields and methods in UnitLoadTreeViewItem
. It will basically be replaced by UnitLoadTreeViewItem2
(which will take its class name).
public class UnitLoadTreeViewItem extends TreeViewItem : inherit constructors { // Fields. public rectI editButtonRect; public rectI cpyButtonRect; public rectI rmButtonRect; public byte over = 0; // Methods. extend public void drawColoredRect(PixelDevice c, rectI r, rectI clipRect, treeViewItemState state, treeViewSelectionStyle style) { extend public void drawMainArrow(PixelDevice d, rectI r, rectI clipRect) { extend public rectI drawBtn(str btnK, Image img, PixelDevice d, rectI r, rectI clipRect) { extend public rectI drawBtn(str btnK, Image img, PixelDevice d, rectI r, rectI clipRect, bool disable) { extend public pointI getBtnPos(str btnK, Image img, rectI r) { extend public Brush backgroundBrush(treeViewItemState state) { extend public bool showSelectedAsWhite(treeViewItemState state, treeViewSelectionStyle style) { extend public ScrollBar vScrollBar(bool ifVisible=false) { extend public void updateApplyButtons(TreeView tv) { extend public void openEditNamePopup(TreeView tv) { extend public void editName(str newName, TreeView tv) { extend public void copyUnitLoadDown(TreeView tv) { extend public void removeUnitLoad(TreeView tv) { extend public void updateTreeView(TreeView tv) { extend public bool isMainSelection() { extend public bool isMultiSelect() {
A new feature has been added that enables users to add extra categories to snappers during insert. In code the feature is called AutoCategorization
. In general, the new functionality should work out of the box for all animations that inherit either InsertAnimation or InsertAnimationG2. Other insert animations may need some adjustments to fully support it.
There are two parts to the feature. One is that all snappers inserted when the feature is enabled should append the categories specified by the user. And secondly, while an insert animation is active there is an information toolbar in the active view showing a preview of all categories that the snapper will receive when inserted.
In order to support the adding of extra categories your animation needs to do one of the following:
Space::undoableInsert(Snapper z, bool putInBsp=true)
if (isAutoCategorizationEnabled()) applyAutoCategories(snapper);
when inserting snappers.To support the information toolbar showing what categories are about to be added to the snapper your animation is required to:
public bool supportsAutoCategorization()
. This will ensure that the toolbar gets displayed during the animation.private SnapperSelection getAnimationSelection(Animation a) {
in cm/core/visibility/categorize/contextualCategoryInfoToolbar.cm
for all the all the ways this can be achieved. The toolbar will still work without returning a valid selection, but a selection is required in order to correctly display what categories will be applied by the snapper and the view mode.Here is a minimal code example of a custom insert animation that supports auto categorization
/** * My custom insert animation. */ public class MyCustomInsertAnimation extends Animation { /** * Supports auto categorization. */ public bool supportsAutoCategorization() { return true; } /** * Return all the snappers in this animation. */ public AnimationSelection getSelection() { return AnimationSelection(snappersToInsert); } /** * End. */ public PropObj end() { super(); // Insert snappers... // Append auto categories to inserted snappers if (isAutoCategorizationEnabled()) { applyAutoCategories(insertedSnappers); } } }