64 lines
2.1 KiB
GDScript
64 lines
2.1 KiB
GDScript
extends Node
|
|
class_name DespawningItem
|
|
|
|
@export var time_to_despawn: float = 8
|
|
|
|
# The minimum speed required to reset despawn timer.
|
|
@export var minimum_speed_square: float = 0.1
|
|
|
|
|
|
@onready var _pickable: XRToolsPickable = get_parent() as XRToolsPickable
|
|
@onready var _rigid: RigidBody3D = get_parent() as RigidBody3D
|
|
|
|
|
|
var _time_left: float = time_to_despawn
|
|
|
|
func _ready() -> void:
|
|
if not _pickable:
|
|
push_error("DespawningItem must be a grand child of an XRToolsPickable.")
|
|
return
|
|
if not _rigid:
|
|
push_error("DespawningItem must be a grand child of an RigidBody3D.")
|
|
return
|
|
|
|
|
|
func _process(delta: float) -> void:
|
|
# Despawning is a world decision, so only the owner of world logic runs the
|
|
# clock. Every peer used to run its own copy: the countdown drifted between
|
|
# them and the blink below toggled `visible` locally, so the same item was
|
|
# shown on one peer and hidden on the other. Non-owners just follow the
|
|
# server, which removes the item for everyone when its time is up.
|
|
if not NetworkManager.owns_world():
|
|
return
|
|
|
|
# if we're held or moving, reset timer and return
|
|
if _pickable.get_picked_up_by() or _rigid.linear_velocity.length_squared() > pow(minimum_speed_square,2):
|
|
_time_left = time_to_despawn
|
|
_set_visible(true)
|
|
return
|
|
|
|
|
|
# Count down to zero and despawn
|
|
_time_left -= delta
|
|
if _time_left <= 0:
|
|
SweetLogger.debug("despawning {0}", [get_parent()], "despawning_item.gd", "_process")
|
|
NetworkManager.despawn_item(get_parent())
|
|
# Stop counting: despawn_item() only queues the free, so without this we
|
|
# keep re-reporting the same item every frame until it actually goes.
|
|
set_process(false)
|
|
return
|
|
|
|
# Make item blink in and out before despawning
|
|
if _time_left < time_to_despawn / 2:
|
|
_set_visible(int(_time_left * 5.0) % 2 == 0)
|
|
|
|
|
|
# `visible` is not a replicated property, so a blink driven only here would make
|
|
# the item flicker on the host and stay solid on clients. Until it is synced,
|
|
# only warn when there is nobody else to disagree with.
|
|
func _set_visible(value: bool) -> void:
|
|
if NetworkManager.is_online():
|
|
get_parent().visible = true
|
|
return
|
|
get_parent().visible = value
|