IFC import only allows selecting 1 floor for import now when using the Kitchen & Bath edition. Also no floor is initially selected on import. Other editions (CI, MH) still allow importing multifloors for IFC (all floors selected by default).
In 16.5 Major we introduced MhSnapper.hasRealConfig() to determine if a snapper should own a non-temporary MhConfigRef and is treated as a "config owner" (see 16.5 Major migration guide "Changes to spread tools and dimension propagation"). In 17.0 Major you can now override the logic of this method through the MhConfigBehavior behavior.
public class MhSnapper extends Snapper { Old: /** * Check whether this snapper has config that is not temp. */ extend public bool hasRealConfig() { if (config) return !config.temp; return false; } New: /** * Check whether this snapper has config that is not temp. */ extend public bool hasRealConfig() { if (MhConfigBehavior b = configBehavior()) return b.hasRealConfig(this); return false; } } public class MhConfigBehavior extends MhBehavior { New: /** * Return true if this snapper hold a valid config. */ extend public bool hasRealConfig(MhSnapper a) { if (MhConfigRef config = a.config) return !config.temp; return false; } }
Previously the preconfigurator is built mainly to support having the same compartment throughout the entire system. We are now adding additional support to have different compartments within a single bay for the preconfigurator.
To use this new workflow, add the classes MhCompartmentOverviewConfigurationItem and MhCompartmentTypeConfigurationItem to your configuration. They do not work with MhCompartmentConfigurationItem.
Each level/compartment is represent by a MhCompartmentType object in the MhCompartmentOverviewConfigurationItem class. Unique MhCompartmentType objects can be created in the MhCompartmentTypeConfigurationItem class.


