push project up

This commit is contained in:
2026-08-07 03:02:53 -05:00
parent 48acb406a7
commit de0da3de6e
40 changed files with 986 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
[gd_scene load_steps=5 format=3 uid="uid://dy51wny4x53f4"]
[ext_resource type="Script" uid="uid://dbnl4tjahkoun" path="res://scenes/data_bridge/game_data.gd" id="1_l6w8l"]
[ext_resource type="Script" uid="uid://65x4bq2wsh8k" path="res://scenes/data_bridge/game_state.gd" id="2_6ash1"]
[ext_resource type="Script" uid="uid://dyq4p5e06ib14" path="res://scenes/data_bridge/lobby_data.gd" id="3_l6w8l"]
[ext_resource type="Script" uid="uid://uyimqfjmuc34" path="res://scenes/data_bridge/multiplayer_data.gd" id="4_gcm58"]
[node name="bridge" type="Node"]
[node name="game_data" type="Node" parent="."]
script = ExtResource("1_l6w8l")
[node name="game_state" type="Node" parent="."]
script = ExtResource("2_6ash1")
[node name="lobby_data" type="Node" parent="."]
script = ExtResource("3_l6w8l")
[node name="multiplayer" type="Node" parent="."]
script = ExtResource("4_gcm58")

View File

@@ -0,0 +1,14 @@
class_name GameData extends Node
func _init() -> void:
Globals.game_data = self
@rpc("authority", "reliable")
func set_game_address(_address: String) -> void:
pass
@rpc("authority", "reliable")
func set_game_port(_port: String) -> void:
pass

View File

@@ -0,0 +1 @@
uid://dbnl4tjahkoun

View File

@@ -0,0 +1,23 @@
class_name GameState extends Node
func _init() -> void:
Globals.game_state = self
func set_game_scene(scene_str: String) -> void:
# NOTE: 'node_pth_str' needs to match game node structure else server sync throws errors.
var node_pth_str = "billiards/scene"
var scene = load(scene_str).instantiate()
var target = get_tree().root.get_node(node_pth_str)
scene.name = "lobby_screen"
clear_game_scene(target)
target.add_child(scene)
func clear_game_scene(container: Node) -> void:
for child in container.get_children():
child.queue_free()
await get_tree().process_frame

View File

@@ -0,0 +1 @@
uid://65x4bq2wsh8k

View File

