duncgibbs 99de9e8b40
Some checks failed
linting & formatting / build (push) Failing after 5s
itch.io publish action / build (linux64, x86_64) (push) Failing after 34s
itch.io publish action / build (osx, app) (push) Failing after 30s
itch.io publish action / build (win64, exe) (push) Failing after 31s
initial commit
2026-04-13 11:34:00 -05:00

463 lines
12 KiB
GDScript

@icon("../icons/tube_inspector.svg")
class_name EditorTubeClientPanel extends Control
## @experimental: This class is used as part of the TubeClientDebugPanel scene, and is part of a scene. Should not be used as itself
const TRACKER_ITEM_CONTROL_SCENE := preload("uid://bc0iqgoaed12")
const PEER_ITEM_CONTROL_SCENE := preload("uid://dq2d125kftur6")
const MESSAGE_ITEM_CONTROL_SCENE := preload("uid://cfsei3airwx4s")
const STATE_COLORS := {
TubeClient.State.IDLE: Color.BEIGE,
TubeClient.State.CREATING_SESSION: Color.CYAN,
TubeClient.State.JOINING_SESSION: Color.CYAN,
TubeClient.State.SESSION_CREATED: Color.PALE_GREEN,
TubeClient.State.SESSION_JOINED: Color.PALE_GREEN,
}
const SIGNALING_COLORS := {
false: Color.CRIMSON,
true: Color.PALE_GREEN,
}
@export var client: TubeClient:
set(x):
if client != x:
if null != client:
client.error_raised.disconnect(
_on_client_error_raised
)
client.session_created.disconnect(
_on_client_session_created
)
client.session_joined.disconnect(
_on_client_session_joined
)
client.session_left.disconnect(
_on_client_session_left
)
client.peer_refused.disconnect(
_on_client_peer_refused
)
client.peer_connected.disconnect(
_on_client_peer_connected
)
client.peer_disconnected.disconnect(
_on_client_peer_disconnected
)
client.peer_unstabilized.disconnect(
_on_client_peer_unstabilized
)
client.peer_stabilized.disconnect(
_on_client_peer_stabilized
)
client._session_initiated.disconnect(
_on_client_session_initiated
)
client._local_signaling_peer_initiated.disconnect(
_on_client_local_signaling_initiated
)
client._tracker_initiated.disconnect(
_on_client_tracker_initiated
)
client._peer_initiated.disconnect(
_on_client_peer_initiated
)
client._upnp.port_mapped.disconnect(
_on_client_port_mapped
)
client._upnp.warning_raised.disconnect(
_on_client_upnp_warning_raised
)
if null != x:
x.error_raised.connect(
_on_client_error_raised
)
x.session_created.connect(
_on_client_session_created
)
x.session_joined.connect(
_on_client_session_joined
)
x.session_left.connect(
_on_client_session_left
)
x.peer_refused.connect(
_on_client_peer_refused
)
x.peer_connected.connect(
_on_client_peer_connected
)
x.peer_disconnected.connect(
_on_client_peer_disconnected
)
x.peer_unstabilized.connect(
_on_client_peer_unstabilized
)
x.peer_stabilized.connect(
_on_client_peer_stabilized
)
x._session_initiated.connect(
_on_client_session_initiated
)
x._local_signaling_peer_initiated.connect(
_on_client_local_signaling_initiated
)
x._tracker_initiated.connect(
_on_client_tracker_initiated
)
x._peer_initiated.connect(
_on_client_peer_initiated
)
x._upnp.port_mapped.connect(
_on_client_port_mapped
)
x._upnp.warning_raised.connect(
_on_client_upnp_warning_raised
)
client = x
if is_instance_valid(client_control):
client_control.client = client
if is_instance_valid(peer_control):
peer_control.client = client
update()
## Maximum of messages available, the oldest message will be removed when a new message is pushed. It is to prevent memory leak.
## [br][br]
## The amount is by item, meaning is max_messages_amount is set to 100. Client can store 100 messages, each trackers 100 messages, each peers 100 messages...
@export var max_messages_amount: int = 100
var message_item_controls: Array[EditorTubeMessagesItemControl] = []
var message_item_button_group := ButtonGroup.new()
@onready var peer_label: Label = %PeerLabel
@onready var session_line_edit: LineEdit = %SessionLineEdit
@onready var session_state_indicator: Control = %SessionIndicator
@onready var join_button: Button = %JoinButton
@onready var create_button: Button = %CreateButton
@onready var refuse_new_button: Button = %RefuseNewButton
@onready var close_button: Button = %CloseButton
@onready var local_signaling_indicator: Control = %LocalSignalingIndicator
@onready var trackers_indicator: Control = %TrackersIndicator
@onready var trackers_container: Container = %TrackersContainer
@onready var peers_container: Container = %PeersContainer
@onready var client_control: Control = %ClientControl
@onready var local_signaling_control: EditorTubeLocalSignalingControl = %LocalSignalingControl
@onready var tracker_control: EditorTubeTrackerControl = %TrackerControl
@onready var peer_control: EditorTubePeerControl = %PeerControl
@onready var chat_control: Control = %ChatControl
@onready var messages_container: EditorTubeMessagesContainer = %MessagesContainer
func _ready() -> void:
messages_container.max_messages_amount = max_messages_amount
chat_control.max_messages_amount = max_messages_amount
local_signaling_control.max_messages_amount = max_messages_amount
client_control.show()
message_item_button_group.allow_unpress = true
switch_to_idle_config()
messages_container.display_messages([], self)
client = client
update()
func clear():
for child in trackers_container.get_children():
trackers_container.remove_child(child)
child.queue_free()
for child in peers_container.get_children():
peers_container.remove_child(child)
child.queue_free()
message_item_controls.clear()
messages_container.display_messages(
message_item_controls,
self
)
update()
func switch_to_idle_config():
session_state_indicator.modulate = STATE_COLORS[TubeClient.State.IDLE]
local_signaling_indicator.modulate = session_state_indicator.modulate
trackers_indicator.modulate = session_state_indicator.modulate
session_line_edit.editable = true
#session_line_edit.clear()
join_button.visible = true
create_button.visible = true
refuse_new_button.visible = false
close_button.visible = false
func switch_to_joined_config():
session_line_edit.editable = false
join_button.visible = false
create_button.visible = false
close_button.visible = true
func switch_to_created_config():
session_line_edit.editable = false
join_button.visible = false
create_button.visible = false
refuse_new_button.visible = true
close_button.visible = true
func update():
if not is_instance_valid(client):
return
if is_instance_valid(session_state_indicator):
session_state_indicator.modulate = STATE_COLORS[client.state]
if is_instance_valid(local_signaling_indicator):
local_signaling_indicator.modulate = SIGNALING_COLORS[client._is_local_signaling()]
if TubeClient.State.IDLE == client.state:
local_signaling_indicator.modulate = STATE_COLORS[client.state]
if is_instance_valid(trackers_indicator):
trackers_indicator.modulate = SIGNALING_COLORS[client._is_online_signaling()]
if TubeClient.State.IDLE == client.state:
trackers_indicator.modulate = STATE_COLORS[client.state]
if is_instance_valid(peer_label):
peer_label.text = EditorTubePeerItemControl.get_peer_string(client.peer_id)
peer_label.modulate = EditorTubePeerItemControl.get_peer_color(client.peer_id)
if is_instance_valid(session_line_edit):
session_line_edit.text = client.session_id
if is_instance_valid(messages_container):
if messages_container.is_displaying_from(self):
messages_container.display_messages(
message_item_controls,
self
)
func add_message_item_control(data) -> EditorTubeMessagesItemControl:
if max_messages_amount <= message_item_controls.size():
var item := message_item_controls.pop_front()
item.queue_free()
var message_item_control := MESSAGE_ITEM_CONTROL_SCENE.instantiate()
message_item_controls.append(message_item_control)
message_item_control.data = data
message_item_control.button_group = message_item_button_group
update()
return message_item_control
func add_tracker(p_tracker: TubeTracker):
var item_control := TRACKER_ITEM_CONTROL_SCENE.instantiate()
trackers_container.add_child(item_control)
#item_control.client = client
item_control.tracker = p_tracker
item_control.tracker_control = tracker_control
item_control.max_messages_amount = max_messages_amount
func add_peer(peer: TubePeer):
for i_control in peers_container.get_children():
if i_control.peer.id == peer.id:
i_control.peer = peer
return
var item_control := PEER_ITEM_CONTROL_SCENE.instantiate()
peers_container.add_child(item_control)
item_control.client = client
item_control.peer = peer
item_control.peer_control = peer_control
item_control.max_messages_amount = max_messages_amount
func _on_header_button_pressed() -> void:
client_control.show()
if not messages_container.is_displaying_from(self):
messages_container.display_messages(
message_item_controls,
self
)
func _on_join_button_pressed() -> void:
if not is_instance_valid(client):
return
var session_id := session_line_edit.text
client.join_session(session_id)
func _on_create_button_pressed() -> void:
if not is_instance_valid(client):
return
client.create_session()
func _on_refuse_new_button_toggled(toggled_on: bool) -> void:
client.refuse_new_connections = toggled_on
func _on_close_button_pressed() -> void:
if not is_instance_valid(client):
return
client.leave_session()
#
func _on_client_error_raised(code: int, message: String):
var item := add_message_item_control(message)
item.error()
match code:
TubeClient.SessionError.CREATE_SESSION_FAILED, TubeClient.SessionError.JOIN_SESSION_FAILED:
switch_to_idle_config()
update()
func _on_client_session_initiated():
clear()
match client.state:
TubeClient.State.JOINING_SESSION:
switch_to_joined_config()
TubeClient.State.CREATING_SESSION:
switch_to_created_config()
TubeClient.State.IDLE:
switch_to_idle_config()
update()
func _on_client_session_created():
switch_to_created_config()
local_signaling_indicator.modulate = SIGNALING_COLORS[true]
trackers_indicator.modulate = SIGNALING_COLORS[true]
add_message_item_control("Create session {id}".format({
"id": client.session_id
})).success()
func _on_client_session_joined():
switch_to_joined_config()
local_signaling_indicator.modulate = SIGNALING_COLORS[true]
trackers_indicator.modulate = SIGNALING_COLORS[true]
add_message_item_control("Join session {id}".format({
"id": client.session_id
})).success()
func _on_client_session_left():
switch_to_idle_config()
add_message_item_control("Leave session {id}".format({
"id": client.session_id
}))
func _on_client_peer_refused(peer_id: int):
add_message_item_control("Peer {peer_id} connection refused".format({
"peer_id": peer_id,
})).warning()
func _on_client_peer_connected(peer_id: int):
var will_add_peer := true
for i_control in peers_container.get_children():
if i_control.peer.id == peer_id:
will_add_peer = false
break
if will_add_peer:
var peer := TubePeer.new(peer_id)
peer.connection_state = WebRTCPeerConnection.STATE_CONNECTED
add_peer(peer)
add_message_item_control("Peer {peer_id} connected".format({
"peer_id": peer_id,
})).success()
func _on_client_peer_disconnected(peer_id: int):
add_message_item_control("Peer {peer_id} disconnected".format({
"peer_id": peer_id,
}))
func _on_client_peer_unstabilized(peer_id: int):
add_message_item_control("Peer {peer_id} unstabilized".format({
"peer_id": peer_id,
})).warning()
func _on_client_peer_stabilized(peer_id: int):
add_message_item_control("Peer {peer_id} stabilized".format({
"peer_id": peer_id,
}))
func _on_client_local_signaling_initiated(local_signaling_peer: TubeLocalSignalingPeer):
local_signaling_control.local_signaling_peer = local_signaling_peer
add_message_item_control("Local signaling on {port} initiated".format({
"port": local_signaling_peer.udp_peer.get_local_port()
}))
update.call_deferred()
func _on_client_tracker_initiated(tracker: TubeTracker):
tracker.failed.connect(update.call_deferred)
tracker.disconnected.connect(update.call_deferred)
add_tracker(tracker)
add_message_item_control("Tracker {tracker} initiated".format({
"tracker": str(tracker)
}))
update.call_deferred()
func _on_client_peer_initiated(peer: TubePeer):
add_peer(peer)
add_message_item_control("Peer {peer_id} initiated".format({
"peer_id": peer.id,
}))
update.call_deferred()
func _on_client_port_mapped(public_port: int, local_port: int):
add_message_item_control("Port {port} mapped to internal port {internal_port}".format({
"port": public_port,
"internal_port": local_port
}))
func _on_client_upnp_warning_raised(message: String):
add_message_item_control("Upnp: " + message).warning()