Interfaces to override:
public class MhStorageConfiguration extends MhSystemConfiguration { extend public str->Object compartmentCreationProps(Class compPropClass) { } public class MhCompartmentTypeConfigurationItem extends MhStorageConfigurationItem { extend public MhCompartmentType createCompartmentType() { extend public str defaultCompartmentTypeName() { } public class MhCompartmentType extends CorePropObj { extend public SubSet compartmentPropsClassDomain() { } }
How the snappers get generated is MhStorageConfiguration has a method MhEngineConstructionEntryInfo[] levelCreationInfos() that returns a sequence of infos that each represent a level. This method is used in MhBaySpawner.entryLayout(MhEntryLayoutEnv env) to generate level entries based on those info objects.
public class MhStorageConfiguration extends MhSystemConfiguration { extend public MhEngineConstructionEntryInfo[] levelCreationInfos() { } public class MhBaySpawner extends MhStorageSpawner { public MhEntryLayout entryLayout(MhEntryLayoutEnv env) { ... MhEngineConstructionEntryInfo[] levelCreationInfos; if (?MhStorageConfiguration config = env.configuration) { levelCreationInfos = config.levelCreationInfos(); } ... } }
The engine visualiser now has a new button that will allow you to do one of three actions. You can open the function class in your editor, open the function call location in your editor, or inspect the function object.

AOElecNodecm.abstract.office now exposes a small reusable node type for node-based electrical routing.
This is the office-side abstraction that the new custom.fika electrical system builds on.
Added: public const symbol cAOElecPathPurpose = #path; Added: public const symbol cAOElecJumperPurpose = #jumper; Added: public const symbol cAOElecInternalPurpose = #internal; Added: public class AOElecNode extends AStarNode
AOElecNode gives implementations a shared node owner/key/position/rotation model while leaving neighbor lookup, path shaping, and routing rules to package-specific subclasses such as custom.fika.office.FOElecNode.
cm.abstract.part now registers two public hooks to support the new 17.0 Ind. Tag system in Calculations and when loading older drawings.
Added: public void indTagAdjustmentHook(PartRowAdjustmentDialog dialog, PartColumnAdjustment adjustment) Added: public Part[] fixCET17Adjustments(Part[] list)
ProdPart import environmentscm.abstract.part.import is a new package in CET 17.0. It adds ProdPart-specific importer environments on top of the shared framework in cm.core.part.import.
Added: public class ProdPartSIFImporterEnv Added: public class ProdPartPMXImporterEnv Added: public class ProdPartOFDAImporterEnv
PMXExporter still lives in cm.abstract.pmx, but in 17.0 it now writes the richer PMX header/project payload exposed from the new shared PMX core layer.
Added effective export usage: public class NotesTable Added effective export usage: public class OrderInformation Added effective export usage: public class ShipToInformation Added effective export usage: public class SoldToInformation
The exporter now initializes those records from ProjectInfo and inserts them through Database before item rows are written.
To support the representation of stacking loads on palletized unit loads, a new class named UnitLoadStackedPallet will be introduced. This class will serve as the new base class for pallet-related functionality. Consequently, all existing pallet classes will be refactored to inherit from UnitLoadStackedPallet instead of their current parent class. This enhancement ensures a consistent and extensible model for managing stack patterns and load behaviors on pallets. This currently only available for certain CET edition.
Old: public class MhCustomPallet extends UnitLoadPallet New: public class MhCustomPallet extends UnitLoadStackedPallet Old: public class MhSysPallet extends UnitLoadPallet : abstract New: public class MhSysPallet extends UnitLoadStackedPallet : abstract
cm.core.invalidListCB() has been added as a public helper for opening the drawing validation dialog from shared UI or package code.
Added: public void invalidListCB()
This is a the same class as the TexturePattern class found in custom.cdMH.textureCreator. It intended that this class should be used in stead of the TexturePattern class or any of the othere classes that have reimplemeted the TexturePattern class.
To migrate to this class just changing thing the your class inheritance from TexturePattern to HoleTexturePattern should be enough.
For classes that have reimplemeted TexturePattern having that class inherit HoleTexturePattern and doing some minor refacturing so it only extend the shape method should in most case be enough.
CET 17.0 adds a shared settings API in cm.core.part.partSettings.cm for the new Ind. Tag reset modes exposed from Calculations.
Added: public const str cIndTagPNOnlyKey = "indTagPNOnly"; Added: public const str cLegacyIndTagsKey = "legacyIndTags"; Added: public const str cIndTagsPNOptsKey = "indTagsPNOpts"; Added: public bool indTagsPNOnly() {} Added: public bool indTagsIncludeOptions() {} Added: public void setIndTagsPNOnly(bool value) {} Added: public void setIndTagsIncOpts(bool value) {} Added: public void setIndTagResetbehavior(str keyToMoveTo, World world=null) {} Added: public void convertItemTagInfo(World world) {}
Added: final public ItemTagInfo getUserItemTagInfo() {} Added: extend public bool isUsrModItemTagInfo(ItemTagInfo info=null) {} Added: extend public str itemTagText() {} Added: public str legacyFinalFlattenableKey(Part part) {} Added: public str legacyPartToOwnerKey(Part part) {}
userTagInfoHolder.cm introduces a snapper-centered store for user-modified ItemTagInfo objects. This is the new location used to preserve and restore explicit Ind. Tag overrides instead of depending on pure key matching against globally cached modifications.
Added: public const str cUserTagInfoHolder = "userTagHolder"; Added: public const str cItemTagInfoDelim = ":::"; Added: public class UserTagInfoHolder Added: public UserTagInfoHolder getUserInfoHolder(PropObj obj) Added: public void putUserTagInfo(PropObj obj, str key, ItemTagInfo info) Added: public void removeUserTagInfo(PropObj obj, str key) Added: public void clearUserTagInfo(PropObj obj, bool remove=false)
cm.core.part.import is a new package in CET 17.0. It introduces a shared importer framework for reading Part data from SIF, PMX, and OFDA XML files.
Added: public class PartImporter Added: public class PartImporterEnv Added: public class PartSIFImporter Added: public class PartPMXImporter Added: public class PartOFDAImporter Added: public class PartSIFImporterEnv Added: public class PartPMXImporterEnv Added: public class PartOFDAImporterEnv Added: public class PMXFilePartSource
CET 17.0 introduces cm.core.pmx as the shared home for PMX database wrappers, PMX data-definition objects, PMX constants, and the underlying .NET bridge helpers that are used by both export and import flows.
The new package also adds first-class support for PMX project header/party records beyond the existing item and option rows.
Added: public class NotesTable Added: public class OrderInformation Added: public class ShipToInformation Added: public class SoldToInformation Added: final public int64 insertNotesInfo(NotesTable in_notesInfo) Added: final public int insertOrderInformation(OrderInformation in_orderInfo) Added: final public int insertShipToInformation(ShipToInformation in_shipToInfo) Added: final public int insertSoldToInformation(SoldToInformation in_soldToInfo)
Performs a feature search for the given search line and arguments and stores the result on the blackboard.
Checks that a feature search result from the blackboard has found the expected feature.
Sets the global graphical snapping, for example to 'all', 'basicPoint', 'custom', or a specific feature. By default, all InstructionTestCases set graphical snapping to 'all', allowing snapping to any type of feature.
custom.fika now includes a concrete 17.0 migrator example for packages with older custom part-special key histories.
Added: public class FikaDsPartSpecialMigrator extends DsPartSpecialMigrator Added/important usage: PartSpecialMigrator "partSpecialMigrator"