Table of Contents

Breaking changes

In the order they will bite an upgrading host.

1. Registration, before anything else

XFactory.Generators changes from a plain Dictionary to a ConcurrentDictionary, so parallel Reg() calls no longer corrupt the registration map. The property is public, so a caller that declares its type explicitly stops compiling.

Carried over from 3.1.172 and still the first thing an upgrading host hits: Reg must be called once at startup, before any project XML is deserialized. Registration no longer happens by accident when a type is first touched. See XML IO.

2. The message channel

Message reporting is rebuilt on a unified model. Every notification carries a Severity, a Category and a filterable id (SimpleMessage), and arrives on one of three typed sinks: ShellProgress for session-lifecycle messages, StepDiagnosticProgress for step-anchored diagnostics, and NcDiagnosticProgress for NC-parsing diagnostics.

MixedProgress0, MultiTagMessage and MultiTagMessageUtil are removed. Every message parameter across the API — the XFactory deserialization chain included — is retyped from IProgress<object> to IProgress<IMessage>. Category.General is deleted, MessageUtil becomes id-first {Category}{Severity}, and NcDiagnostic.Text renames to Notification. See Message Management.

3. The session surface

LocalProjectService.SessionShell is created by BeginSession() and nulled at EndSession() — it is null outside a session and no longer lazily created. ShellProgress is recreated per session, so hold no long-lived reference to either: subscribe once through OnShellMessageAdded / OnShellMessageCleared, or buffer one call's messages with MessageCollector.

MachiningSession takes an injected IMachiningService host in its constructor, and IMachiningService replaces PlayerCancellationToken / PausePlayer with a single PacePlayer property.

4. The play verbs

Nc becomes the umbrella term for any playable control program, and BrandNc names the famous-brand controller-code group as a sibling of Cl and Csv.

Was Is now
PlayNcFile(file) — brand G-code only PlayNcFile(file, NcKind kind = NcKind.Auto)
RunNcFile(file) RunNcFile(file, NcKind kind = NcKind.Auto)
the narrow brand-only file verbs PlayBrandNcFile / RunBrandNcFile
IControlRunner Hi.Numerical.INcRunner
RunControlLines RunNcLines
ControlKind NcKind
IsRunningControlLines / BeginControlRunner IsRunningNcLines / BeginNcRunner
the interim PlayControlFile / RunControlFile mirrors removed

The same rename applies on LocalProjectService, SessionShellController and MachiningSession. Only .cl / .cls / .clsf / .csv arguments change meaning — DetectByPath treats those as closed extension sets and everything else falls back to brand G-code, so an exotic brand extension can never be misrouted.

5. Renames with no shim

Was Is now
WorkpieceService.GetRuntimeGeom / ReadRuntimeGeom / WriteRuntimeGeom / SetRuntimeGeom / ResetRuntimeGeom / IsRuntimeGeomInit / ScanRuntimeGeomInfDefect GetOrBuildMeshedGeom / ReadMeshedGeom / WriteMeshedGeom / SetMeshedGeom / ResetMeshedGeom / IsMeshedGeomInit / ScanMeshedGeomInfDefect
MachiningEquipmentCollisionIndex.WorkpieceRuntimeGeomGetter WorkpieceMeshedGeomGetter
IContourTray / UniformContourTray / FreeContourTray IFluting / UniformFluting / FreeFluting
MillingCutter.FluteContourTray Fluting
Hi.Common.ResourceUtil (the HiNc one) ResourceLayout
NativeTopoStld / NativeTopoStlfr / NativeCarveTopoStl3wfr NativeTopoStl3d / NativeTopoStl3wfr / CarveStl
Solid.NativeSmoothTopoStl / Sweptable.NativeTopoStl SmoothTopoStl3d / NativeTopoStl3d
ITimeGetter and its Time member Hi.Physics.ITimecoded and Timecode
ClStrip.DrawingRefreshing ClStrip.DrawingRefreshed
CbtrPickable.CleanLinked* CbtrPickable.CleanAttached*
SoftNcRunner.NcDependencyList PipelineNcDependencyList
StateActRunner.Feedrate_mmds / Feedrate_mmdmin, ActFeedrate.Feedrate_mmds / Feedrate_mmdmin (and ActRapid), MachineMotionStep.Feedrate_mmds, the MachineMotionStep constructor's feedrate_mmds parameter CommandedClFeedrate_mmds / CommandedClFeedrate_mmdmin, CommandedClFeedrate_mmds / CommandedClFeedrate_mmdmin, CommandedClFeedrate_mmds, commandedClFeedrate_mmds
GetMillingEquipment GetMachiningEquipment
CodeXyzabcMachineTool / CodeXyzabcMachineToolUri GeneralXyzabcMachineTool (the old XML names still load)