@@ -0,0 +1,183 @@
class_name LobbyData extends Node
var uuid = null
var lobby_ui: Node = null
var IS_VALID_CHARS_REGEX: RegEx = RegEx.create_from_string("^[a-zA-Z0-9]+$")
const MATCH_TYPES: Array = ["8ball", "9ball", "snooker"]
const CLIENT_DICT: Dictionary = {
"id": "",
"partner_id": "",
"in_match": false,
"match_id": ""
}
const MATCH_POOL_ENTRY: Dictionary = {
"player1": "",
"player2": "",
"data": {}
}
var active_match_pool: Dictionary = {}
var match_pool: Dictionary = {}
var client_pool: Dictionary = {}
func _init() -> void:
Globals.lobby_data = self
uuid = load('res://addons/uuid/uuid.gd')
func _delete_from_match_pool(match_id: String) -> Dictionary:
if not match_pool.get(match_id):
return {}
var to_delete: Dictionary = match_pool[match_id].data
match_pool.erase(match_id)
return to_delete
func _signal_match_list_remove_entry(match_id: String) -> void:
lobby_ui.rpc_signals.rpc_id(1, "match_list_remove_entry", match_id)
for client in client_pool.values():
if client.in_match: continue
lobby_ui.rpc_signals.rpc_id(client.id, "match_list_remove_entry", match_id)
func _launch_game_server(
match_entry: Dictionary,
client1: Dictionary, client2: Dictionary
) -> void:
var port: String = InstanceLauncher.launch_game_server(match_entry.data.type)
if port == "-1":
# TODO: Alert clients that the game wont be created due to
# server reaching number of allowed instances
return
Globals.game_data.rpc_id(client1.id, "set_game_address", "127.0.0.1")
Globals.game_data.rpc_id(client2.id, "set_game_address", "127.0.0.1")
Globals.game_data.rpc_id(client1.id, "set_game_port", port)
Globals.game_data.rpc_id(client2.id, "set_game_port", port)
rpc_id(client1.id, "connect_to_game")
rpc_id(client2.id, "connect_to_game")
@rpc("any_peer", "reliable")
func match_list_add_entry(match_entry: Dictionary) -> void:
var client1 = client_pool.get( multiplayer.get_remote_sender_id() )
if not client1: return
if not client1.match_id.is_empty(): return
if match_entry.name.length() < 1 or match_entry.name.length() > 12: return
if not IS_VALID_CHARS_REGEX.search(match_entry.name): return
if not match_entry.type in MATCH_TYPES: return
match_entry["match_id"] = uuid.v4()
match_pool[match_entry.match_id] = MATCH_POOL_ENTRY.duplicate_deep()
match_pool[match_entry.match_id].player1 = client1.id
match_pool[match_entry.match_id].data = match_entry
client1.match_id = match_entry.match_id
lobby_ui.rpc_signals.rpc_id(1, "match_list_add_entry", match_entry)
for client in client_pool.values():
if client.in_match: continue
lobby_ui.rpc_signals.rpc_id(client.id, "match_list_add_entry", match_entry)
lobby_ui.rpc_signals.rpc_id(client1.id, "match_list_activate_entry", match_entry.match_id)
@rpc("any_peer", "reliable")
func match_list_remove_entry(match_id: String) -> void:
var client1 = client_pool.get( multiplayer.get_remote_sender_id() )
if not client1: return
if not client1.match_id == match_id: return
client1.match_id = ""
_delete_from_match_pool(match_id)
_signal_match_list_remove_entry(match_id)
@rpc("any_peer", "reliable")
func match_list_join_entry(match_id: String) -> void:
var match_entry = match_pool.get(match_id)
if not match_entry: return
var client1 = client_pool.get( match_entry.player1 )
var client2 = client_pool.get( multiplayer.get_remote_sender_id() )
if not client1: return
if not client2: return
match_entry.player2 = client2.id
client1.in_match = true
client1.partner_id = client2.id
client2.match_id = match_id
client2.in_match = true
client2.partner_id = client1.id
active_match_pool[match_id] = match_entry
match_pool.erase(match_id)
client_pool.erase(client1.id)
client_pool.erase(client2.id)
_signal_match_list_remove_entry(match_id)
_launch_game_server(match_entry, client1, client2)
# NOTE: Needed for hash check to pass between client and server but isn't used by server...
@rpc("authority", "reliable")
func connect_to_game() -> void:
pass
@rpc("authority", "call_local", "reliable")
func load_game_scene(_match_entry: Dictionary, _is_player_1: bool) -> void:
pass
@rpc("authority", "reliable")
func go_back_to_match_screen() -> void:
pass
func server_client_connected(id: int) -> void:
push_warning("Client Connected... ID: ", id)
client_pool[id] = CLIENT_DICT.duplicate_deep()
client_pool[id].id = id
var matches: Array = []
for match_entry in match_pool.values():
matches.append(match_entry.data)
lobby_ui.rpc_signals.rpc_id(id, "receive_match_list", matches)
func server_client_disconnected(id: int) -> void:
push_warning("Client Disconnected... ID: ", id)
var client1 = client_pool.get(id)
if not client1: return
var client2 = client_pool.get( client1.partner_id )
var match_entry = _delete_from_match_pool(client1.match_id)
if not client1.match_id.is_empty() and not match_entry.is_empty():
lobby_ui.rpc_signals.rpc_id(1, "match_list_remove_entry", match_entry.match_id)
for client in client_pool.values():
if client.in_match: continue
if client.id == id: continue
lobby_ui.rpc_signals.rpc_id(client.id, "match_list_remove_entry", match_entry.match_id)
match_pool.erase(client1.match_id)
client_pool.erase(client1.id)
if not client2: return
if active_match_pool.get(client2.match_id):
match_pool.erase(client2.match_id)
var _id = client2.id
client2 = CLIENT_DICT.duplicate_deep()
client2.id = _id

View File

@@ -0,0 +1 @@
uid://dyq4p5e06ib14

View File

@@ -0,0 +1,10 @@
class_name MultiplayerData extends Node
@rpc("authority", "reliable")
func set_multiplayer_active() -> void:
pass
@rpc("authority", "call_local", "reliable")
func set_active_player_id(_id: int) -> void:
pass

View File

@@ -0,0 +1 @@
uid://uyimqfjmuc34

View File

