Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,54 @@ The format is based on Keep a Changelog, and this project follows semantic versi
has not been verified, and deleting them would lose that while making the
document look healthier.

### Removed
- **Fifty-seven private functions and nine fields that nothing used** (#609,
#610). `plugin.gd` and `level_root.gd` are documented as thin coordinators
whose named one-line delegates exist to be called by name, and the rule beside
that is that a delegate with no caller gets deleted. These had drifted past it.
The whole viewport drop path in `plugin.gd` was a second layer: Godot calls
`_can_drop_data` and `_drop_data`, those hand straight to
`plugin_drop_handler.gd`, and its own `drop_data()` dispatches the four payload
kinds itself, so the eight wrappers in front of that dispatch were reachable
from nothing.

Five architecture tests were keeping much of this alive, which is the more
useful half of the finding. Each enumerates a module's methods and asserts
`plugin.gd` contains a delegation string for every one, and the lists had grown
to include helpers the modules call themselves: `update_preview`,
`apply_value`, `do_displacement_stroke`, `point_near_polygon_3d`,
`update_prefab_hover`, `move_selected_vertical`, `normalize_editor_selection`,
`expand_native_group_selection`, `same_node_selection`,
`sync_hf_selection_if_empty`, `face_screen_center`, `show_quick_property`,
`ensure_vertex_overlay`. The only way to satisfy the assertion was a wrapper
nothing called, so tests written to enforce that `plugin.gd` stays thin were
requiring it to be thicker. Each list is now the entry points `plugin.gd`
actually owns, and the drop test additionally asserts that `plugin.gd` does not
contain the payload type strings, which is the property "thin delegate" was
reaching for and the enumeration never checked.

`HFPluginSelectionState.selection_has_brush()` and `selection_has_entity()` went
too. Their only caller was the dead wrapper, so removing it made them provably
dead in the same pass.

Two of the fields are public on registered custom types, so both are a break
for any script that touched them, and both earn it. `DraftEntity.entity_properties`
was a second name for `entity_data` that nothing in the plugin used, and two
names for one dictionary can only ever diverge. `LevelRoot.drag_active` is the
worse of the two: its setter called `input_state.cancel()` while the canonical
`cancel_drag()` is `input_state.cancel()` **and** `_clear_preview()`, so setting
`drag_active = false` did half a cancel and left the preview brush orphaned in
the scene. It was a latent bug rather than dead weight. `LevelRoot.grid_plane_axis`
and `dock.gd`'s `_entity_props_entity` were written and never read, so the
writes went with the declarations.

`map_io.gd`'s `_format_face_line()` was a drifted second copy of the `.map`
face line: it takes three arguments and hard-codes the texture and the
`0 0 0 1 1` tail, while the three adapters take `(a, b, c, texture, face_data)`
and read real UV data off `FaceData`. Nothing could have called it even by
accident, and a second copy of the export format is a trap for whoever fixes
the exporter next.

### Fixed
- **A visgroup can be renamed, a prefab variant deleted, a displacement's power
changed** (#615). Three level-editing operations were implemented, carefully,
Expand Down
2 changes: 1 addition & 1 deletion DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ The project has a GitHub Actions workflow (`.github/workflows/ci.yml`) that runs
- `gdformat --check` -- verifies formatting
- `gdlint` -- checks lint rules (configured in `.gdlintrc`)
- `tools/check_placement_order.py` -- refuses a world transform written to a node that is not in the tree yet
- **GUT unit + integration tests** -- 4,084 tests across 221 test scripts (4,077 passing plus seven intentional no-assert safety tests; 19,725 assertions; verified in CI on September 16, 2026; runs Godot headless)
- **GUT unit + integration tests** -- 4,084 tests across 221 test scripts (4,077 passing plus seven intentional no-assert safety tests; 19,707 assertions; verified in CI on September 16, 2026; runs Godot headless)

Run locally before pushing:
```
Expand Down
2 changes: 1 addition & 1 deletion HammerForge_SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,6 @@ Unit tests use the [GUT](https://github.com/bitwes/Gut) framework and run headle
| `test_selection_gesture.gd` | 40 | Native widget/Object Select ownership, modal Face Select, recovery, focus/scope guards, native duplicate/reparent repair, and Inspector/undo change tracking |
| `test_viewport_outlines.gd` | 39 | Sparse semantic outlines, exact/composite entity collision, visibility/transforms, and shape-aware resize recovery |

Full suite (verified in CI on September 16, 2026): **4,084 tests** across **221 scripts** (**4,077 passing** plus seven intentional no-assert safety tests; **19,725 assertions**).
Full suite (verified in CI on September 16, 2026): **4,084 tests** across **221 scripts** (**4,077 passing** plus seven intentional no-assert safety tests; **19,707 assertions**).

Tests use root shim scripts (dynamically created GDScript) to provide the LevelRoot interface without circular preload dependencies. Configuration in `.gutconfig.json`.
8 changes: 0 additions & 8 deletions addons/hammerforge/brush_instance.gd
Original file line number Diff line number Diff line change
Expand Up @@ -1509,13 +1509,5 @@ func _discard_private_visual(node: Node) -> void:

# Compatibility entry points for editor code or third-party tools that called
# the previous private helpers directly.
func _apply_brush_entity_overlay() -> void:
_sync_visual_overlays()


func _apply_subtract_wireframe_overlay() -> void:
_sync_visual_overlays()


func _apply_additive_wireframe_overlay() -> void:
_sync_visual_overlays()
88 changes: 0 additions & 88 deletions addons/hammerforge/dock.gd
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,6 @@ var active_shape: int = LevelRootType.BrushShape.BOX
var shape_id_to_key: Dictionary = {}
var paint_layers_signature: String = ""
var materials_signature: String = ""
var surface_paint_signature: String = ""
var root_properties: Dictionary = {}
var history_entries: Array = []
var history_max := 50
Expand Down Expand Up @@ -549,8 +548,6 @@ var _io_wiring_section: VBoxContainer = null
# Entity Properties controls
var _entity_props_section: VBoxContainer = null
var _entity_props_controls: Array = []
var _entity_props_entity: Node3D = null

# Displacement / Bevel UI controls
var _disp_section: HFCollapsibleSection = null
var _disp_power_spin: SpinBox = null
Expand All @@ -574,10 +571,6 @@ var _bevel_inset_dist_spin: SpinBox = null
var _bevel_inset_height_spin: SpinBox = null


func _is_level_root(node: Node) -> bool:
return node != null and node is LevelRootType


func _find_level_root_in(scene: Node) -> Node:
if not scene:
return null
Expand Down Expand Up @@ -1074,15 +1067,6 @@ func _on_paint_mode_toggled(enabled: bool) -> void:
builtin_tool_changed.emit()


func _on_welcome_dismissed(dont_show_again: bool) -> void:
if dont_show_again and _user_prefs:
_user_prefs.set_pref("show_welcome", false)
_user_prefs.save()
var tabs = $Margin/VBox/MainTabs
if tabs:
tabs.visible = true


## Persist a pref change to disk.
func _save_user_pref(key: String, value: Variant) -> void:
if not _user_prefs:
Expand Down Expand Up @@ -1329,14 +1313,6 @@ func _find_editor_icon(icon_names: Array) -> Texture2D:
return HFEditorTheme.find_editor_icon(editor_base_control, self, icon_names)


func _has_editor_icon(icon_name: String) -> bool:
return HFEditorTheme.has_editor_icon(editor_base_control, self, icon_name)


func _get_editor_icon(icon_name: String) -> Texture2D:
return HFEditorTheme.get_editor_icon(editor_base_control, self, icon_name)


func _get_editor_color(color_name: String, fallback: Color) -> Color:
return HFEditorTheme.get_editor_color(editor_base_control, self, color_name, fallback)

Expand Down Expand Up @@ -1429,10 +1405,6 @@ func _build_paint_tab() -> void:
builder.build(root_vbox)


func _build_entity_props_section() -> void:
pass # Now built by EntityTabBuilder


func _rebuild_entity_props(entity: Node3D) -> void:
HFDockEntityHandler.rebuild_entity_props(self, entity)

Expand Down Expand Up @@ -1461,10 +1433,6 @@ func _can_edit_selected_entity(entity: Node3D) -> bool:
return HFDockEntityHandler.can_edit_selected_entity(self, entity)


func _entity_prop_default(type_name: String, value: Variant) -> Variant:
return HFDockEntityHandler.entity_prop_default(type_name, value)


# ---------------------------------------------------------------------------
# External Tool Settings — auto-generated UI from HFEditorTool.get_settings_schema()
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -3194,10 +3162,6 @@ func _on_bake_dry_run() -> void:
HFDockManageHandler.on_bake_dry_run(self)


func _get_bake_preview_mode() -> int:
return HFDockManageHandler.get_bake_preview_mode(self)


func _on_bake_selected() -> void:
await HFDockManageHandler.on_bake_selected(self)

Expand All @@ -3210,10 +3174,6 @@ func _on_bake_check_issues() -> void:
HFDockManageHandler.on_bake_check_issues(self)


func _update_bake_estimate() -> void:
HFDockManageHandler.update_bake_estimate(self)


func _on_validate_level() -> void:
HFDockManageHandler.on_validate_level(self)

Expand Down Expand Up @@ -3404,14 +3364,6 @@ func _on_create_entity() -> void:
HFDockEntityHandler.on_create_entity(self)


func _focus_entity_selection(entity: Node) -> void:
HFDockEntityHandler.focus_entity_selection(self, entity)


func _get_default_entity_definition() -> Dictionary:
return HFDockEntityHandler.get_default_entity_definition(self)


func _connect_root_signals() -> void:
HFDockConnections.connect_root(self)

Expand Down Expand Up @@ -3616,30 +3568,10 @@ func _on_quick_play_selected_area() -> void:
await HFDockManageHandler.on_quick_play_selected_area(self)


func _restore_cordon_state(enabled: bool, bounds: AABB) -> void:
HFDockManageHandler.restore_cordon_state(self, enabled, bounds)


func _on_export_playtest() -> void:
await HFDockManageHandler.on_export_playtest(self)


func _show_spawn_fix_dialog(spawn: Node3D, validation: Dictionary, mask: int) -> void:
HFDockManageHandler.show_spawn_fix_dialog(self, spawn, validation, mask)


func _record_spawn_create_undo(before_state: Dictionary) -> void:
HFDockManageHandler.record_spawn_create_undo(self, before_state)


func _record_spawn_move_undo(spawn: Node3D, old_pos: Vector3, new_pos: Vector3) -> void:
HFDockManageHandler.record_spawn_move_undo(self, spawn, old_pos, new_pos)


func _restore_spawn(spawn: Node3D, pos: Vector3, angle_deg: float) -> void:
HFDockManageHandler.restore_spawn(spawn, pos, angle_deg)


func _on_spawn_validate() -> void:
await HFDockManageHandler.on_spawn_validate(self)

Expand All @@ -3652,10 +3584,6 @@ func _on_show_spawn_debug_toggled(enabled: bool) -> void:
await HFDockManageHandler.on_show_spawn_debug_toggled(self, enabled)


func _notify_running_instances() -> void:
HFDockManageHandler.notify_running_instances(self)


func _warn_missing_dependencies() -> void:
HFDockManageHandler.warn_missing_dependencies(self)

Expand Down Expand Up @@ -4247,14 +4175,6 @@ func _refresh_terrain_slots() -> void:
HFDockPaintHandler.refresh_terrain_slots(self)


func _terrain_slot_label(path: String) -> String:
return HFDockPaintHandler.terrain_slot_label(path)


func _set_terrain_slot_controls_enabled(enabled: bool) -> void:
HFDockPaintHandler.set_terrain_slot_controls_enabled(self, enabled)


func _on_material_selected(index: int) -> void:
_selected_material_index = index

Expand Down Expand Up @@ -5718,10 +5638,6 @@ func refresh_visgroup_ui() -> void:
HFDockVisgroupHandler.refresh_visgroup_ui(self)


func _get_selected_visgroup_name() -> String:
return HFDockVisgroupHandler.get_selected_visgroup_name(self)


func _on_visgroup_add() -> void:
HFDockVisgroupHandler.on_visgroup_add(self)

Expand Down Expand Up @@ -5763,10 +5679,6 @@ func _setup_cordon_ui() -> void:
HFDockVisgroupHandler.setup_cordon_ui(self)


func _make_cordon_spin(min_val: float, max_val: float, default_val: float) -> SpinBox:
return HFDockVisgroupHandler.make_cordon_spin(self, min_val, max_val, default_val)


func _on_cordon_toggled(pressed: bool) -> void:
HFDockVisgroupHandler.on_cordon_toggled(self, pressed)

Expand Down
2 changes: 0 additions & 2 deletions addons/hammerforge/dock_entity_handler.gd
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ static func rebuild_entity_props(dock: Object, entity: Node3D) -> void:
return

dock._entity_props_section.visible = true
dock._entity_props_entity = entity
var content = dock._entity_props_section.get_content()

var e_data := HFEntityPropUtils.get_entity_data(entity)
Expand Down Expand Up @@ -140,7 +139,6 @@ static func clear_entity_props(dock: Object) -> void:
if is_instance_valid(ctrl):
ctrl.queue_free()
dock._entity_props_controls.clear()
dock._entity_props_entity = null
if dock._entity_props_section:
dock._entity_props_section.visible = false

Expand Down
6 changes: 0 additions & 6 deletions addons/hammerforge/draft_entity.gd
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,6 @@ var entity_class: String:
var entity_data: Dictionary = {}
var preview_node: Node3D = null
var _gizmo_update_queued := false
var entity_properties: Dictionary:
get:
return entity_data
set(value):
if value is Dictionary:
entity_data = value


func _set_entity_type(val: String) -> void:
Expand Down
Loading