Four notes on that table.

The SessionShell script names for meshed geometry keep hidden [Obsolete] aliases so existing player scripts still run; the service-level members do not. WorkpieceService.ResetRuntimeGeom also drops its ClStrip parameter.

ClStrip.DrawingRefreshed was renamed because both invocations always fired after the work — the -ing name told subscribers the opposite of when they are called. A subscriber that misses the rename silently detaches.

Project and cutter files written before the fluting rename keep loading: each Reg() registers the ContourTray-era XName beside the older aliases, and the cutter element reader tries Fluting, then FluteContourTray, then FluteContourTrackTray. A cutter that nevertheless fails to resolve its fluting machines as a plain bounding shape rather than failing loudly, so verify the load rather than assuming it.

The feedrate members were renamed because the value is the controller's commanded feedrate of the CL point – the F word after G94/G95/G93 conversion, or for a rapid the CL path over the act duration – and not the equipped tool's tip feedrate; under RTCP with a tool-length offset that does not describe the equipped tool the two differ. The step now also carries ActualTipFeedrate_mmds (client key ActualTipFeedrate_mmdmin), which the physics reads. The client key Feedrate_mmdmin keeps its historical name.

SoftNcRunner.PipelineNcDependencyList is the raw list; machine-config consumers read the resolved view through GetEffectiveNcDependencyList. Legacy <NcDependencyList> XML still loads and migrates.