@@ -0,0 +1,42 @@
class_name Lobby extends LobbyBase
@onready var rpc_signals: Node = $rpc_signals
func _ready() -> void:
Globals.lobby_data.lobby_ui = self
setup_signals()
func _exit_tree() -> void:
if server.peer:
server.close_connection()
func setup_signals() -> void:
rpc_signals.server_host_started.connect(_server_host_started)
rpc_signals.match_list_entry_added.connect(_on_match_list_entry_added)
rpc_signals.match_list_entry_removed.connect(_on_match_list_entry_removed)
func _server_host_started() -> void:
host_start_bttn.visible = false
host_stop_bttn.visible = true
func _on_match_list_entry_added(match_entry: Dictionary) -> void:
push_warning("Client: Added Match List Entry... ", match_entry)
_create_match_entry(match_entry)
func _on_match_list_entry_removed(match_id: String) -> void:
push_warning("Client: Removed Match List Entry... ", match_id)
for match_entry in match_list.get_children():
if not match_id == match_entry.match_id: continue
match_entry.queue_free()
func _create_match_entry(match_entry: Dictionary) -> void:
var container = MATCH_ENTRY.instantiate()
match_list.add_child(container)
container.name_lbl.text = match_entry.name
container.type_lbl.text = match_entry.type
container.match_id = match_entry.match_id

View File

@@ -0,0 +1 @@
uid://dk7afnf7ol7dy

View File

