My EditorNode3DGizmoPlugin script can't see my custom class's public function

Godot Version

4.2.1

Question

I followed the official 3D gizmo guide to make my own gizmo, but during the process I kept receiving an Invalid Call error in the _redraw function.
The error is specifically:

res://addons/sky_light_3d_gizmo/plugin.gd:20 - Invalid call. Nonexistent function 'calculate' in base 'DirectionalLight3D (SkyLight3D)'.

Here is my entire SkyLight3D class:

extends DirectionalLight3D
class_name SkyLight3D

@export_group("Orbit Properties")
@export_range(-180.0, 180.0) var orbit_offset := 0.0
@export var orbit_period := 0.0
@export var pertubation_period := 0.0
@export_range(-90.0, 90.0) var incline := 0.0

@export_group("Wobble Incline")
@export var wobble_incline := false
@export var wobble_period := 0.0

var _seconds := 0.0
var _tick := 0
var _days := 0.0

func _process(delta: float) -> void:
	position = calculate(delta)
	look_at(Vector3.ZERO)

func calculate(delta: float) -> Vector3:
	# calculate current time
	_seconds += delta * 3600
	if _seconds > 1.0:
		_tick += roundi(_seconds)
		_seconds = 0.0
	_days = _tick / float(86400)
	
	# calculate position in orbit
	var cycle := _cycle_angle(_days, orbit_period)
	var final_position := _circle(fmod(orbit_offset + cycle, 360.0))
	if not wobble_incline:
		final_position = final_position.rotated(Vector3.RIGHT, incline)
	var pertube_cycle := _cycle_angle(_days, pertubation_period)
	final_position = final_position.rotated(Vector3.UP, pertube_cycle)
	if wobble_incline:
		var wobble_cycle := _cycle_angle(_days, wobble_period)
		wobble_cycle = sin(deg_to_rad(wobble_cycle)) * incline
		final_position = final_position.rotated(Vector3.RIGHT, wobble_cycle)
	
	return final_position

func _cycle_angle(current: float, max: float) -> float:
	if is_equal_approx(current, 0.0) || is_equal_approx(max, 0.0):
		return 0.0
	return fmod(current, max) / max * 360.0

func _circle(f: float, r := 1.0) -> Vector3:
	return Vector3(r * sin(f), 0.0, r * cos(f))

And here is my entire plugin script:

extends EditorNode3DGizmoPlugin

const default_icon := preload("res://gizmo_icons/earth_icon.png")

func _get_gizmo_name() -> String:
	return "SkyLight3D Gizmo"

func _has_gizmo(for_node_3d: Node3D) -> bool:
	return for_node_3d is SkyLight3D

func _init() -> void:
	create_material("main", Color(0, 0, 1))
	create_icon_material("icon", default_icon)

func _redraw(gizmo: EditorNode3DGizmo) -> void:
	gizmo.clear()
	var node := gizmo.get_node_3d() as SkyLight3D
	var lines := PackedVector3Array()
	
	print(node.calculate(23.0))
	
	var icon_material := get_material("icon", gizmo)
	icon_material.albedo_texture = load("res://gizmo_icons/" + node.name.to_lower() + "_icon.png")
	gizmo.add_unscaled_billboard(get_material("icon", gizmo), 0.05)

It’s that print(node.calculate(23.0)) line that causes the error. No idea why. The function absolutely exists, it even appears in the autocompletion menu.

Edit

I have found that not only do I get this error for functions but also for properties. The plugin only seems to recognize exported variables. Is this intentional?

Here’s the error for the properties:

 res://addons/sky_light_3d_gizmo/plugin.gd:34 - Invalid get index '_seconds' (on base: 'DirectionalLight3D (SkyLight3D)').

It seems like my only option is to have my plugin store its own data.

You need to make the scripts @tool scripts if you want to run them inside the editor.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.