Files
mtgodot-poc/project/fx/target_effect_anchor.gd
T

44 lines
1.9 KiB
GDScript

# Target-following effects use actor-local offset. Snapshot effects use the
# fly-target's world position and a world-aligned offset (40250 type 10).
extends Node
const CONVERSION := Basis(Vector3(0.01, 0, 0), Vector3(0, 0, -0.01), Vector3(0, 0.01, 0))
var target: WeakRef
var offset := Vector3.ZERO
func configure(node: Node3D, source_offset: Vector3, following: bool) -> bool:
if not is_instance_valid(node) or not node.is_inside_tree(): return false
target = weakref(node)
offset = CONVERSION * source_offset
process_priority = 100
set_process(following)
if following:
_process(0.0)
else:
get_parent().global_position = fly_target_position(node) + offset
return true
static func fly_target_position(node: Node3D) -> Vector3:
# The reference model-index 0 sphere is built from bone OBBs, not the
# union of visible attachments or the rendered vertex AABB.
var models := node.find_children("*", "Metin2Model", true, false)
if node.has_method("get_fly_target_bounds"): models.push_front(node)
for model in models:
var result: Dictionary = model.get_fly_target_bounds()
if result.get("valid", false):
var body_bounds: AABB = result.bounds
return model.to_global(body_bounds.get_center())
# The reference returns the model bounding sphere centre, not its feet.
var meshes := node.find_children("*", "MeshInstance3D", true, false)
var bounds := AABB()
var found := false
for mesh in meshes:
if mesh.mesh == null or not mesh.is_visible_in_tree(): continue
var box: AABB = mesh.global_transform * mesh.get_aabb()
bounds = bounds.merge(box) if found else box
found = true
return bounds.get_center() if found else node.global_position
func _process(_delta: float) -> void:
var node: Node3D = target.get_ref() if target else null
if not is_instance_valid(node) or not node.is_inside_tree():
get_parent().queue_free()
return
get_parent().global_transform = node.global_transform * Transform3D(Basis.IDENTITY, offset)