Migrating to Hammerite 2.0
Migrate a 1.x project before you open it in 2.0. Every .tres, .res and scene that 1.x saved names
Hammerite's objects by the scripts they were - res://addons/hammerite-core/scripts/resources/map.gd, brush.gd,
map_3d.gd and the rest - and 2.0 has none of those scripts: no stub at their paths, and no loader that reads such
a file as the native classes. Until it is migrated a file naming one does not load at all. Godot says
Failed loading resource: res://addons/hammerite-core/scripts/resources/map.gd for each script it names, and then
the same of the file, so a map, a bake, a prefab set or a scene placing a HammeriteMap3D comes back null and the
game does not start.
- Commit the project, or copy it.
- Install 2.0 in place of 1.x: every addon folder, with its library (What 2.0 needs).
- Migrate it:
tools/migrate_to_2.sh path/to/project, from the release's docs zip, or Project → Tools → Migrate Hammerite 1.x Resources... in the Godot editor with the full package (Migrating a project). Opening the project first writes nothing by itself, but when the Godot editor offers to open a scene with missing dependencies anyway, or to fix them, decline: a scene saved that way has lost what it held of Hammerite's. - Change the code 2.0's API breaks: the rest of this page.
What needs nothing: a .hmap saved by any earlier Hammerite opens, and so does every other data file - a
.hcache worldrep or navigation cache, a variant's bake, the editor's .hworkspace and its autosaves. They name
classes, not scripts, and read as they did.
Caches are migrated with the rest, and one that is not is only a cache. level.worldrep.res and level.nav.res,
which 1.x wrote beside a map saved as a .res, fail to load as anything else 1.x saved does - with the same
errors, on every load - and are then treated as missing: the world is compiled from the map and its navigation
built again, and both are written in 2.0's form the next time the editor saves the map. Migrate them, or delete
them, rather than leave them to print errors. Hammerite writes nothing else of its own under user://: the
editor's workspace and autosaves are data files, and the lightmapper's diagnostic reports are never read back.
What a game keeps there itself - its players' maps saved as .res, say - is migrated by pointing the editor's
dialog at that folder, or by running the command on it. A game can call HammeriteMigration.migrate("user://maps")
itself, but the class is experimental: it may change in any 2.x release, where the command and the menu items will not.
The rest of this page is what changed. 2.0 moves the addons' classes from GDScript into the native library (#263). A class keeps its name, its base class and what it does - checked against its script, call for call, before the script was deleted - but a native class cannot express everything a script could, and where it cannot, the API changes. Every such change is here, and every change of behaviour.
- What 2.0 needs
- Migrating a project
- The entity interface
- Required virtuals
- The editor
- The shapes that change
- Class by class
- The native kernel's classes and switches
- What the suites reached
- Experimental classes
- Behaviour
What 2.0 needs
- The native library, always. 1.x ran on GDScript and used its native kernel where one was built; 2.0's classes
are the library. It is
addons/hammerite-core/bin/libhammerite.<platform>, loaded byhammerite_core.gdextensionfor all four addons, and there is no GDScript to fall back on: a project without it does not load core, and says "Hammerite's native library is not loaded". Nonative_*switch chooses any more (the kernel's classes and switches). - One of two packages, installed whole (#273).
hammerite-runtime-<version>.zipis core, audio and nav, for a game whose players never open the map editor;hammerite-full-<version>.zipis those and the editor. 1.x's four addons were installed one by one; 2.0's come as a package's folders with the library built for exactly those, so replace all four 1.x folders with one package's. Ahammerite-editorfolder beside the runtime package's library has none of its classes, and a full library without one is missing a folder: either is an error as the project starts. An addon a game does not use stays installed with its plugin disabled. See Installing. - macOS, Linux x86_64 and Windows x86_64. A release carries the library for macOS as one universal binary (Apple
silicon and Intel), for Linux x86_64 and for Windows x86_64, in every package. The
.gdextensionalso names a Linux arm64 library, which a checkout can build (tools/build_native.sh) but no release carries. - No web export. No library is built for the web, and without one core does not load, so a game exporting to the web cannot use 2.0. None will be until GDExtension on the web is dependable (#263). 1.x did not support the web either, but nothing stopped its GDScript loading there.
- Godot 4.7, as 1.x. The library is built against godot-cpp's 4.5 API and its
.gdextensionloads in 4.5 or later, but the suites run on 4.7.1 and nothing earlier is tested. - No hot reload. The library is not reloadable: restart the Godot editor after replacing it.
Migrating a project
Migrate a project once, after installing 2.0, from the command line or from either editor:
tools/migrate_to_2.sh path/to/project --dry-run # what would change; writes nothing
tools/migrate_to_2.sh path/to/project # migrate, keeping each original as <file>.bak
tools/migrate_to_2.sh path/to/project --no-backup # without the .bak files
The tool is not in either package, which hold only what goes into addons/: it is in tools/ of
hammerite-docs-<version>.zip, released beside them, and of this repository. Unzip the docs anywhere and run it
from there, naming the project - path/to/hammerite-docs/tools/migrate_to_2.sh path/to/project - keeping
migrate_to_2.sh and migrate_to_2.gd together. It is a bash script, so on Windows run it from Git Bash, or use
the editor's command below. It runs Godot headless in the project - /Applications/Godot.app unless GODOT= names
another binary, as it must on Linux and Windows - importing it first if the project has not
been opened since 2.0 was installed - and calls HammeriteMigration.migrate("res://"). It lists each file it migrated, with the classes it was migrated for, and each it could not, with why,
and exits 1 when there is any of those. Commit the project, or copy it, before running it.
The editor does the same, with the dry run shown before anything is written: Project → Tools → Migrate Hammerite
1.x Resources... in the Godot editor, which rescans the project afterwards and is the one to use while the game
cannot start, and File → Migrate 1.x Resources… in Hammerite's editor, in the game. Each lists what it would
migrate and what it cannot, with why, migrates on confirming - keeping the .bak files unless told not to - and
lists what it did. It looks in res:// and takes another res:// or user:// folder, such as where a game keeps
its players' maps. Both are the editor's, so the full package has them and the runtime package does not: with the
runtime package, use the command line. It migrates what core, audio and nav saved, and reports a file naming one of
the editor's scripts - a scene placing an editor node, or the editor's settings saved as a .tres - as skipped, with its
classes, for the full package to migrate.
What 2.x promises is the command and the two menu items - tools/migrate_to_2.sh with its options,
File → Migrate 1.x Resources… and Project → Tools → Migrate Hammerite 1.x Resources... - and what they
migrate (API stability). HammeriteMigration, the class all three call, and the editors' dialog
are experimental: a script can call them, but they may change in any release.
What it does to a file that names a 1.x script of Hammerite's, and nothing else:
- each object the file holds as a
Resourcecarrying a 1.x script - a map, a brush, a bake, a probe set, a light curve, a prefab, an audio graph, a navigation cache - is written as its native class, without the script; - in a text scene (
.tscn), each node carrying one of Hammerite's 1.x node scripts -map_3d.gd,eye_adaptation_3d.gd, a light, a decal, a mover, a trigger, a logic entity, an entity base, audio's emitter, receiver and sound entities, nav's link entity - is that node class, without the script or the_custom_type_scriptthe editor marked it with, keeping its place and its properties; - the scripts go from the file's
[ext_resource]lines or external table, andload_stepsand the script class of the file's main resource with them.
Every other byte of the file is as it was: text stays text, binary stays binary, and a compressed .res is
compressed again as it was, with its uid. The file is rewritten where it lies rather than loaded and saved, so
nothing in the project is loaded - a game's own script that does not compile in a headless run would otherwise
cost the objects carrying it their values - and the rewritten file is read back before it is kept. A file
naming no 1.x script is not touched, nor is anything in a hidden folder, one holding a .gdignore, or
Hammerite's own folders under addons/. A second run finds nothing to do.
A file it cannot migrate it leaves as it was, and says why:
- it names a script of Hammerite's that has no class in 2.0. hammerite-audio's acoustic classes
(
acoustic_node_graph.gdand the rest) were renamed to its audio ones before 1.0 (#249), so a map still holding an acoustic graph loads neither in 1.0 nor in 2.0: re-save it from the Hammerite that wrote it with its audio rebaked, or rebuild it; - a node carries a 1.x script on a node the scene does not make itself (an instance's, or an inherited scene's), or one whose class the native one does not extend: set the node's type in the Godot editor;
- a binary scene (
.scn) places a node by its 1.x script: save it as a.tscnfrom the Godot editor, and run the migration again.
A script of the game's that extends one of Hammerite's by path (extends "res://addons/hammerite-core/...gd")
is the game's code, not a resource, and is not touched: extend the class by name.
2.0 ships without the 1.x compatibility layer its development builds had - a stub script at each 1.x path and a loader that read 1.x files as the native classes (#272) - and the migration needs neither: it knows each 1.x script by the path and the uid 1.x gave it. It ships with every 2.x release (API stability).
The entity interface
Core's scene nodes are native (#268): HammeriteMap3D, the entity bases, and every entity class of core's own
sets. A game's entity class still extends a base (HammeritePointEntityNode3D, HammeritePointEntityAnimatableBody3D,
HammeritePointEntityRigidBody3D, HammeriteBrushEntityNode3D, HammeriteBrushEntityStaticBody3D,
HammeriteBrushEntityAnimatableBody3D, HammeriteBrushEntityArea3D) or one of core's entity classes, but it
overrides the interface under the engine's convention: a method a script overrides is a native virtual, and a
native virtual is a name with an underscore. The public names stay, and are what everybody calls - the map, the
editor, a game: each dispatches to the virtual.
Rename every override to its underscore name. The signatures are unchanged.
# 1.x
extends HammeritePointEntityNode3D
func set_editor_active(active: bool) -> void: ...
func apply_entity_property(prop_name: StringName, value: Variant) -> void: ...
func trigger(impulse: Variant = null) -> void: ...
# 2.0
extends HammeritePointEntityNode3D
func _set_editor_active(active: bool) -> void: ...
func _apply_entity_property(prop_name: StringName, value: Variant) -> void: ...
func _trigger(impulse: Variant = null) -> void: ...
| 1.x override | 2.0 virtual | |
|---|---|---|
set_entity(new_entity) |
_set_entity(new_entity) |
after the base has bound the entity |
update_properties() |
_update_properties() |
after the base has applied every property |
apply_entity_property(prop_name, value) |
_apply_entity_property(prop_name, value) |
required of a script extending a base; after the class's own |
set_editor_active(active) |
_set_editor_active(active) |
required of a script extending a base, except HammeriteBrushEntityArea3D |
draw_editor_gizmos(gizmos) |
_draw_editor_gizmos(gizmos) |
|
draws_editor_gizmos_only_when_picked() |
_draws_editor_gizmos_only_when_picked() |
|
get_editor_handles() |
_get_editor_handles() |
|
move_editor_handle(handle_id, to) |
_move_editor_handle(handle_id, to) |
|
get_aabb() |
_get_aabb() |
|
can_simulate(), start_simulation(), stop_simulation(), reset_simulation() |
_can_simulate(), ... |
|
get_runtime_properties(), get_runtime_property(key, default_value), set_runtime_property(key, value), reset_runtime_properties() |
_get_runtime_properties(), ... |
|
can_trigger(), trigger(impulse) |
_can_trigger(), _trigger(impulse) |
|
get_actions() |
_get_actions() |
merged over the class's own (Trigger) |
run_action(action_id) |
_run_action(action_id) |
after the class's own |
turn_to(facing) |
_turn_to(facing) |
point bases but the rigid body |
set_light_modulation(modulation) |
_set_light_modulation(modulation) |
point bases |
should_create_meshes(), should_create_colliders() |
_should_create_meshes(), _should_create_colliders() |
brush bases |
An override left under its old name does not compile: it would hide a native method the engine calls, which GDScript refuses (Required virtuals).
super() goes. GDScript cannot call super() into a native virtual, nor super._init(), super._ready() or
super._process() on a native class. Where an override called super() first - set_entity, update_properties,
apply_entity_property on one of core's classes, get_actions, run_action - the class's own now runs first by
itself, and the script's override after it, so drop the call:
# 1.x
func set_entity(new_entity: HammeriteEntity) -> void:
super(new_entity)
_offer_a_hand()
# 2.0
func _set_entity(new_entity: HammeriteEntity) -> void:
_offer_a_hand()
Work an override did before super() has to find another place: it runs after the base now. A flag raised
around super() to quiet _apply_entity_property while the entity is being bound starts raised instead, and
_set_entity lowers it. get_actions()'s override answers only the actions it adds. Any other override replaces
what the class does, as before - with no super() to reach what it replaced. A script on one of core's own
classes that called super._process(delta) drops it: the class does its per-frame work from its notification,
after the script's _process.
Overriding one of a script's virtuals is unchanged: a class extending a game's entity script still calls
super._apply_entity_property(...).
A native class of core's has hooks of its own under the same convention: a script on a dynamic light
overrides _get_lit_modulation() and may follow set_seen() with _set_seen(); one on a logic entity or a mover
_get_icon(), _tick(), _reset(), _apply() and _wired_targets(); one on HammeritePropModel may follow
set_room_seen() with _set_room_seen(); one on HammeriteThumbnailGenerator takes over _generate_thumbnail(),
_generate_entity_thumbnail() or _generate_mesh_thumbnail().
A classname may name a native class. HammeriteMap3D builds an entity's node from a script class of that name
or, where there is none, from a class the library registers; core's own (HammeritePointLight3D...) are native.
Required virtuals
1.x marked what a subclass had to write @abstract, and a script that left one out did not compile. A native class
has no @abstract: what a script must write is a required virtual, and every one of them has an underscore.
1.x, @abstract |
2.0, required virtual |
|---|---|
set_editor_active(active) and apply_entity_property(prop_name, value) on HammeritePointEntityNode3D, HammeritePointEntityAnimatableBody3D, HammeritePointEntityRigidBody3D, HammeriteBrushEntityNode3D and HammeriteBrushEntityStaticBody3D |
_set_editor_active(active) and _apply_entity_property(prop_name, value), on those and on HammeriteBrushEntityAnimatableBody3D |
apply_entity_property(prop_name, value) on HammeriteBrushEntityArea3D |
_apply_entity_property(prop_name, value); _set_editor_active is optional there, as set_editor_active was |
HammeriteEditorTool's _tool_input(event), _tool_process(delta), _tool_exit() and get_tool_name() |
_tool_input(event), _tool_process(delta), _tool_exit() and _get_tool_name() |
HammeritePropertyControl's get_value(), set_value_no_signal(value), set_disabled(disabled) and set_indeterminate(indeterminate) |
_get_value(), _set_value_no_signal(value), _set_disabled(disabled) and _set_indeterminate(indeterminate) |
HammeriteDynamicLight3D._icon() |
none: the class is registered abstract, and only its own point, spot and directional lights extend it. A script that extended it extends HammeriteDynamicPointLight3D or one of the others, whose icon is theirs |
| - | HammeriteEntitySet._register_types(), new since 1.0 |
A script overrides one by declaring it under that name with the signature in the class reference, as it would any
engine virtual (func _set_editor_active(active: bool) -> void:). Where the public method of the same name is
still what everybody calls, the class dispatches to the override.
One left out is an error when it is called, not when the script compiles. A script extending a base without
_set_editor_active parses, and new() makes one where the @abstract script refused; the first call then
reports
ERROR: Required virtual method HammeritePointEntityNode3D::_set_editor_active must be overridden before calling.
and does nothing - an engine error, which fails a suite. HammeriteMap3D still refuses a classname whose class
does not extend a base, so a map never builds a base itself. The entity suites of a game should build every type
it registers and call these once, which is what Hammerite's own do.
One written under its old public name does not compile:
Parse Error: The method "set_editor_active()" overrides a method from native class "HammeritePointEntityNode3D". This won't be called by the engine and may not work as expected. (Warning treated as error.)
The editor
The level editor is native (#271): every class of hammerite-editor, and the editor tools and extensions of hammerite-audio and hammerite-nav, in the library's editor, audio_editor and nav_editor modules, which only the full package has. They keep their names and what they do - each was held to its script, call for call and node for node, before the scripts were deleted - and the shapes that change are the same as core's. What a game that extends or drives the editor changes:
A tool overrides the underscore names. The editor calls tool_input(event), tool_process(delta) and
tool_exit(), and get_tool_name(), get_status_text(), holds_cursor() and get_manual_page() as before; each
dispatches to a virtual, which is what a script overrides, as an entity does. A tool is made with
create(editor), and a script's own constructor calls setup(editor) where it called super(editor). The options
panel is a class of its own.
# 1.x
extends HammeriteEditorTool
func _init(editor: HammeriteMapEditor) -> void:
super(editor)
func get_tool_name() -> String:
return "Patrol Route"
func get_status_text() -> String:
return "Click to add a point"
func _tool_input(event: InputEvent) -> bool: ...
var popup := HammeriteEditorTool.SimpleToolPopup.new()
editor.set_active_tool(PatrolRouteTool.new(editor))
tool._tool_process(delta)
# 2.0
extends HammeriteEditorTool
func _init(editor: HammeriteMapEditor) -> void:
setup(editor)
func _get_tool_name() -> String:
return "Patrol Route"
func _get_status_text() -> String:
return "Click to add a point"
func _tool_input(event: InputEvent) -> bool: ...
var popup := HammeriteEditorToolSimpleToolPopup.new()
editor.set_active_tool(PatrolRouteTool.new(editor))
tool.tool_process(delta)
| 1.x | 2.0, what a script overrides | what is called |
|---|---|---|
_tool_input(event) |
_tool_input(event) |
tool_input(event) |
_tool_process(delta) |
_tool_process(delta) |
tool_process(delta) |
_tool_exit() |
_tool_exit() |
tool_exit() |
get_tool_name() |
_get_tool_name() |
get_tool_name() |
get_status_text() |
_get_status_text() |
get_status_text() |
holds_cursor() |
_holds_cursor() |
holds_cursor() |
get_manual_page() |
_get_manual_page() |
get_manual_page() |
The editor's own tools are made with create(...) where new(...) took arguments:
HammeriteTransformTool.create(editor, mode), HammeriteFaceEditTool.create(editor, popup),
HammeriteFaceMoveTool.create(editor, origin), HammeriteExtrudeTool.create(editor, origin) and
create(editor) for the rest, hammerite-audio's HammeriteAudioPortalTool and hammerite-nav's
HammeriteNavigationTool among them.
A property control overrides the underscore names too. The panel calls get_value(),
set_value_no_signal(value), set_disabled(disabled) and set_indeterminate(indeterminate), which dispatch to
_get_value(), _set_value_no_signal(value), _set_disabled(disabled) and _set_indeterminate(indeterminate).
set_value(value) is the class's own: it shows the value through _set_value_no_signal and emits value_changed
with what _get_value then answers, so an override of it goes.
# 1.x
extends HammeritePropertyControl
func get_value() -> Variant:
return _value
func set_value(new_value: Variant) -> void:
set_value_no_signal(new_value)
value_changed.emit(_value)
func set_value_no_signal(new_value: Variant) -> void:
_value = new_value
_refresh()
func set_disabled(disabled: bool) -> void: ...
func set_indeterminate(indeterminate: bool) -> void: ...
# 2.0
extends HammeritePropertyControl
func _get_value() -> Variant:
return _value
func _set_value_no_signal(new_value: Variant) -> void:
_value = new_value
_refresh()
func _set_disabled(disabled: bool) -> void: ...
func _set_indeterminate(indeterminate: bool) -> void: ...
A script extending HammeriteChoiceProperty calls setup(initial, choices, allow_empty) where it called
super(...), and one is made with HammeriteChoiceProperty.create(initial, choices, allow_empty = true).
Everything else a game hangs on the editor - register_property_editor, register_property_choices,
register_cell_overlay, add_toolbar_button, register_workspace and the rest - takes a Callable, as before.
A coroutine answers a Variant. A native method cannot await, so the editor's coroutines run on a stack of
their own on the main thread and give the thread back where the script awaited, as the lightmapper's do. Awaited,
each answers what it did; not awaited, it answers its result when it never had to wait, and otherwise a
HammeriteEditorCoroutine's finished signal that carries it. HammeriteMapEditor.save_map(), save_map_to(),
prompt_save_map_as(), autosave(), new_map(), open_map_at(), prompt_load_map() and
prompt_unsaved_changes(), and HammeriteTextureBrowser.refresh():
if await editor.save_map() == OK: ... # as in 1.x
Names that would hide the engine's take a suffix: a Window's min_size, so MIN_SIZE of the texture
browser, the command launcher, the entity search and the manual browser is min_size_constant(); and
Node.get_viewport(), so HammeriteMapEditor's and the editor cameras' viewport property has the accessors
get_viewport_value() and set_viewport_value() (the property keeps its name; a tool's viewport is unchanged).
Static variables: HammeritePropertyEditor.label_width is get_label_width() / set_label_width(), and
HammeriteObjectSelection.individual_key get_individual_key() / set_individual_key().
HammeriteNavigationTool.CRAMPED_CLEARANCE, a static var while the tool was a script, is cramped_clearance().
Inner classes:
| 1.x | 2.0 |
|---|---|
HammeriteEditorTool.SimpleToolPopup |
HammeriteEditorToolSimpleToolPopup |
HammeriteManual.SearchHit |
HammeriteManualSearchHit |
HammeriteManualPage.Heading |
HammeriteManualPageHeading (HammeriteManualPage.headings holds them) |
HammeriteCommandMatcher.Entry |
HammeriteCommandMatcherEntry |
HammeriteEditorHandles.Offered |
HammeriteEditorHandlesOffered |
HammeriteDarkMissionImporter.DarkObject |
HammeriteDarkMissionImporterDarkObject |
HammeriteDarkMissionImporter.DarkPatrol |
HammeriteDarkMissionImporterDarkPatrol |
HammeriteArchGeometry.ArchSpec |
HammeriteArchGeometryArchSpec |
HammeriteEntityBrowser.EntityBrowserItem |
HammeriteEntityBrowserEntityBrowserItem |
HammeriteMessageLog.LogEntry |
HammeriteMessageLogLogEntry |
The importer's objects and patrols are typed: object.patrol is a HammeriteDarkMissionImporterDarkPatrol, and
importer.objects, importer.patrols and importer.player_start hold the two classes. After 2.0.0 the importer is in
no release, only the dev package a checkout builds (tools/build_native.sh dev, #279). The other inner classes are
internal, which nothing outside the library names: HammeritePrefabBrowser.PrefabBrowserItem,
HammeritePropBrowser.PropGrid, HammeriteManualTabs.Tab, HammeriteCellPreview2D.WallDrawing,
HammeriteVertexTool.VertexIndex, HammeriteFaceEditTool.FaceAttributes, the dock's Strip, Chevron and
DropZone, the importer's DarkSurface, DarkCell, WorldrepLayout, BrushRecord and Piece, and the map
editor's private _GizmoPresenter and _SaveShield and the save status's _Spinner.
HammeritePropertyEditor._DocumentedLabel is HammeritePropertyEditorDocumentedLabel.
A few signatures take one of these classes as a RefCounted, since an inner class could not be named where they
are declared; the object passed is the class above, as before: HammeriteArchGeometry's functions and
HammeriteArchBrushTool.build_spec() a HammeriteArchGeometryArchSpec, HammeriteCommandMatcher,
HammeriteCommandLauncher (and its entry_chosen signal) and HammeriteMapEditor.launcher_entries() and
remember_launched() a HammeriteCommandMatcherEntry, HammeriteEditorHandles a HammeriteEditorHandlesOffered,
and HammeriteManualTabs.tabs its tabs.
Made with create(): HammeriteArchBrushTool.create(editor), HammeriteAudioPortalTool.create(editor), HammeriteBrush2D.create(brush, map_2d, cam_2d, settings), HammeriteBrushTool.create(editor), HammeriteCellPreview2D.create(map_2d, cam_2d), HammeriteChoiceProperty.create(initial, choices, allow_empty = true), HammeriteClipTool.create(editor), HammeriteCommandMatcherEntry.create(entry_id, entry_label, entry_run), HammeriteConeBrushTool.create(editor), HammeriteContextMenu.create(map_editor), HammeriteCubeBrushTool.create(editor), HammeriteCurveProperty.create(initial = null), HammeriteCylinderBrushTool.create(editor), HammeriteDecalTool.create(editor), HammeriteDockBox.create(box_id, box_title, box_content), HammeriteDockColumn.create(column_side), HammeriteEditorCamera.create(cam), HammeriteEditorCommand.create(command_id, command_label, command_action), HammeriteEditorHandles.create(editor), HammeriteEditorHandlesOffered.create(handle_owner, offered), HammeriteEditorTool.create(editor), HammeriteEntity2D.create(entity, map_2d), HammeriteEntityBrowserEntityBrowserItem.create(type_name, props), HammeriteEntityFacing.create(turned, handle_color = Color(1, 0.8, 0.25, 1)), HammeriteEntityTool.create(editor), HammeriteExtrudeTool.create(editor, origin), HammeriteFaceEditTool.create(editor, popup), HammeriteFaceHighlight3D.create(colors = null), HammeriteFaceMoveTool.create(editor, origin), HammeriteFragmentOutlines2D.create(chunks, layer, map_2d), HammeriteGrid.create(div = 1.0), HammeriteLightmapTool.create(editor), HammeriteManualBrowser.create(the_manual, the_workspace = null), HammeriteManualRenderer.create(manual), HammeriteMap2D.create(editor, cam_2d), HammeriteMapSave.create(of, to), HammeriteMarqueeSelection2D.create(cam, mode), HammeriteMessageLogLogEntry.create(msg, ts, t), HammeriteNarrowState.create(map_ref, visible_brushes, visible_entities = null), HammeriteNavigationTool.create(editor), HammeritePickResult.create(e, b, f), HammeritePolygonTool.create(editor), HammeritePrefabTool.create(editor), HammeritePropTool.create(editor), HammeritePropertyItem.create(default_value, hint = null), HammeriteQuadViewportContainer.create(editor), HammeriteRampBrushTool.create(editor), HammeriteScreenLines.create(dedupe = false, added = null), HammeriteSelectTool.create(editor), HammeriteSkyTool.create(editor), HammeriteStairBrushTool.create(editor), HammeriteTerrainTool.create(editor), HammeriteTransformHelper.create(transform_origin, camera, transform_grid), HammeriteTransformTool.create(editor, mode), HammeriteVariantProperty.create(initial = null), HammeriteVertexGizmo.create(editor), HammeriteVertexTool.create(editor) - every argument with the default it had. Without arguments, new() still works.
Constants that are methods now:
HammeriteAudioEditorExtension:MENU_COMMAND→menu_command()HammeriteAudioPortalTool:PICK_RADIUS→pick_radius(),OUTLINE_OFFSET→outline_offset()HammeriteTransformGizmo3D:AXIS_REACH→axis_reach()HammeriteVertexGizmo:PICK_RADIUS→pick_radius(),HANDLE_SIZE→handle_size(),HANDLE_HOVER_SCALE→handle_hover_scale(),HANDLE_TINT→handle_tint(),HANDLE_TINT_HOVERED→handle_tint_hovered()HammeriteVoidWindowOverlay3D:COLOR→color(),LIFT→lift()HammeriteBrush2D:DETAIL_OUTLINE→detail_outline()HammeriteCellPreview2D:WALL_HALF_WIDTH→wall_half_width(),PORTAL_HALF_WIDTH→portal_half_width()HammeriteCommandMatcher:NO_MATCH→no_match(),AT_LABEL_START→at_label_start(),AT_WORD_START→at_word_start(),AS_INITIALS→as_initials(),INSIDE_LABEL→inside_label(),IN_ORDER→in_order(),IN_MENU_OR_KEYWORDS→in_menu_or_keywords(),PER_WORD_ALONG→per_word_along(),RECENT→recent()HammeriteMapEditorCore:ANY_TYPE→any_type()HammeriteEditorCamera2D:CAMERA_OFFSET→camera_offset(),ENTITY_PICK_MARGIN_PX→entity_pick_margin_px(),DRAG_THRESHOLD→drag_threshold(),ZOOM_TIMEOUT→zoom_timeout()HammeriteEditorCamera3D:DRAG_THRESHOLD→drag_threshold(),MAX_PAN_DELTA→max_pan_delta(),ORBIT_DISTANCE→orbit_distance(),ORBIT_PITCH_LIMIT→orbit_pitch_limit(),PICK_DISTANCE→pick_distance()HammeriteEditorHandles:GRAB_RADIUS→grab_radius(),RADIUS→radius(),HOVER_LIGHTEN→hover_lighten()HammeriteEditorWorkspace:PATH→path(),SETTLE→settle()HammeriteEntity2D:DEFAULT_SIZE→default_size(),CENTRE_DOT→centre_dot()HammeriteEntityFacing:ID→id(),REACH_PAST_BOX→reach_past_box(),LEAST_REACH→least_reach()HammeriteFacePicking:COINCIDENT_DISTANCE→coincident_distance()HammeriteFragmentOutlines2D:HALF_WIDTH→half_width()HammeriteGrid:MIN_DIVISION→min_division(),MAX_DIVISION→max_division()HammeriteEditorCommands:FILE→file(),EDIT→edit(),SELECTION→selection(),VIEW→view(),VIEWPORT_3D→viewport_3d(),TOOLS→tools(),HELP→help(),MENU_ORDER→menu_order(),CTX_ENTITY→ctx_entity(),CTX_INSTANCE→ctx_instance(),CTX_BRUSH→ctx_brush(),CTX_FACE→ctx_face(),CTX_SELECTION→ctx_selection(),CTX_VIEW→ctx_view(),CONTEXT_ORDER→context_order()HammeriteDarkMissionImporter:TEXELS_PER_SPAN→texels_per_span(),SPAN_UNITS→span_units(),WORLDREP_CHUNK→worldrep_chunk(),FIXED_SPAN→fixed_span(),SURFACE_PLANE_SLACK→surface_plane_slack(),NOT_DRAWN_RENDER_TYPES→not_drawn_render_types(),MOVING_LIGHT_MODES→moving_light_modes(),MATERIAL_SKY→material_sky(),MATERIAL_WATER→material_water(),MATERIAL_DEFAULT→material_default()HammeriteDarkPrimals:CUBE_POINTS→cube_points(),CUBE_FACES→cube_faces(),WEDGE_POINTS→wedge_points(),WEDGE_FACES→wedge_faces(),DODECAHEDRON_POINTS→dodecahedron_points(),DODECAHEDRON_FACES→dodecahedron_faces()HammeriteManual:INDEX→index()HammeriteManualBrowser:MIN_SIZE→min_size_constant(),MONO_FACES→mono_faces()HammeriteManualExport:ADDON_MANUAL_DIR→addon_manual_dir(),EXTRA_ROOTS_SETTING→extra_roots_setting()HammeriteManualRenderer:MISSING→missing()HammeriteMap2D:CUT_REACH→cut_reach(),OFF_CUT_ALPHA→off_cut_alpha()HammeriteMap2DGizmos:DASH_PIXELS→dash_pixels()HammeriteQuadViewportContainer:ENTITY_DRAG_KEY→entity_drag_key(),PROP_DRAG_KEY→prop_drag_key(),VIEW_MENU_MARGIN→view_menu_margin(),VIEW_NAMES→view_names(),HOLD_MARGIN→hold_margin()HammeriteRulerInteraction:RULER_WIDTH→ruler_width(),TICK_MAJOR_SIZE→tick_major_size(),TICK_MINOR_SIZE→tick_minor_size(),SLICE_GRAB→slice_grab(),AXES→axes()HammeriteBrushTool:DEFAULT_PLANE→default_plane(),DEFAULT_THICKNESS→default_thickness()HammeriteArchGeometry:EPSILON→epsilon(),MIN_ARC_DEGREES→min_arc_degrees(),MAX_ARC_DEGREES→max_arc_degrees()HammeritePropTool:PROP_CLASSNAME→prop_classname(),PROP_TYPE→prop_type(),DRAG_THRESHOLD→drag_threshold()HammeriteSelectTool:DOUBLE_CLICK_DISTANCE→double_click_distance()HammeriteStairBrushTool:MAX_STEP_HEIGHT→max_step_height(),ANGLE_EPSILON→angle_epsilon(),FLAT_EPSILON→flat_epsilon()HammeriteTerrainTool:RADIUS_STEP→radius_step()HammeriteTransformHelper:FACE_ON_LIMIT→face_on_limit(),COHERENT_NORMAL_LIMIT→coherent_normal_limit()HammeriteActiveTexturePanel:SIDE_MIN→side_min(),SIDE_MAX→side_max()HammeriteChoiceProperty:NOTHING→nothing(),POPUP_LIST_HEIGHT→popup_list_height(),POPUP_MIN_WIDTH→popup_min_width()HammeriteCommandLauncher:MIN_SIZE→min_size_constant()HammeriteCurveProperty:HEIGHT→height(),REACH→reach()HammeriteDockBox:DRAG_KEY→drag_key()HammeriteEditorCanvas:STEPS→steps(),MIN_SCALE→min_scale(),MAX_SCALE→max_scale()HammeriteEditorTheme:CANVAS→canvas(),SURFACE→surface(),RAISED→raised(),LINE→line(),LINE_BRIGHT→line_bright(),TEXT→text(),TEXT_DIM→text_dim(),TEXT_FAINT→text_faint(),ACCENT→accent(),ACCENT_SUNK→accent_sunk(),WARNING→warning(),DANGER→danger(),VARIANT→variant()HammeriteEntityBrowser:CELL→cell(),PICTURE_HEIGHT→picture_height()HammeriteEntitySearchPopup:MIN_SIZE→min_size_constant()HammeriteFaceLoopHelper:EPSILON→epsilon()HammeriteMeasurementLabels3D:PIXEL_SIZE→pixel_size(),UPRIGHT_LEEWAY→upright_leeway()HammeriteLayerTree:COLUMN_ICONS→column_icons(),COLUMN_ICON_SIZE→column_icon_size(),DRAG_KEY→drag_key(),ABSENT_COLOR→absent_color(),STALE_COLOR→stale_color(),UNBAKED_COLOR→unbaked_color(),BAKE_CHECK_DELAY→bake_check_delay(),MIN_HEIGHT→min_height(),MAX_HEIGHT→max_height()HammeriteLightmapToolPopup:PARAMETERS→parameters(),FALLOFF_MODES→falloff_modes()HammeriteMapEditor:ANY_TYPE→any_type(),PANEL_WIDTH_MIN→panel_width_min(),BROWSER_SHARE→browser_share(),ENTITY_SEARCH_SHARE→entity_search_share(),WIRED→wired(),LAUNCHER_SHARE→launcher_share(),AUTOSAVE_SECONDS→autosave_seconds()HammeriteMessageLogStatusLabel:FLASH_SECONDS→flash_seconds()HammeriteProblemBrowser:MIN_HEIGHT→min_height(),GRAPH_KIND_ORDER→graph_kind_order(),BAKE_KIND_ORDER→bake_kind_order()HammeritePropBrowser:CELL→cell(),PICTURE_HEIGHT→picture_height()HammeritePropertyEditor:LABEL_WIDTH_DEFAULT→label_width_default(),LABEL_WIDTH_MIN→label_width_min()HammeritePropertyEditorDocumentedLabel:WIDTH→width()HammeriteSelectionPanel:ICONS→icons(),PREFAB_BADGE→prefab_badge()HammeriteSelectionPropertyEditor:ENTITY_DOC_PREFIX→entity_doc_prefix(),RUNTIME_REFRESH_INTERVAL→runtime_refresh_interval()HammeriteSkyToolPopup:NUMBERS→numbers(),COLOURS→colours()HammeriteTextureBrowser:MIN_SIZE→min_size_constant(),ZOOM_STEP→zoom_step()HammeriteTextureBrowserItem:PER_UNIT→per_unit(),SMALLEST→smallest(),LARGEST→largest(),CAPTION→caption(),bg_texture→bg_texture()HammeriteTextureBrowserLayout:COLUMN→column(),MIN_ZOOM→min_zoom(),MAX_ZOOM→max_zoom()HammeriteToolHelpPanel:KEY_PATTERN→key_pattern(),PARAMETERS_OPEN→parameters_open()HammeriteUvEditor:SHAPE_COLOR→shape_color(),SHAPE_FILL_COLOR→shape_fill_color(),HANDLE_COLOR→handle_color(),PIVOT_COLOR→pivot_color(),HANDLE_RADIUS→handle_radius(),ROTATE_HANDLE_OFFSET→rotate_handle_offset(),FIT_MARGIN→fit_margin(),ZOOM_SPEED→zoom_speed(),MIN_ZOOM→min_zoom(),MAX_ZOOM→max_zoom(),PAN_SPEED→pan_speed()HammeriteVariantProperty:TYPES→types()HammeriteVolumeWheel:DEADZONE→deadzone(),RADIUS_INNER→radius_inner(),RADIUS_OUTER→radius_outer()HammeriteNavigationTool:ROUTE_ARRIVAL_TOLERANCE→route_arrival_tolerance(),ROUTE_COLOR→route_color(),LINK_COLORS→link_colors()HammeriteNavigationEditorExtension:MENU_COMMAND→menu_command()
The editor's three scenes are gone: scenes/ui/property_editor.tscn, scenes/3d/vertex_gizmo.tscn and
scenes/3d/transform_gizmo_3d.tscn. Each class builds the same nodes itself: HammeritePropertyEditor.new(),
HammeriteVertexGizmo.create(editor) and HammeriteTransformGizmo3D.new() where a game instanced the scene.
The autoloads are thin scripts over native classes. HammeriteAudio is scripts/hammerite_audio.gd, one line
extending HammeriteAudioAutoload, and HammeriteNavigation scripts/hammerite_navigation.gd extending
HammeriteNavigationAutoload: the same paths and uids, so a project.godot naming them is unchanged, and the same
members, which the reference documents. HammeriteEditor stays a script, and makes the
editor's classes by name so that it compiles in a game installed without the editor: its editor and workspaces
are typed Control, and integrate() answers one. Assign it to a HammeriteMapEditor to have it typed.
var map_editor: HammeriteMapEditor = HammeriteEditor.integrate(self) # as in 1.x; a cast now, not a type
The migration knows the editor's scripts. The editor's scripts are deleted: a 1.x scene or resource naming
one does not load until it is migrated, and tools/migrate_to_2.sh rewrites it. It places each of the 60 editor scripts whose class is a Node (the three
scenes' scripts among them) as its native class, and writes the four Resources a user's settings were saved as -
HammeriteEditorWorkspace, HammeriteMapEditorSettings, HammeriteGrid and HammeriteEditorColors - as theirs.
The audio and nav editor scripts are RefCounted, which no scene places. A library without the editor (the
runtime package) has none of those classes, so a file naming one is reported skipped, with its classes and that
the full package migrates it, rather than failed. The autoload scripts stay where they were and are left alone.
Defaults are never shared instances. The engine takes a class's defaults from one instance it keeps, so a
property a constructor filled was everybody's default, and the Godot editor printed "Instantiated ... used as
default value" for each as it opened. HammeriteMap.probe_set is null until the map has one - once it is lit, or
read from a file that has one - and a map made with HammeriteMap.new() and saved writes no probe set where it
wrote an empty one. HammeriteMapEditorSettings.colors is null until an editor uses the settings; an editor's own
always have them. HammeriteMapEditor.settings is made the first time it is asked for.
City of Thieves, a worked example: what it changed to run on the native editor.
HammeriteEditorTheme.CANVAS,TEXT,TEXT_DIM,TEXT_FAINT,ACCENT,WARNINGandDANGERarecanvas(),text(),text_dim(),text_faint(),accent(),warning()anddanger().HammeriteMapEditor.ANY_TYPEisany_type(), inregister_property_editor(HammeriteMapEditor.any_type(), ...).HammeriteChoiceProperty.new(...)andHammeriteCurveProperty.new(...)arecreate(...), andHammeriteEditorHandles.new(editor)create(editor).- Its spawn flags and light preset property controls override
_get_value,_set_value_no_signal,_set_disabledand_set_indeterminate, and drop theirset_value; its resource picker, extendingHammeriteChoiceProperty, callssetup(...)where it calledsuper(...). - Its patrol route tool calls
setup(editor), overrides_get_tool_nameand_get_status_text, and makes its panel withHammeriteEditorToolSimpleToolPopup.new(). - Its Dark mission import names
HammeriteDarkMissionImporterDarkObjectandHammeriteDarkMissionImporterDarkPatrol, andHammeriteEditorHandles.gather()answersArray[HammeriteEditorHandlesOffered].
The shapes that change
A static variable becomes a pair of static methods, get_<name>() and set_<name>(value): GDScript
reaches no static property of a native class.
HammeriteDataFile.last_error # 1.x
HammeriteDataFile.get_last_error() # 2.0
HammeriteSkybox.dome_material = sky # 1.x
HammeriteSkybox.set_dome_material(sky) # 2.0
A constant that is not an integer becomes a static method of its name in lower case: ClassDB binds only
integer constants and enums. Integer constants and enums are unchanged (HammeriteBrush.VolumeType.AIR,
HammeriteMap.BakeState.BAKED, HammeriteCarving.PLANE).
HammeriteDataFile.MAP_EXTENSION # 1.x
HammeriteDataFile.map_extension() # 2.0
A const of your own made from one is a constant expression no longer, since a method call is not: make
it a static var or a literal.
const BASE: String = HammeriteReferences.BASE # 1.x
static var BASE: String = HammeriteReferences.base() # 2.0
The same goes for a match pattern, which has to be a constant: match the value itself (&"rotation").
An inner class becomes a class of its own, named owner and inner: GDExtension has no nested classes.
Change every type annotation, is, typed array and .new() that names one.
| 1.x | 2.0 |
|---|---|
HammeriteMap.BakeWarning |
HammeriteMapBakeWarning |
HammeriteMap.GraphWarning |
HammeriteMapGraphWarning |
HammeriteMap.LightingSnapshot |
HammeriteMapLightingSnapshot |
HammeriteMap.BVHHitResult |
HammeriteMapBVHHitResult |
HammeriteFace.UvAnchor |
HammeriteFaceUvAnchor |
HammeriteDataFile.ReadReport |
HammeriteDataFileReadReport |
HammeriteBVHBuilder.BVHNode |
HammeriteBVHBuilderBVHNode |
HammeriteSubtractiveCompiler.Result |
HammeriteSubtractiveCompilerResult |
HammeriteGizmoBuffer.Primitives |
HammeriteGizmoBufferPrimitives |
HammeritePrefab.Placement |
HammeritePrefabPlacement |
HammeriteLightmapBakeReport.PassSnapshot |
HammeriteLightmapBakeReportPassSnapshot |
HammeriteLightmapperDiagnosticReport.PassData |
HammeriteLightmapperDiagnosticReportPassData |
HammeriteLightmapper._Patch |
HammeriteLightmapperPatch (made with create(face, rect, world_rect, normal)) |
HammeriteLightmapper._BakedDecal |
HammeriteLightmapperBakedDecal |
HammeriteNavigationRuntime.Prepared |
HammeriteNavigationRuntimePrepared |
HammeriteAudioRuntime.Changes |
HammeriteAudioRuntimeChanges |
HammeriteAudioMaterialSampler.WallSurvey |
HammeriteAudioMaterialSamplerWallSurvey |
HammeriteAudioManager._SoundData |
HammeriteAudioManagerSoundData |
HammeriteAudioManager._PositionalSoundData |
HammeriteAudioManagerPositionalSoundData |
HammeriteAudioManager._EnvironmentalSoundData |
HammeriteAudioManagerEnvironmentalSoundData |
Core's, audio's and nav's other inner classes are internal: HammeriteMap.AuthoredFaces and VariantWorld (both
experimental in 1.x), HammeriteLightmapPacker.Group and Row, HammeriteLightmapperState.Grid,
HammeriteLightmapper._EdgeNeighbour, HammeriteDataFile._Reader and _Writer, the compiler's (below),
HammeriteAudioAmbience.Bed, HammeriteAudioNodeGraph._Search and HammeriteNavigationMeshWriter._RoomGround.
HammeriteEntitySets' own sets (Everything, Lights, Logic, Movers, Scenes, Particles) are
internal classes nothing outside names: make them with HammeriteEntitySets.lights() and the rest, as
before. Their constants moved onto HammeriteEntitySets: Logic.TINT is logic_tint(), Logic.RELAY_ICON
logic_relay_icon() (and TIMER_ICON, COUNTER_ICON, TOGGLE_ICON, AUTO_ICON likewise),
Movers.TINT movers_tint(), Scenes.EMPTY_BOX scenes_empty_box(), Particles.TINT particles_tint().
A constructor that takes arguments becomes static create(...): a native object is made with none. The
arguments are named for what they are (origin, not p_origin). Without arguments, new() still works.
HammeriteSkyPropertySchema.new(&"clouds", "Clouds") # 1.x
HammeriteSkyPropertySchema.create(&"clouds", "Clouds") # 2.0
A coroutine cannot be a native method. HammeritePrefab.generate_thumbnail() and
HammeritePrefabSet.regenerate_all_thumbnails() were coroutines; awaited, they answer as they did:
await prefab.generate_thumbnail(generator) # true once preview_texture is set, as in 1.x
await prefab_set.regenerate_all_thumbnails(generator)
The lightmapper's bake(), quick_bake(), prepare(), transfer() and write_lightmaps() were coroutines
too, and are awaited as before:
var lightmapper := HammeriteLightmapper.create(map, settings) # new(map, settings) in 1.x
lightmapper.yield_to = get_tree()
if await lightmapper.bake(progress) == OK:
HammeriteDataFile.write(map, path)
They run on a stack of their own on the main thread and give yield_to a frame where the script awaited one. What
they answer is their answer when they never had to wait for a frame, and otherwise the signal
HammeriteLightmapper.finished(result), which carries it. Their return type is Variant.
Not awaited, what the prefab methods answer is a Signal to await - HammeritePrefab.thumbnail_generated(has_thumbnail) and
HammeritePrefabSet.thumbnails_regenerated() - while a generator that is a coroutine is still drawing, and the
answer itself when it answered at once.
A script that extends a native class still does, and still overrides its virtuals; but it cannot call a
bare virtual on an object that does not override it, so a native class with one binds a public method that
calls it (HammeriteEntitySet.extend_editor(editor) for _extend_editor).
Containers are shared, as a script's were. A getter answers the object's own array or dictionary, typed
as before, so changing it in place is changing the object - entity.properties[&"name"] = "x" works as it
did. A typed array or dictionary of a moved class is typed by the class's name now, not by its script:
get_typed_class_name() answers &"HammeriteBrush" where get_typed_script() answered the script.
Class by class
Static variables
HammeriteMap.local_cache_directory→get_local_cache_directory()/set_local_cache_directory()HammeriteBrush.surface_material,sky_material→get_/set_each;chroma_bleed→get_chroma_bleed(), set with the existingset_chroma_bleed(value, map = null)HammeriteFace.looks_log→get_looks_log(), the log itself (cleared in place);looks_log_epoch→get_looks_log_epoch()/set_looks_log_epoch()HammeriteSubtractiveCompiler.parallel,verify_program→get_/set_eachHammeriteDataFile.last_error,last_warnings→get_/set_eachHammeriteSkybox.dome_material→get_dome_material()/set_dome_material()HammeriteTextureLibrary.search_paths,fallback_name,generation→get_/set_each (the arrayget_search_paths()answers is the library's own);HammeriteModelLibrary.library→get_library()/set_library()HammeriteNavigationRuntime.profiles→get_profiles()/set_profiles(), which warns of a bad table as the setter did. TheHammeriteNavigationautoload'sprofilesis unchanged.HammeriteAudioRuntime.changes,sound_types,mix_settings,materials,presets,material_resolver,ambient_resolver,soundsandambient_bus→get_/set_each:HammeriteAudioRuntime.get_sounds().search_paths = [...],HammeriteAudioRuntime.set_material_resolver(resolver). The setters do what assigning did (a new table reaches every manager, new presets declare the brush schema again). TheHammeriteAudioautoload's properties are unchanged. A multi-line lambda assigned to one is given a name first and passed to the setter.HammeriteAudioPortalProperties.NAMESPACE→get_namespace()
Constants that are methods now
HammeriteBrush:BRUSH_MATERIAL→stock_brush_material(),GHOSTED_BRUSH_MATERIAL→stock_ghosted_brush_material(),TRANSPARENT_BRUSH_MATERIAL→stock_transparent_brush_material(),CLIP_EPSILON→clip_epsilon(),SKY_MATERIAL→stock_sky_material(),VERTEX_WELD_EPSILON→vertex_weld_epsilon()HammeriteDataFile:MAP_EXTENSION→map_extension(),CACHE_EXTENSION→cache_extension(),PREFAB_SET_EXTENSION→prefab_set_extension(),_MAGIC→_magic(),_TAG→_tag()HammeriteDecalProjection:SURFACE_OFFSET→surface_offset(),ENTITY_CLASSNAME→entity_classname(),PLANE_TOLERANCE→plane_tolerance(),FACING_TOLERANCE→facing_tolerance()HammeriteEntity:EDITOR_ONLY_PREFIX→editor_only_prefix(),KEY_BOX_BASIS→key_box_basis(),KEY_ROTATION→key_rotation(),KEY_SCALE→key_scale(),LEAST_SCALE→least_scale()HammeriteEntityFiles:SCENES→scenes(),IMAGES→images()HammeriteEntitySets:LIGHTS→lights_id(),LOGIC→logic_id(),MOVERS→movers_id(),SCENES→scenes_id(),PARTICLES→particles_id(),EVERYTHING→everything_id()HammeriteEntityTypeRegistry:KEY_ROTATION_AXES→key_rotation_axes(),POINT_ENTITY_BASES→point_entity_bases(),BRUSH_ENTITY_BASES→brush_entity_bases()HammeriteFace:TEXELS_PER_UNIT→texels_per_unit(),_FORMER_NAMES→_former_names(),UV_LOCK_PROPERTY→uv_lock_property()HammeriteLightingProperties:SCHEMA_ID→schema_id(),KEY_CASTS_SHADOW→key_casts_shadow(),KEY_BAKE_STATIC→key_bake_static(),KEY_ENTITY_BAKE_STATIC→key_entity_bake_static(),KEY_ENTITY_CASTS_SHADOW→key_entity_casts_shadow(),DEFAULT_CASTS_SHADOW→default_casts_shadow(),DEFAULT_BAKE_STATIC→default_bake_static()HammeriteMap:BASE_ENTITY_PROPS→base_entity_props(),BOUNDARY_NUDGE→boundary_nudge(),CELL_HASH_CELL_SIZE→cell_hash_cell_size(),LIGHT_TYPES→light_types(),PROBE_GATHER_RADIUS_CELLS→probe_gather_radius_cells(),PARTIAL_BAKE_FINGERPRINT→partial_bake_fingerprint(),WALL_OCCLUDER_THICKNESS→wall_occluder_thickness(),VOID_WALLS_KEY→void_walls_key(),SLIVER_GAP_MAX→sliver_gap_max()HammeritePortal:PROPERTY_NAMESPACE→property_namespace(),NAME_FIELD→name_field()HammeriteReferences:TEXTURE→texture(),DECAL→decal(),MODEL→model(),ENTITY_CLASS→entity_class(),BASE→base()HammeriteSkybox:STOCK_DOME_MATERIAL→stock_dome_material(),_FORMER_NAMES→_former_names()HammeriteSubtractiveCompiler:EPSILON_DIST→epsilon_dist(),MIN_CONTACT_AREA→min_contact_area(),WALL_GRID_CELL_SIZE→wall_grid_cell_size(),EXPOSURE_OFFSET→exposure_offset(),EXPOSURE_INSET→exposure_inset()HammeriteWaterProperties:SCHEMA_ID→schema_id(),KEY_CLARITY→key_clarity(),KEY_TINT→key_tint(),KEY_DISTURBANCE→key_disturbance(),DEFAULT_CLARITY→default_clarity(),DEFAULT_TINT→default_tint(),DEFAULT_DISTURBANCE→default_disturbance()HammeriteShaderGlobals: every name,EXPOSURE→exposure(),ALL→all(),DEFAULTS→defaults()and so onHammeriteLightCurve:UNIFORM_LUT→uniform_lut()and the rest of theUNIFORM_*,MIN_LIT_LEVEL→min_lit_level()HammeriteTextureLibrary:DECALS→decals(),EXTENSIONS→extensions()HammeriteCompileProgress:STAGES→stages()HammeriteBrushFillRegistry:WATER→water(),STOCK_WATER_MATERIAL→stock_water_material()HammeriteVersion:STRING→string()HammeriteAABBGrid:DEFAULT_CELL_SIZE→default_cell_size()HammeriteGizmoBuffer:BOX_EDGES→box_edges()HammeriteTerrain:ID_PROPERTY→id_property(),CELL_PROPERTY→cell_property(),HALF_PROPERTY→half_property(),SPACING_PROPERTY→spacing_property(),MIN_THICKNESS→min_thickness(),UP_EPSILON→up_epsilon(),EDGE_EPSILON→edge_epsilon()(MAX_CELLSis an integer and stays)HammeriteSkyPresets:EARLY_MORNING→early_morning(),NOON→noon(),EVENING→evening(),DUSK→dusk(),NIGHT→night(),OVERCAST_GREYING→overcast_greying(),OVERCAST_LIGHT→overcast_light(),OVERCAST_SUN→overcast_sun(),TIMES→times()HammeriteBrushEntityLighting:BLEND_SECONDS→blend_seconds(),REGATHER_DISTANCE→regather_distance()HammeriteDecalSurface:COVERAGE_THRESHOLD→coverage_threshold()HammeriteLightmapLight:STATIC_LIGHT_TYPES→static_light_types(),DIRECTIONAL_LIGHT_TYPES→directional_light_types(),SPOT_LIGHT_TYPES→spot_light_types(),DEFAULT_DIRECTION→default_direction()HammeriteLightmapPacker:SHARED_ATLAS_FILL→shared_atlas_fill()HammeriteLightmapperAntialias:RANGE_SIGMA→range_sigma()HammeriteLightmapperDiagnosticReport:DEFAULT_DIRECTORY→default_directory()HammeriteLightmapperState:WATER_CLUSTER_SIZE→water_cluster_size(),CLUSTER_SIZE→cluster_size(),CLUSTER_NEAR→cluster_near()HammeriteMeshTriangleBVH:BOX_SLACK→box_slack()-
HammeriteLightmapper:_CAUSTIC_WATER_DEPTH_RANGE→_caustic_water_depth_range() -
HammeriteMap3D:NEAR_PLANE→near_plane(),FAR_PLANE→far_plane() HammeriteCarriedLight3D:METRES_PER_UNIT→metres_per_unit(),UNITS_PER_METRE→units_per_metre()(SHADOW_LAYER_NUMBERandSHADOW_LAYERare integers and stay)HammeriteSkyRenderer:SKY_MATERIAL→stock_sky_material(); its staticsky_material→get_sky_material()/set_sky_material()HammeriteDecal3D:DECAL_MATERIAL→decal_material();HammeriteSpotLight3D:UNBOUNDED_CONE_LENGTH→unbounded_cone_length()HammeriteStaticBrush3D:DETAIL_TINT→detail_tint();HammeriteAirBrushPreview3D:IDLE_COLOR→idle_color(),SELECTED_COLOR→selected_color()HammeritePropModel:BRUSH_MATERIAL→brush_material(),TEXTURE_KEY_PREFIX→texture_key_prefix();HammeritePropScene:EMPTY_BOX→empty_box()HammeriteThumbnailGenerator:THUMBNAIL_BACKGROUND→thumbnail_background(),DEFAULT_ENTITY_BOX→default_entity_box(),DEFAULT_ENTITY_TINT→default_entity_tint(),FRAMED_LOOSELY→framed_loosely(),FRAMED_TIGHTLY→framed_tightly()-
HammeriteEntityTargets:WIRE_COLOR→wire_color();HammeriteLogicEntity,HammeriteMover,HammeritePathCorner:TINT→tint();HammeriteLogicAuto,HammeriteLogicCounter,HammeriteLogicRelay,HammeriteLogicTimer,HammeriteLogicToggle:ICON→icon() -
HammeriteNavigationBuilder:MAX_WALKABLE_SLOPE_DEGREES→max_walkable_slope_degrees(),NAV_ROLE_KEY→nav_role_key()(PropRoleis an enum and stays) HammeriteNavigationLinkBuilder:DEFAULT_STEP_HEIGHT→default_step_height(),MAX_DROP→max_drop(),MAX_JUMP_SPAN→max_jump_span(),MAX_JUMP_RISE→max_jump_rise(),ENTITY_TYPE→entity_type(),TARGET_KEY→target_key(),NAME_KEY→name_key(),ONE_WAY_KEY→one_way_key()HammeriteNavigationLinkData:NO_PORTAL→no_portal()(Kindis an enum and stays);HammeriteNavigationAgentProfile:MEASURED_SHORT→measured_short()HammeriteNavigationBrushProperties:SCHEMA_ID→schema_id(),KEY_TRAVEL_COST→key_travel_cost(),DEFAULT_TRAVEL_COST→default_travel_cost()HammeriteNavigationRuntime:STAGES→stages(),DERIVED_KEY→derived_key()(CACHE_VERSIONis an integer and stays)HammeriteNavigationMeshWriter:LINK_NAME_META→link_name_meta()(DEFAULT_LAYERSstays);HammeriteNavigationFloorEdges:BUCKET_SIZE→bucket_size()HammeriteNavigationOverlay3D:LIFT→lift(),OPEN_COLOR→open_color(),CRAMPED_COLOR→cramped_color(),UNUSABLE_COLOR→unusable_color(),FALLBACK_CRAMPED_CLEARANCE→fallback_cramped_clearance();HammeriteNavigationTool.CRAMPED_CLEARANCE, made of it, iscramped_clearance()
A key used as a match pattern has to be a constant: match the property's own name (&"nav_link_target"), or compare
against HammeriteNavigationLinkBuilder.target_key() outside the match.
HammeriteAudioRuntime:GRAPH_KEY→graph_key(),AMBIENCE→ambience(),SOUND_FILE→sound_file()HammeriteAudioBrushProperties:SCHEMA_ID→schema_id(),KEY_ZONE_TYPE→key_zone_type(),KEY_PRESET→key_preset(),KEY_WEATHER_EXPOSURE→key_weather_exposure(),KEY_EXCLUDE→key_exclude(),KEY_AMBIENT→key_ambient(),KEY_AMBIENT_VOLUME→key_ambient_volume()(PRESET_AUTOandZoneTypeChoicestay)HammeriteAudioManager:BUS_NAME→bus_name(),_SILENT_DB→_silent_db(),_MIN_PREDELAY_MSEC→_min_predelay_msec(); a game'sconstmade ofBUS_NAMEis astatic varHammeriteAudioCalculations:SPEED_OF_SOUND,AIR_ABSORPTION_COEFFICIENT,OPEN_AIR_CUTOFF_HZ,MIN_CUTOFF_HZ,OCCLUSION_DB_PER_OCTAVE,DETOUR_UNITS_PER_OCTAVE,AIR_UNITS_PER_OCTAVE→ the same in lower case (open_air_cutoff_hz()...)HammeriteAudioWater:SURFACE_LOSS_DB→surface_loss_db(),SURFACE_CUTOFF_HZ→surface_cutoff_hz(),UNDERWATER_CUTOFF_HZ→underwater_cutoff_hz()HammeriteAudioZone:METRES_PER_UNIT→metres_per_unit(),SPEED_OF_SOUND→speed_of_sound()(ZoneTypestays)HammeriteAudioMaterialSampler:SKY→sky(),OPEN_AIR_SKY_SHARE→open_air_sky_share(),SMALL_ROOM_SIZE→small_room_size(),LARGE_ROOM_SIZE→large_room_size(),CORRIDOR_ASPECT→corridor_aspect(),CORRIDOR_MAX_WIDTH→corridor_max_width()HammeriteAudioInterpolator:PRESET_BLEND_RADIUS→preset_blend_radius();HammeriteAudioPortalProperties:DEFAULT_MAX_ATTENUATION_DB→default_max_attenuation_db(),DEFAULT_OCCLUSION→default_occlusion()
Made with create()
HammeriteDecalProjection.create(origin, normal, size, angle), HammeriteBrushPropertySchema.create(id,
label = ""), HammeriteSkyPropertySchema.create(id, label = ""), HammeriteDataFileWrite.create(...),
HammeriteBrushFill.create(...), HammeriteReferenceChange.create(...), HammeriteEditorHandle.create(...),
HammeriteQuad3D.create(...), HammeriteOrientedBoundingBox.create(...), HammeriteAABBGrid.create(...),
HammeriteEntityBox.create(...), HammeriteAssetLibrary.create(type, extensions, convert),
HammeriteVertex.create(position, faces = []), HammeriteBakeOccluder.create(owner_entity, world_vertices),
HammeriteBrushEntityLighting.create(node, drives_itself = false), HammeriteRoomVisibility.create(map),
HammeriteWorldrepCompile.create(map), HammeriteLightmapper.create(map, bake_settings = null),
HammeriteLightmapperState.create(map), HammeriteLightmapLight.create(entity),
HammeriteLightmapPacker.create(texture_size, padding), HammeriteLightmapFaceData.create(face, bounds, world_bounds,
verts_3d, verts_2d, lightmap_scale), HammeriteMeshChartData.create(entity, chart_index, triangles),
HammeriteMeshTriangleData.create(entity, tri_index, surface_index, vertices, lightmap_scale, uvs = [], texture = null,
normal = Vector3.ZERO), HammeriteLightmapperPatch.create(face, rect, world_rect, normal),
HammeriteStaticBrush3D.create(brush), HammeriteAirBrushPreview3D.create(brush),
HammeriteAudioMaterial.create(name, reverb, absorption, transmission_loss, freq_bias, category),
HammeriteAudioPreset.create(id, name, room_size, damping, spread, wet, dry, abs_low, abs_mid, abs_high),
HammeriteAudioNode.create(node_id, pos), HammeriteAudioHearing.create(mixer), HammeriteAudioAmbience.create(map,
parent) - every argument with the default it had.
Other signatures
HammeriteMap.native_cell_index()answers aRefCountedrather than anObject. Handed out as a bareObject, a reference-counted index lost a reference each time a script asked for it.HammeriteLayer's name is itsnameproperty as before; its accessors are_get_name()/_set_name(), so as not to hideResource.get_name().-
HammeriteBrushEntity._brusheskeeps its name - it is what a file stores - with_get_brushes()/_set_brushes(), answering the stored array;get_brushes()answers a copy, as before. -
HammeriteEntityTypeRegistry.is_entity_class(class, brush)takes a class's name (&"HammeriteSpotLight3D") as well as a script, andentity_classes()lists the native entity classes beside the scripts'. - The thumbnail generator's
generate_thumbnail(),generate_entity_thumbnail()andgenerate_mesh_thumbnail()were coroutines: each answers the picture at once where it has it, and otherwise a signal to await - awaited, as before. HammeriteBrush3DHelper.BrushFolloweris the internal classHammeriteBrushFollower, which a script cannot name.HammeritePlatform.pathandHammeritePathCorner.nextkeep their names; their accessors areget_path_name()/set_path_name()andget_next_name()/set_next_name(), sinceNodehasget_path().HammeriteAudioPreset,HammeriteAudioZoneandHammeriteAudioPortalkeep theirnameproperty; its accessors are_get_name()/_set_name(), so as not to hideResource.get_name().- A script on
HammeriteEnvSoundorHammeriteEnvSoundEnvironmentoverrides_play_sound(), a virtual now, and callsplay_sound()- the class's own - where it calledsuper(). It dropssuper()from_apply_entity_property(the class applies its own properties first) andsuper(delta)from_process(the class does its frame from its notification). The privates a game reached are bound under their own names:_sound_file,_volume,_autoplay,_loop,_sound_handle,_is_simulating,_runtime_properties, and_max_distance,_attenuation_scale,_use_audio_propagation,_debug_drawor_direction;_stop_sound()and_get_map_3d()are bound methods.
```gdscript # 1.x func _play_sound() -> void: _sound_file = pick_a_recording() super()
# 2.0
func _play_sound() -> void:
_sound_file = pick_a_recording()
play_sound()
``
- **HammeriteAudioReceiver3DandHammeriteAudioEmitter3D** do their tree and frame work from notifications, so a
script on one keeps its own_enter_tree,_ready,_processand_exit_treeand cannot callsuper()in them.
A receiver registers again once ready, after a script's_readyhas set its types, which is whatsuper()at the end
of_ready` was for: drop it.
The native kernel's classes and switches
1.x's native kernel was optional: a set of HammeriteNative* classes that GDScript called where one was built,
each behind a switch that turned it off. In 2.0 the library is the classes, so the kernel's classes are their C++
and the switches are gone with the GDScript they chose between. None of it was supported API - the classes were
undocumented and the switches tagged experimental - and there is no project setting to remove: 1.x had none.
| 1.x kernel class | In 2.0 |
|---|---|
HammeriteNativeKernel, and HammeriteNative.KERNEL_VERSION, KERNEL_SOURCE, KERNEL_CLASS, OLDEST_CLASS and verdict() |
HammeriteLibrary: the package the library was built as (package()), its modules(), and the hash of the sources it was built from (source()), which HammeriteNative.problem() compares with a checkout's. There is no version to raise: tools/build_native.sh --bump is gone, and HammeriteNative.source_hash() takes the modules too. Both are experimental |
HammeriteNativeAABBGrid |
HammeriteAABBGrid itself |
HammeriteNativeCarver, HammeriteNativeWalls, HammeriteNativePortals |
HammeriteSubtractiveCompiler's own C++ |
HammeriteNativePickIndex, HammeriteNativeOccluders |
HammeriteMap's own C++ |
HammeriteNativeCellIndex |
still registered, as the index HammeriteMap.native_cell_index() answers (a RefCounted); internal |
HammeriteNativeBrushes |
still registered, as HammeriteBrush's corners; internal |
HammeriteNativeProbeGrid |
HammeriteLightProbeSet's own C++ |
HammeriteNativeTexels, HammeriteNativeGather, HammeriteNativeAtlas |
the lightmapper's own C++ |
HammeriteNativeSoundRoutes, HammeriteNativePortalWalks |
HammeriteAudioNodeGraph's and HammeriteAudioGraphBuilder's own C++, in the audio module |
HammeriteNativeNavGround, HammeriteNativeNavLinks |
HammeriteNavigationFloorEdges' and HammeriteNavigationLinkBuilder's own C++, in the nav module; HammeriteNativeNavLinks.probe() is HammeriteNavigationLinkBuilder._probe() |
HammeriteNativeScreenLines |
HammeriteScreenLines' own C++, in the editor module |
Kernel classes added after 1.0 went the same way: HammeriteNativeDataReader (HammeriteDataFile),
HammeriteNativeRoomMesh (HammeriteMap3D), HammeriteNativeSurfaceJoins (the compiler), and
HammeriteNativeLegacyResources, whose reading of 1.x files is HammeriteMigration's now. HammeriteNative
itself stays a script, experimental, saying whether the library is loaded and current (available, has(),
problem(), package(), modules()).
| 1.x switch | the kernel class it named |
|---|---|
HammeriteAABBGrid.use_native, NATIVE_CLASS |
HammeriteNativeAABBGrid |
HammeriteBrush.native_corners, NATIVE_BRUSHES |
HammeriteNativeBrushes |
HammeriteMap.native_cells, NATIVE_CELL_INDEX |
HammeriteNativeCellIndex |
HammeriteMap.native_picking, NATIVE_PICK_INDEX |
HammeriteNativePickIndex |
HammeriteMap.native_occluders, NATIVE_OCCLUDERS |
HammeriteNativeOccluders |
HammeriteSubtractiveCompiler.native_walls, native_carving, native_portals and their NATIVE_WALLS, NATIVE_CARVER, NATIVE_PORTALS |
the walls, carver and portals |
HammeriteLightProbeSet.native_grid, NATIVE_PROBE_GRID |
HammeriteNativeProbeGrid |
HammeriteLightmapperAntialias.use_native, NATIVE_ATLAS |
HammeriteNativeAtlas |
HammeriteLightmapperState.native_gather, NATIVE_GATHER |
HammeriteNativeGather |
HammeriteLightmapper._native_texels, _NATIVE_TEXELS, _native_atlas |
HammeriteNativeTexels, HammeriteNativeAtlas |
HammeriteAudioNodeGraph.native_routes, NATIVE_SOUND_ROUTES |
HammeriteNativeSoundRoutes |
HammeriteAudioGraphBuilder.native_walks, NATIVE_PORTAL_WALKS |
HammeriteNativePortalWalks |
HammeriteNavigationFloorEdges.native, NATIVE_KERNEL |
HammeriteNativeNavGround |
HammeriteNavigationLinkBuilder._native_jumps, _NATIVE_NAV_LINKS |
HammeriteNativeNavLinks |
HammeriteScreenLines.native_lines, NATIVE_SCREEN_LINES, native_screen_lines() |
HammeriteNativeScreenLines |
And those added after 1.0: HammeriteSubtractiveCompiler.native_joins, HammeriteDataFile.native_fill,
HammeriteMap3D.native_room_mesh, NATIVE_ROOM_MESH, _use_native_rooms and _inward_surfaces_natively(). What
the suites held each kernel to against the GDScript is now a fixture of what the GDScript answered, recorded
before it went (tests/fixtures/kernels.json in core, audio, nav and the editor).
What the suites reached
Private members are not API, but a game reaching into one should know where it went.
- Bound under the same name:
HammeriteMap._worldrep_compiler,_worldrep_valid,_graph_valid,_lighting_memo,_void_chunks,_sliver_bounds,_sliver_gap_of,_rebuild_baked_light_registry(),_as_variant(),_face_address(),_read_worldrep_cache(),_middles_of(),_sliver_gaps();HammeriteBrush._fill_uniforms();HammeriteFace._plane,_texture,_lightmap,_uv_transform,_lightmap_scale,_brush;HammeriteSubtractiveCompiler._program_memo,_brush_volume(),_air_regions(),_punched(),_section();HammeriteDataFile._replace_file(). - Bound under the same name, the lightmapper's:
HammeriteLightmapper._state,_packer,_map,_lightmaps,_rd,_quick,_decals,_mesh_charts,_mesh_triangles_in(read-only where only read),_get_faces(),_unwrap_mesh_entity(),_apply_decals(),_sky_radiance(),_report_bake_warnings(),_save_diagnostic_image(),_swizzle_mesh_triangle_light_assignments()and the statics_fold_light(),_padding_light(),_padding_sample_point(),_permute_patch_slots(),_caustic_water_color(),_dilate_caustic_water(),_baked_light_of(),_write_face();HammeriteLightmapperState._face_exterior_cache,_mesh_bvh,_pass_faces,_water_emitter_rows,_face_is_exterior(),_fill_exterior_cache(),_gather_grids()and the statics_face_transparency(),_face_uv_bytes(),_mask_layer_size();HammeriteLightmapPatches._faces,_face_of,_triangle_of,_texture_rects,_world_rects,_normals,_areas,_texture_centers,_flags,_padding_lights(read-only);HammeriteLightmapLight._sky_followed(). The rest of their private members are their own C++. - Changed:
HammeriteMap._variant_worlds[id].compiler→_variant_compiler(id);HammeriteSubtractiveCompiler._solid_frag_cacheand_air_frag_cache→_carve_fragments()(every cached fragment) and_carve_serial(brush_id)(0 when not cached, a number that changes on each carve);HammeriteBrush._warned_undeclared→_get_warned_undeclared();HammeriteDataFile._MAGIC,_TAG→_magic(),_tag();HammeriteDataFile._upgrades→_get_upgrades();HammeriteReferences._resolvers→_get_resolvers();HammeriteBakeOccluders._providers→_get_providers();HammeriteWorldrepCompile._stages→_get_stages()(a copy, each stage[names, run]as before) and_under_way→_get_under_way(). -
Gone:
HammeriteMap._pick_index,_rebuild_cell_hash(); the compiler's_bface_cache,_kept_by_air,_air_region_grid(),_classify_fragment_faces(),_kept_owners(),FaceEntry,WallMachineryand the rest of its inner classes, which are its own C++. -
The node classes: what a test drove a frame with is a method of its own, since a native class answers
_processas a notification:HammeriteMap3D._run_frame(delta),HammeriteDynamicLight3D._run_frame(delta), and_step(delta)on the logic entities and the movers (their_processand_physics_process). The privates the suites read are bound under their own names (HammeriteMap3D._entity_index,_room_meshes,_cull_from()...), as properties where they were variables.HammeriteMap3D.native_room_mesh,NATIVE_ROOM_MESH,_use_native_roomsand_inward_surfaces_natively()are gone with the script they chose against, andHammeriteNativeRoomMeshis the map's own C++, no longer registered. -
hammerite-nav (#270):
HammeriteNavigationFloorEdges.nativeandNATIVE_KERNEL, andHammeriteNavigationLinkBuilder._native_jumpsand_NATIVE_NAV_LINKS, are gone with the GDScript they chose between, andHammeriteNativeNavGroundandHammeriteNativeNavLinksare nav's own C++, no longer registered; what the suite held them to ishammerite-nav/tests/fixtures/kernels.json, recorded from the GDScript. The arithmetic checkHammeriteNativeNavLinks.probe()isHammeriteNavigationLinkBuilder._probe(), and moved from core's suite to nav's.HammeriteNavigationRuntime._attached→_get_attached(), the dictionary itself;HammeriteNavigationMeshWriter._BODY_SLACK→_body_slack(). Bound under the same name:HammeriteNavigationLinkBuilder._index_surfaces(),_window_links(),_drop_links(),_jump_links(),_authored_links()and_obstructions,HammeriteNavigationAgentProfiles._values_of(),HammeriteNavigationLinkEntity3D._labeland_editor_active. Gone: the link builder's_linked_pairs, the GDScript fallbacks the kernels had replaced (_furthest_from,_edges_near,_weld_index,_split_edges,_closest_points,_crossing_is_open,_ground_between) and the mesh writer's_RoomGround. -
hammerite-audio (#269):
HammeriteAudioNodeGraph.native_routesandNATIVE_SOUND_ROUTES, andHammeriteAudioGraphBuilder.native_walksandNATIVE_PORTAL_WALKS, are gone with the GDScript searches they chose between, andHammeriteNativeSoundRoutesandHammeriteNativePortalWalksare audio's own C++, moved out of core and no longer registered; what the suite held them to ishammerite-audio/tests/fixtures/kernels.json, recorded from the GDScript. Bound under the same name: the manager's_active_sounds,_audio_graph,_listener_position,_ambienceand most of its private methods (_hearing_path(),_voice_bus(),_voice_cutoff(),_apply_absorption_tilt(),_hash_position_pair(),_use_graph(),_get_or_load_stream()...); the emitter's and the receiver's_handleand_manager(read-only); the graph'snode_map,zone_by_regionandspatial_index. The graph's_rank,_id_at,_preset_by_idand_Search, and the builder's private steps, are their own C++. -
hammerite-editor (#271):
HammeriteScreenLines.native_linesandnative_screen_lines()are gone, and core'sHammeriteNativeScreenLineswith them: the editor'sHammeriteScreenLineslays its lines itself, and what the suite held the kernel to ishammerite-editor/tests/fixtures/kernels.json, recorded from the script. The editor's private members are its own C++, but for those its suites and the audio and nav editor tools reach, which are bound under the same names. A property the script wrote plainly, beside aset_<name>()that does more (a brush tool's rememberedsides, whichset_sides()makes an undo step of; the map editor'sactive_tool, whichset_active_tool()switches), has_set_<name>_value()as its setter.
Experimental classes
The port kept the experimental classes' API as it kept the supported ones', with the same shapes changed. What else changed in them between 1.0 and 2.0, beside new members and arguments added with defaults:
HammeriteBrushTooland the brush tools (the cube, cylinder, cone, ramp, stair, arch and polygon tools): theiron_*steps (on_update_bounding_box(),on_finish()...) are the classes' own and not virtuals, so a script cannot override them, and one that does does not compile. A tool of a game's own extendsHammeriteEditorTool.on_bounding_box_resized()is gone: the tool callson_bounding_box_changed()and shows the size itself. The cylinder tool's Inverse is gone (inverse,inverse_brushes,set_inverse(),update_inverse_brushes()): an air cylinder is the round hole it made.HammeriteClipTool:finish_pick_points_state()is gone, andadd_preview_brush(brush)takes no source brush id.HammeriteSubtractiveCompiler.surface_edge_key()is gone: a surface's edges are keyed by their face and their index in its vertices (HammeriteMap.get_worldrep_surface_edges()).HammeriteLightmapPacker.add_face()answers nothing, andget_texture_size()aVector2.HammeriteMapEditorCore.KEY_ROTATION_AXESisHammeriteEntityTypeRegistry.key_rotation_axes(), andHammeriteDecalTool.DECAL_CLASSNAMEHammeriteDecalProjection.entity_classname().- Constants that held a loaded resource are gone, each class loading its own:
HammeriteEntity2D.FONT,HammeriteMap2DGizmos.font,HammeriteGizmoRenderer3D.OUTLINE_MATERIAL,HammeriteScreenLines.SHADER, andHammeriteVertexGizmo.HANDLE_TEXTUREandHANDLE_TEXTURE_SELECTED. HammeriteFaceEditorPopup.UV_LOCK_DEFAULT,UV_LOCK_ONandUV_LOCK_OFFare integer constants of the same values, no longer an unnamed enum.HammeriteNative(above).
Behaviour
- A moved class has no script.
get_script()is null, andget_class()answers the class's own name rather than its native base's.is HammeriteMapworks as before. - Every bake made before this reads STALE once, and wants baking again, if its map has a sky. A sky's
part of the lighting fingerprint (
HammeriteMap.lighting_fingerprint(), whichget_bake_state()compares with the one a bake recorded) was every stored property of the skybox, by name and in its script's order, the script's own uid and path among them - so renamingcolourtocolordated every bake there was, though nothing lit had changed. It is now what the bake reads of the sky, worked out as the lightmapper works it out, in a fixed order under a tag that says which line it is (sky2|...): what a sky aperture emits (ambient_color()in linear colour timeslight_energy), whether that light claims a slot of its own and with which group (light_is_dynamic,light_group), and - only when a directional light the bake reads follows the sky - the sun's direction, colour and energy. A rename, a property added, the sky's name, its model and where it is seen from, a game's own sky properties and a sun nothing follows date no bake from now on; a change to what the bake reads of the sky still does, and changing what it reads changes the tag. The brushes' and entities' parts of the fingerprint, and the program fingerprint, are unchanged to the bit, so a map with no sky reads as it did. HammeriteEntitySetis a virtual class:HammeriteEntitySet.new()succeeds where the@abstractscript refused, and a set with no_register_typesfails when it is added.HammeriteEntitySets.any_nameand the other providers can no longer be passed as aCallablevalue from GDScript: GDScript cannot make aCallableof a native static method.- The registries convert some bad values where the scripts raised a script error:
String()of a non-string_editor_rotation_axes,bool()of a null or a stringcasts_shadow/bake_static,float()of a non-number clarity. HammeriteBrush.volume_typeandinterior_exteriorare 32-bit enums: a file holding a value beyond 32 bits reads back as another. Only absurd values are affected.- The data file keeps GDScript's typed-member refusals when reading a class that was a script: a value of the wrong type leaves the member alone rather than being converted, so old files read as they did.
HammeriteAABBGrid.query_afterwithafterbelow -1 no longer answers -1.HammeritePrefabandHammeritePrefabSet: a 1.x.tresor.resof a prefab or a set, its array typed by the prefab's script, is migrated to the native classes.HammeriteBakeOccluder.from_meshreads a surface of anArrayMeshthat has no index array straight through, as it always said it did; the script stopped on a script error there and answered null.HammeriteTerrain.convertof a brush whose top has no corners is an error and answers no prisms, where the script stopped on a script error.HammeriteTerrain.of()answers a plainnullfor a brush that is not terrain, which compares as the script's did.- A
Resourceof a moved class opened in the Godot editor runs its constructor there now: a newHammeriteMapmade in the inspector has its default layer. - Property docs: an inspector reading a class's
##comments out of its script (HammeritePropertyDocs) has no script to read for a moved class; its words are in the class reference, Godot's own help. - Speed: nothing answers differently, but sooner. The compile benchmark's 256 rooms compile in 303 ms rather than 626, and a one-brush edit in 25 rather than 42; the persist benchmark's largest loads from a .res in 113 ms rather than 220.
- A null an entity's signal hands on -
HammeriteTrigger.fired(by)with nobody,HammeriteMap3D.map_changedwith no map - is a plainnull, as the scripts' was. map_3d.gdandeye_adaptation_3d.gdare gone: a 1.x scene that names them by path is migrated to name the class (type="HammeriteMap3D"), as a scene saved since does.- hammerite-nav's classes are native (#270): the ground, the links, the profiles and their table, the report, the
brush properties, the floor's edges, the cache, the mesh writer, the runtime and the link entity, in the library's nav
module, and the overlay the Navigation tool draws in its nav_editor module, which only the full package has. The
HammeriteNavigationautoload,HammeriteNavigationToolandHammeriteNavigationEditorExtensionfollowed with the editor (The editor). A table of profiles or a.nav.res1.x saved is migrated to the native class. A navigation cache 1.x saved is taken up as it was: every fingerprint is worked out to the byte as the scripts worked it out, and a.nav.hcachethe native classes save is the scripts' file byte for byte. - A
.nav.rescache comes back without its report's warnings, as in 1.x: a resource keeps no array typed inside a dictionary, and the report takes itswarningsonly as anArray[String], as the script's member did when set by name. Assigning an untyped array toHammeriteNavigationBakeReport.warningsleaves it as it was, where the script raised an error. - Navigation is built in half the time or less (
HammeriteNavigationRuntime.prepare()): a Thief mission's 5.7 s is 2.8 s, a smaller one's 1.5 s is 0.56 s. Reading a saved cache costs what it did, most of it the fingerprint and the data file. - hammerite-audio's classes are native (#269), in the library's audio module,
HammeriteEnvSoundandHammeriteEnvSoundEnvironmentas native subclasses ofHammeritePointEntityNode3D. TheHammeriteAudioautoload,HammeriteAudioPortalToolandHammeriteAudioEditorExtensionfollowed with the editor (The editor). A graph baked into a 1.x map, or a preset, material, mix or sound table saved by 1.x, is migrated to the native class.HammeriteAudioGraphBuilder.fingerprint()is the script's to the byte, so a graph 1.x baked reads current where it did. - A native audio class has no script to read its property docs from (
HammeritePropertyDocs): its words are in the class reference. - An audio method given a null map refuses it with an error and returns what the script's call would have, where 1.x raised the error from the line that dereferenced it.