clockwork-city/addons/tube/tube_context.gd
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

153 lines
4.5 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@icon("./icons/tube_context.svg")
@tool
class_name TubeContext extends Resource
## A resource that holds configuration and helper methods for managing simple multiplayer session.
## Character set to generate app IDs. Contains most printable ASCII characters.
const _APP_ID_CHARACTER_SET := "!#$%&()*+,-./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890:;<=>?@[]^_{|}~"
@export_tool_button("Generate app id", "RandomNumberGenerator") var _generate_app_id_tool_button = (func():
app_id = _get_random_string(15, _APP_ID_CHARACTER_SET)
)
## Application identifier for this multiplayer context.
## Must be exactly 15 ASCII characters long.
@export var app_id: String
## Character set used to generate session IDs.
## Must not be empty and should only contain ASCII characters.
## A larger set reduces the probability of collision. With 62 characters
## (AZ, az, 09), the chance of two random 5-character IDs matching is approximately 1 in 916 million.
## For readability by players, consider removing ambiguous characters (e.g., oO0, ilj1I, z2).
@export_multiline var session_id_characters_set: String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"
## List of tracker server URLs used for session signaling.
@export var trackers_urls: Array[String] = []
## List of STUN server URLs used for WebRTC ICE candidate resolution.
@export var stun_servers_urls: Array[String] = []
## List of TURN servers (optional). Turn server are dictionnary in the form:
## [codeblock]
## {
## "urls": "turn:turn.example.com:3478",
## "username: "my-username",
## "credential": "my-credential",
## }
@export var turn_servers: Array[Dictionary] = []
func _to_string() -> String:
return "AppID: %s | Trackers: %s | STUN: %s" % [app_id, str(trackers_urls), str(stun_servers_urls)]
func _is_ascii(string: String) -> bool:
for char_index in range(string.length()):
if string.unicode_at(char_index) >= 128:
return false
return true
## Checks if the context configuration is valid.
func is_valid() -> bool:
if 0 == session_id_characters_set.length():
printerr("Session ID Character Set is empty")
return false
if not _is_ascii(session_id_characters_set):
printerr("Session ID Character Set can only contain ASCII characters")
return false
if null == app_id or 15 != app_id.length() or not _is_ascii(app_id):
printerr("App id is invalid")
return false
return true
## Returns ICE server configuration dictionary for WebRTC peer connection.
##
## Example:
## [codeblock]
## {
## "iceServers": [
## {
## "urls": [ "stun:stun.example.com:3478" ], # One or more STUN servers.
## },
## {
## "urls": [ "turn:turn.example.com:3478" ], # One or more TURN servers.
## "username": "a_username", # Optional username for the TURN server.
## "credential": "a_password", # Optional password for the TURN server.
## }
## ]
## }
## [/codeblock]
func get_ice_servers() -> Dictionary:
var ice_servers := []
if null != stun_servers_urls:
for url in stun_servers_urls:
ice_servers.append({
"urls": url
})
if null != turn_servers:
for turn_server in turn_servers:
ice_servers.append(turn_server)
if ice_servers.is_empty():
return {}
return {
"iceServers": ice_servers
}
func _get_random_string(p_size: int, character_set: String) -> String:
var rng := RandomNumberGenerator.new()
rng.randomize()
var character_set_length := character_set.length()
var out := ""
for i in range(p_size):
var index := rng.randi()%character_set_length
out += character_set[index]
return out
## Generates a random 5-character session ID.
func generate_session_id() -> String:
return _get_random_string(5, session_id_characters_set)
## Validates if a session ID is correct
func is_session_id_valid(p_session_id: String) -> bool:
return 5 == p_session_id.length()
## Validates if a peer ID hash is numeric and valid.
func is_peer_id_hash_valid(p_peer_id_hash: String) -> bool:
return p_peer_id_hash.is_valid_int()
## Returns the combined "info hash" (app ID and session ID) for tracker usage.
func get_info_hash(p_session_id: String) -> String:
if not is_session_id_valid(p_session_id):
printerr("Invalid session id")
return ""
return app_id + p_session_id
## Converts a integer peer ID hash into an peer ID hash for tracker usage.
func get_peer_id_hash(p_peer_id: int) -> String:
return str(p_peer_id).pad_zeros(20)
## Converts a peer ID hash into an integer peer ID.
func get_peer_id(p_peer_id_hash: String) -> int:
if not is_peer_id_hash_valid(p_peer_id_hash):
return 0
return int(p_peer_id_hash)