6. Removals

  • CSVCsvRunner0, LocalProjectService.EnableSoftCsvRunner, and the earlier RawCsvRunner and CsvRowSemantic. CSV playback has one path, GeneralCsvRunner, and CsvRunner returns the CSV suit's SoftNcRunner directly.
  • CarriersIndexedSentence (wrap a bare Sentence in your own ISentenceCarrier if you passed one as a sourceCommand), SimpleSessionCommand, HiCbtr's [Obsolete] LsStl. The packed MixedIndex file-line key is replaced by typed FileLineIndex comparison, so file and line positions compare by type rather than through a packed integer.
  • GUI-layer compositionMachiningProjectDisplayee, IsoCoordinateEntryDisplayee, HeidenhainCoordinateEntryDisplayee, UserConfig, UserService, PlayerDivConfig. Construct LocalProjectService with the ILogger-only constructor and copy the displayees from any app project — Hi.Sample.Wpf/Disp/ ships them. They compose only public API (IDisplayee over LocalProjectService), so tailoring them is the point.
  • Managed physics kernel types — the class FluteZData, MillingForceUtil.RuntimePack / LayerPack / AnglePack, the LayerMillingEngagement constructor that built an engagement from a z-to-dz list (the default and BinaryReader constructors stay), and MillingPhysicsBrief.YieldStressMinHeight_mm.
  • Culture declarationCultureUtil.SupportedCultureNames and CultureUtil.SetCurrentCulture(string), deleted outright with no [Obsolete] shim. What remains is English and SetCurrentCultureEn. A host that enumerated supported cultures must enumerate its own manual or resource folders instead.
  • Dead P/Invoke declarations — eight gl* methods on HiDisp's public GL class (glFenceSync, glGetDoublev, glGetDoublei_v, glGetDoubleIndexedvEXT, glIglooInterfaceSGIX, glPNTrianglesfATI, glPNTrianglesiATI, and the already-commented glDebugMessageCallbackAMD). They had no backing export and threw EntryPointNotFoundException when called.
  • NcFileListCommand — a list of NC files is just a List of Program File commands, so the dedicated type is gone. Loading a project that contains one converts it in place: each <File> entry becomes a single-file NcFileCommand (kind Auto, the same per-file extension dispatch) inside a ListCommand, and re-saving persists the converted form.
  • Post-Execution meshed-geometry outputPostExecutionCommand loses EnableWriteMeshedGeom and MeshedGeomFileTemplate (and their pre-rename …RuntimeGeom… spellings) together with the enable-write-meshed-geom and meshed-geom-file-path routes. A geometry snapshot can be taken at any time-spot, unlike the run-derived outputs that command manages, so the carriers are now the placeable RecordMeshedGeomCommand and ExportMeshedGeomToStlCommand. Loading an old project with the pair enabled emits PostExecution--MeshedGeomOutputRetired, and re-saving drops the elements.
  • Cutter tessellation resolution — mesh resolution is runtime data, not authored cutter data, so the seam that let a live object be “the resolution” is gone: MillingCutter no longer implements IPolarResolution2d and loses LinearResolution_mm / AngleResolution_rad / AngleResolution_deg and UpperBeamPolarResolution2dSource; the Func-based IPolarResolution2dSourceProperty interface is deleted together with the PolarResolution2dSource properties on Solid, AptProfile and CustomSpinningProfile. A Solid now holds the immutable resolution it was built with — pass it to the Solid(IGetStl, PolarResolution2d) constructor — and changing resolution means building a new solid: play paths go through SetShaperStlResolution and SetStrutStlResolution (the runner calls both for you, so the strut/upper-beam mesh follows the runtime value during a play too), holders re-mesh when you assign their PolarResolution2d property, and a fresh cutter's shaper solid is born with DefaultShaperStlResolution while the strut solid is born on the geometry's own default. Cutter files keep loading whether or not they carry the old <LinearResolution_mm> / <AngleResolution_deg> elements; the values in them were only ever the residue of the last play and are ignored, and 3.2 no longer writes them — a 3.1 install needs a support-line build carrying the guarded cutter reader (HiMech 3.1.157.2 / HiNc 3.1.175.5, shipped 2026-08-29) to open a 3.2-saved cutter file.
  • Parameterless profile meshingIShaperProfile no longer extends IGetStl, and the GetStl() convenience methods on AptProfile, ConstRatioProfile, FluteDependentRatioProfile and CustomSpinningProfile are gone. Profile mesh access is resolution-explicit: pass your value through GenStl(resolution), or state the profile's own default with GenStl(null). Geometry types that serialize as an STL source (Cylindroid, GeomCombination, TransformationGeom, ExtendedCylinder) keep GetStl() as their IGetStl contract; it is documented as, and equivalent to, GenStl(null).
  • Bounds queries never mesh — expanding a bounding box is a rough, quick operation (view fitting), so it no longer triggers STL generation anywhere. TransformationGeom.ExpandToBox3d transforms the geometry's own box corner-wise — a conservative superset of the transformed geometry's true bounds — instead of meshing, and GeomCombination now implements IExpandToBox3d by folding its sources' boxes. A geometry without IExpandToBox3d support contributes nothing to a bounds query; generate the mesh yourself if you need its true extent. MillingCutter's cutter-height bookkeeping likewise reads the profile's ZR contour and the upper beam's box instead of meshing both on every cache clear.
  • The web application's Legacy-Controller pageHiNC-2025-webservice removes the page the Page menu's third group opened, at /controller/<tab>, on 2026-09-11 (the 3.2 line). It edited HardNcEnv — the project's NcEnv, the HardNc controller model that is deprecating now that EnableSoftNcRunner defaults to true. Controller settings are edited on the General Setup page's Controller branch (/general-setup?tree=equipment/controller), the SoftNc runner's own face — see Controller. Of the settings only that page could edit, three were HardNcEnv's alone and retire with it: EnableShortestRotary (the runner honours the program's own M126 / M127 modal codes), MaxRotarySpeedABC (the runner's rotary ceiling is the rotary rate on the branch's Rapid Feedrates leaf) and HeidenhainMasterAxisChar (a HardNc parser setting with no SoftNc counterpart). The fourth, Align P0 — moving the part so that program zero lands on a work-coordinate row — is not offered on the runner path: the Work Coordinates leaf carries only P0 and M0, which write the row from the machine position; the part is placed by hand instead — see Program Zero Alignment. Old links keep working: /controller and anything below it redirects to the Controller branch. Nothing on the C# side moves — MachiningProject.NcEnv still loads and the /api/Controller/* endpoints stay mounted, so a host that drives HardNcEnv through the API or a script is unaffected.

7. Signature and shape changes

  • MachiningToolHouse derives from Dictionary<int, IMachiningTool>: SetToolId takes an int and CreateStickMillingTool returns KeyValuePair<int, MillingTool>. Any (int)entry.Key cast stops compiling. Siemens T="name" string tool calls are unaffected — they still resolve to an int at the semantic layer.
  • ActualTimecode and ActualDateTime become get-only views onto the new optional ActualTime (StepActualTime) — their setters are gone. AccumulatedTime is superseded by EndTimecode, kept as an [Obsolete] alias; step CSVs write the new header and still read the old.
  • PreSettingCommand becomes a legacy bundle. A saved bundle expands on load into MachiningResolutionCommand, MachiningMotionResolutionCommand, CollisionDetectionCommand, PauseOnFailureCommand and PhysicsCommand (plus a Read-mode RecordMeshedGeomCommand), and is never written back. Anything that located the bundle element in a saved .hincproj must look for the split commands.
  • ToPresentDto wire keys change with the obfuscation fix: geometry DTOs use Type / Min / Max / PairZrs / Z / R / SourceFile / FileIndex / LineIndex (Vec3d keeps lowercase x / y / z), transformer DTOs use Trans, Angle_deg, CosTheta / SinTheta, Axis, Pivot, Scale, Rotation, Translation, Step, Stack, Matrix. A front-end reading those payloads must be updated in lockstep.
  • defaultFontFile changes value from "Font/WCL06.ttf" to "(embedded)". It is a public const, so an assembly compiled against 3.1.175 already carries the old literal and keeps passing it — Init still accepts it — but a rebuild changes what it passes, and no font file is extracted to the working directory any more.
  • The equipment splits into two faces. SetupEquipment is the authored one — the only face a project file persists, reached as SetupEquipment. MachiningEquipment is the runtime face the runner, physics, collision and execution display read; it is rebuilt from the authored face at project assignment and at session boundaries, so a value written onto it is discarded rather than saved. See Getting started.

8. Defaults and gates that changed

  • EnableSoftNcRunner defaults to true. The SoftNc pipeline is the NC engine; HardNcRunner is the opt-out fallback for the shrinking set of features still bound to it.
  • EnableNativeMillingPhysics defaults to true, and in a shipping build setting it to false throws InvalidOperationException at the setter — the managed reference implementation lives only in a non-shipping assembly. Code that flipped it off for an A/B comparison now fails at configuration time.
  • YieldingStressRatio and YieldingStressRatio report NaN instead of 0 when no beam section qualifies. A caller treating 0 as “no yielding constraint” — as both feed solvers did — must add a NaN branch or it will pass NaN into downstream queries.
  • New licence feature NcComposition (id 22). Registering any non-built-in processing unit into a SoftNcRunner pipeline, or executing an NC-embedded C# script, requires it. Degradation is silent and functional: external units are skipped for the session with one Composition--NotLicensed naming them, an external segmenter falls back to SingleLineSegmenter, and scripts are skipped with Script--NotLicensed. An unlicensed installation therefore produces a different simulation, not an error. Calling the public API from your own application or session script needs no extra licence; composing the interpretation pipeline does. See NC Parsing Engine.
  • RadiusOffsetBasis decides what a tool-house refresh writes into the D column: CutterRadius (default — geometry plus wear, the only behaviour before the basis existed) or ZeroBased (wear only, for a tool-centre CAM path). An older project refreshes exactly as before until the basis is changed. See Tool Offsets.
  • The four SnapshotSyntax entries in the Fanuc preset default to IsEnabled = false, so projects stop serializing enabled debug snapshots. A project saved by an earlier build keeps what it serialized until its pipeline list is refreshed from the current preset.
  • Server side: HiNcServer pins request localization to English, so an Accept-Language: zh-Hant request falls back to en. HiNcRcl removes the HiNC:DisplayEngine:FontFile configuration key, which never had any effect — delete it from appsettings. FontFile remains for a custom font.
  • Localization: HiMech's MachiningStep.zh-Hant / .zh-Hans resx are deleted. Step presentation strings now come from the HiNc-Resource present catalog (catalog.en.json, catalog.zh-Hant.json, catalog.zh-Hans.json) that a host overlays; a host that ships neither loses the localized step labels it used to get for free.
  • Packaging is x64-only: HiDisp drops the win-x86 runtime identifier and its Sentinel payload, HiNc-Resource drops the x86 platform.
  • The shipped machine-tool packages are renamed. They now carry the .default marker and neutral names: MachineTool/Table-B1.default and MachineTool/CT-350.default. The table-type package was renamed outright — its .mt, its .general-mech and its STL headers travel with it — and the duplicated nested STL set inside the CT-350 package is deleted. A project, script or .mt that refers to a shipped machine-tool package by its earlier path must be repointed at the name above.
  • The shipped mechanism file takes the canonical extension. MachineTool/Table-B1.default/Table-B1.general-mech is now Table-B1.GeneralMechanism — the spelling GeneralMechanism.XName gives and every Save As has written since the type-name extensions arrived — and the package's Table-B1.mt is repointed at it. .general-mech stays readable everywhere: the loader dispatches on the XML root element and never reads the extension, so a hand-authored file keeps its name and loads as before. Only something that refers to the shipped mechanism by its old file name must be repointed. The rename ships from HiNc-Resource 3.2.21; 3.2.20 still carries .general-mech, and an admin folder already seeded by it is re-mirrored — old name deleted, new name copied, Table-B1.mt refreshed — on the first start with the newer package.