@@ -0,0 +1,34 @@
[gd_scene load_steps=5 format=3 uid="uid://dkes5cdu45q6e"]
[ext_resource type="Script" uid="uid://dk7afnf7ol7dy" path="res://scenes/screens/lobby_screen/lobby.gd" id="1_hhiik"]
[ext_resource type="PackedScene" uid="uid://rb6av5eg4u0" path="res://scenes/ui_controls/lobby_screen/lobby_ui.tscn" id="2_lqt48"]
[ext_resource type="Script" uid="uid://6sfwe1hwgf0g" path="res://scenes/screens/lobby_screen/lobby_rpc.gd" id="3_rurl6"]
[ext_resource type="Script" uid="uid://bvqtgf3vbsoj4" path="res://scripts/server_networking.gd" id="4_glu7g"]
[node name="lobby_screen" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_hhiik")
[node name="ui" parent="." instance=ExtResource("2_lqt48")]
layout_mode = 1
theme_override_constants/margin_left = 10
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 10
theme_override_constants/margin_bottom = 10
[node name="rpc_signals" type="Node" parent="."]
script = ExtResource("3_rurl6")
[node name="server" type="Node" parent="."]
script = ExtResource("4_glu7g")
[connection signal="pressed" from="ui/body/left_body/server_host_hbox/host_start_bttn" to="." method="_on_host_start_bttn_pressed"]
[connection signal="pressed" from="ui/body/left_body/server_host_hbox/host_stop_bttn" to="." method="_on_host_stop_bttn_pressed"]
[connection signal="button_up" from="ui/body/left_body/search_vbox/search_hbox/match_search_bttn" to="." method="_on_match_search_bttn_button_up"]
[editable path="ui"]

View File

@@ -0,0 +1,39 @@
class_name LobbyBase extends Control
const MATCH_ENTRY = preload("res://scenes/screens/lobby_screen/match_entry.tscn")
@onready var host_start_bttn: Button = $ui/body/left_body/server_host_hbox/host_start_bttn
@onready var host_stop_bttn: Button = $ui/body/left_body/server_host_hbox/host_stop_bttn
@onready var host_address_input: LineEdit = $ui/body/left_body/server_host_hbox/host_address_input
@onready var host_port_range: SpinBox = $ui/body/left_body/server_host_hbox/host_port_range
@onready var search_vbox: VBoxContainer = $ui/body/left_body/search_vbox
@onready var match_search_input: LineEdit = $ui/body/left_body/search_vbox/search_hbox/match_search_input
@onready var match_list: VBoxContainer = $ui/body/left_body/search_vbox/scroll_container/match_list
@onready var server: Node = $server
func _on_home_bttn_pressed() -> void:
Globals.game_state.set_game_scene(
"res://scenes/screens/start_screen/start.tscn"
)
func _on_host_start_bttn_pressed() -> void:
server.start_server(host_address_input.text, int(host_port_range.value))
func _on_host_stop_bttn_pressed() -> void:
if not server.peer: return
server.close_connection()
host_start_bttn.visible = true
host_stop_bttn.visible = false
func _on_search_bttn_pressed() -> void:
pass
func _on_match_search_bttn_button_up() -> void:
pass

View File

@@ -0,0 +1 @@
uid://5tvhtoe6fdu1

View File

@@ -0,0 +1,29 @@
extends Node
@warning_ignore_start("unused_signal")
signal server_host_started()
signal match_list_entry_added(match_entry: Dictionary)
signal match_list_entry_removed(match_id: String)
@warning_ignore_restore("unused_signal")
@rpc("authority", "call_local", "reliable")
func match_list_add_entry(match_entry: Dictionary) -> void:
push_warning("Received new match entry...")
emit_signal("match_list_entry_added", match_entry)
@rpc("authority", "call_local", "reliable")
func match_list_remove_entry(match_id: String) -> void:
push_warning("Received delete match entry...")
emit_signal("match_list_entry_removed", match_id)
@rpc("authority", "reliable")
func receive_match_list(_match_list: Array) -> void:
pass
@rpc("authority", "reliable")
func match_list_activate_entry(_match_id: String) -> void:
pass

View File

@@ -0,0 +1 @@
uid://6sfwe1hwgf0g

View File

@@ -0,0 +1,8 @@
class_name MatchEntry extends HBoxContainer
@onready var name_lbl: Label = $name_lbl
@onready var type_lbl: Label = $type_lbl
@onready var view_bttn: Button = $view_bttn
var match_id: String = ""

View File

@@ -0,0 +1 @@
uid://ck663xy8rqumo

View File

@@ -0,0 +1,23 @@
[gd_scene load_steps=2 format=3 uid="uid://b5b18vkfe3caa"]
[ext_resource type="Script" uid="uid://ck663xy8rqumo" path="res://scenes/screens/lobby_screen/match_entry.gd" id="1_kw53p"]
[node name="match_entry" type="HBoxContainer"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_kw53p")
[node name="name_lbl" type="Label" parent="."]
layout_mode = 2
size_flags_horizontal = 3
[node name="type_lbl" type="Label" parent="."]
layout_mode = 2
size_flags_horizontal = 3
[node name="view_bttn" type="Button" parent="."]
layout_mode = 2
text = "Join"

View File

@@ -0,0 +1,107 @@
[gd_scene load_steps=3 format=3 uid="uid://rb6av5eg4u0"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_e03fk"]
content_margin_left = 4.0
content_margin_top = 4.0
content_margin_right = 4.0
content_margin_bottom = 4.0
bg_color = Color(0.22352941, 0.47058824, 0.23137255, 1)
corner_radius_top_left = 3
corner_radius_top_right = 3
corner_radius_bottom_right = 3
corner_radius_bottom_left = 3
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_lqt48"]
content_margin_left = 4.0
content_margin_top = 4.0
content_margin_right = 4.0
content_margin_bottom = 4.0
bg_color = Color(0.8460855, 0.21924442, 0.24864262, 1)
corner_radius_top_left = 3
corner_radius_top_right = 3
corner_radius_bottom_right = 3
corner_radius_bottom_left = 3
[node name="margin" type="MarginContainer"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="body" type="HBoxContainer" parent="."]
layout_mode = 2
size_flags_vertical = 3
[node name="left_body" type="VBoxContainer" parent="body"]
layout_mode = 2
size_flags_horizontal = 3
[node name="server_host_hbox" type="HBoxContainer" parent="body/left_body"]
layout_mode = 2
size_flags_horizontal = 3
[node name="host_address_input" type="LineEdit" parent="body/left_body/server_host_hbox"]
layout_mode = 2
size_flags_horizontal = 3
text = "127.0.0.1"
placeholder_text = "Server Address: (Eg. 0.0.0.0)"
alignment = 1
max_length = 12
emoji_menu_enabled = false
clear_button_enabled = true
caret_blink = true
[node name="host_port_range" type="SpinBox" parent="body/left_body/server_host_hbox"]
layout_mode = 2
min_value = 1.0
max_value = 65535.0
page = 10.0
value = 31315.0
rounded = true
alignment = 1
[node name="host_start_bttn" type="Button" parent="body/left_body/server_host_hbox"]
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_styles/normal = SubResource("StyleBoxFlat_e03fk")
text = "Start Host"
[node name="host_stop_bttn" type="Button" parent="body/left_body/server_host_hbox"]
visible = false
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_styles/normal = SubResource("StyleBoxFlat_lqt48")
text = "Stop Host"
[node name="search_vbox" type="VBoxContainer" parent="body/left_body"]
layout_mode = 2
size_flags_vertical = 3
[node name="search_hbox" type="HBoxContainer" parent="body/left_body/search_vbox"]
layout_mode = 2
size_flags_horizontal = 3
[node name="match_search_input" type="LineEdit" parent="body/left_body/search_vbox/search_hbox"]
layout_mode = 2
size_flags_horizontal = 3
placeholder_text = "Search Match List... "
max_length = 12
emoji_menu_enabled = false
clear_button_enabled = true
caret_blink = true
[node name="match_search_bttn" type="Button" parent="body/left_body/search_vbox/search_hbox"]
custom_minimum_size = Vector2(85, 0)
layout_mode = 2
mouse_default_cursor_shape = 2
text = "Search"
[node name="scroll_container" type="ScrollContainer" parent="body/left_body/search_vbox"]
layout_mode = 2
size_flags_vertical = 3
[node name="match_list" type="VBoxContainer" parent="body/left_body/search_vbox/scroll_container"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3