neon-sprawl/client/scripts/interactable_world_builder.gd

102 lines
2.9 KiB
GDScript

extends Object
## NEO-25: spawns walkable interactable props + glow marker pairs from server descriptor dicts.
## Returns glow groups for [method InteractionRadiusIndicators.setup_glow_groups].
const _PROP_SIZE := Vector3(0.9, 1.0, 0.4)
const _MARKER_MESH_SIZE := Vector3(0.22, 0.35, 0.22)
const _MARKER_OFFSET_A := Vector3(1.1, 0.25, 0.9)
const _MARKER_OFFSET_B := Vector3(-0.95, 0.22, -1.05)
static func build_from_catalog(
descriptors: Array, interactables_root: Node3D, markers_root: Node3D
) -> Array:
for c in interactables_root.get_children():
c.free()
for c in markers_root.get_children():
c.free()
var glow_groups: Array = []
for row in descriptors:
if not row is Dictionary:
continue
var rd: Dictionary = row
var id: String = str(rd.get("interactableId", ""))
var kind: String = str(rd.get("kind", ""))
var anchor: Vector3 = _anchor_from_row(rd)
var radius: float = float(rd.get("interactionRadius", 0.0))
var body := StaticBody3D.new()
body.name = "Interactable_%s" % id
body.collision_mask = 3
body.add_to_group("walkable")
interactables_root.add_child(body)
body.global_position = anchor
var prop_mesh := MeshInstance3D.new()
var box_mesh := BoxMesh.new()
box_mesh.size = _PROP_SIZE
prop_mesh.mesh = box_mesh
prop_mesh.position = Vector3.ZERO
var prop_mat := StandardMaterial3D.new()
if kind == "resource_node":
prop_mat.albedo_color = Color(0.18, 0.55, 0.32, 1.0)
else:
prop_mat.albedo_color = Color(0.28, 0.38, 0.45, 1.0)
prop_mesh.material_override = prop_mat
body.add_child(prop_mesh)
var col := CollisionShape3D.new()
var box_shape := BoxShape3D.new()
box_shape.size = _PROP_SIZE
col.shape = box_shape
body.add_child(col)
var marker_parent := Node3D.new()
marker_parent.name = "Markers_%s" % id
markers_root.add_child(marker_parent)
marker_parent.global_position = anchor
var mi_a := _make_marker_mesh()
mi_a.position = _MARKER_OFFSET_A
marker_parent.add_child(mi_a)
var mi_b := _make_marker_mesh()
mi_b.position = _MARKER_OFFSET_B
marker_parent.add_child(mi_b)
var glow_mat := StandardMaterial3D.new()
glow_mat.albedo_color = Color(0.15, 0.4, 1.0, 1.0)
glow_mat.emission_enabled = true
glow_mat.emission = Color(0.3, 0.6, 1.0)
glow_mat.emission_energy_multiplier = 0.12
mi_a.material_override = glow_mat
mi_b.material_override = glow_mat
glow_groups.append(
{"anchor": anchor, "radius": radius, "material": glow_mat, "markers": [mi_a, mi_b]}
)
return glow_groups
static func _anchor_from_row(rd: Dictionary) -> Vector3:
var a: Variant = rd.get("anchor", null)
if not a is Dictionary:
return Vector3.ZERO
var ad: Dictionary = a
return Vector3(
float(ad.get("x", 0.0)),
float(ad.get("y", 0.0)),
float(ad.get("z", 0.0)),
)
static func _make_marker_mesh() -> MeshInstance3D:
var mi := MeshInstance3D.new()
var m := BoxMesh.new()
m.size = _MARKER_MESH_SIZE
mi.mesh = m
return mi