push project up
This commit is contained in:
4
.editorconfig
Normal file
4
.editorconfig
Normal file
@@ -0,0 +1,4 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Normalize EOL for all files that Git considers text files.
|
||||
* text=auto eol=lf
|
||||
7
addons/uuid/plugin.cfg
Normal file
7
addons/uuid/plugin.cfg
Normal file
@@ -0,0 +1,7 @@
|
||||
[plugin]
|
||||
|
||||
name="godot-uuid"
|
||||
description="Unique identifier generation v4 for Godot Engine"
|
||||
author="Binogure Studio"
|
||||
version="3.0.0"
|
||||
script="plugin.gd"
|
||||
10
addons/uuid/plugin.gd
Normal file
10
addons/uuid/plugin.gd
Normal file
@@ -0,0 +1,10 @@
|
||||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
const AUTOLOAD_NAME = 'uuid'
|
||||
|
||||
func _enable_plugin() -> void:
|
||||
add_autoload_singleton(AUTOLOAD_NAME, 'res://addons/uuid/uuid.gd')
|
||||
|
||||
func _disable_plugin() -> void:
|
||||
remove_autoload_singleton(AUTOLOAD_NAME)
|
||||
1
addons/uuid/plugin.gd.uid
Normal file
1
addons/uuid/plugin.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://by83vwyqmco65
|
||||
112
addons/uuid/uuid.gd
Normal file
112
addons/uuid/uuid.gd
Normal file
@@ -0,0 +1,112 @@
|
||||
# Note: The code might not be as pretty it could be, since it's written
|
||||
# in a way that maximizes performance. Methods are inlined and loops are avoided.
|
||||
extends Node
|
||||
|
||||
const BYTE_MASK: int = 0b11111111
|
||||
|
||||
static func uuidbin():
|
||||
# 16 random bytes with the bytes on index 6 and 8 modified
|
||||
return [
|
||||
randi() & BYTE_MASK, randi() & BYTE_MASK, randi() & BYTE_MASK, randi() & BYTE_MASK,
|
||||
randi() & BYTE_MASK, randi() & BYTE_MASK, ((randi() & BYTE_MASK) & 0x0f) | 0x40, randi() & BYTE_MASK,
|
||||
((randi() & BYTE_MASK) & 0x3f) | 0x80, randi() & BYTE_MASK, randi() & BYTE_MASK, randi() & BYTE_MASK,
|
||||
randi() & BYTE_MASK, randi() & BYTE_MASK, randi() & BYTE_MASK, randi() & BYTE_MASK,
|
||||
]
|
||||
|
||||
static func uuidbinrng(rng: RandomNumberGenerator):
|
||||
return [
|
||||
rng.randi() & BYTE_MASK, rng.randi() & BYTE_MASK, rng.randi() & BYTE_MASK, rng.randi() & BYTE_MASK,
|
||||
rng.randi() & BYTE_MASK, rng.randi() & BYTE_MASK, ((rng.randi() & BYTE_MASK) & 0x0f) | 0x40, rng.randi() & BYTE_MASK,
|
||||
((rng.randi() & BYTE_MASK) & 0x3f) | 0x80, rng.randi() & BYTE_MASK, rng.randi() & BYTE_MASK, rng.randi() & BYTE_MASK,
|
||||
rng.randi() & BYTE_MASK, rng.randi() & BYTE_MASK, rng.randi() & BYTE_MASK, rng.randi() & BYTE_MASK,
|
||||
]
|
||||
|
||||
static func v4():
|
||||
# 16 random bytes with the bytes on index 6 and 8 modified
|
||||
var b = uuidbin()
|
||||
|
||||
return '%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x' % [
|
||||
# low
|
||||
b[0], b[1], b[2], b[3],
|
||||
|
||||
# mid
|
||||
b[4], b[5],
|
||||
|
||||
# hi
|
||||
b[6], b[7],
|
||||
|
||||
# clock
|
||||
b[8], b[9],
|
||||
|
||||
# clock
|
||||
b[10], b[11], b[12], b[13], b[14], b[15]
|
||||
]
|
||||
|
||||
static func v4_rng(rng: RandomNumberGenerator):
|
||||
# 16 random bytes with the bytes on index 6 and 8 modified
|
||||
var b = uuidbinrng(rng)
|
||||
return '%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x' % [
|
||||
# low
|
||||
b[0], b[1], b[2], b[3],
|
||||
|
||||
# mid
|
||||
b[4], b[5],
|
||||
|
||||
# hi
|
||||
b[6], b[7],
|
||||
|
||||
# clock
|
||||
b[8], b[9],
|
||||
|
||||
# clock
|
||||
b[10], b[11], b[12], b[13], b[14], b[15]
|
||||
]
|
||||
|
||||
var _uuid: Array
|
||||
|
||||
func _init(rng := RandomNumberGenerator.new()):
|
||||
_uuid = uuidbinrng(rng)
|
||||
|
||||
func as_array():
|
||||
return _uuid.duplicate()
|
||||
|
||||
func as_dict(big_endian := true):
|
||||
if big_endian:
|
||||
return {
|
||||
"low" : (_uuid[0] << 24) + (_uuid[1] << 16) + (_uuid[2] << 8 ) + _uuid[3],
|
||||
"mid" : (_uuid[4] << 8 ) + _uuid[5],
|
||||
"hi" : (_uuid[6] << 8 ) + _uuid[7],
|
||||
"clock": (_uuid[8] << 8 ) + _uuid[9],
|
||||
"node" : (_uuid[10] << 40) + (_uuid[11] << 32) + (_uuid[12] << 24) + (_uuid[13] << 16) + (_uuid[14] << 8 ) + _uuid[15]
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"low" : _uuid[0] + (_uuid[1] << 8 ) + (_uuid[2] << 16) + (_uuid[3] << 24),
|
||||
"mid" : _uuid[4] + (_uuid[5] << 8 ),
|
||||
"hi" : _uuid[6] + (_uuid[7] << 8 ),
|
||||
"clock": _uuid[8] + (_uuid[9] << 8 ),
|
||||
"node" : _uuid[10] + (_uuid[11] << 8 ) + (_uuid[12] << 16) + (_uuid[13] << 24) + (_uuid[14] << 32) + (_uuid[15] << 40)
|
||||
}
|
||||
|
||||
func as_string():
|
||||
return '%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x' % [
|
||||
# low
|
||||
_uuid[0], _uuid[1], _uuid[2], _uuid[3],
|
||||
|
||||
# mid
|
||||
_uuid[4], _uuid[5],
|
||||
|
||||
# hi
|
||||
_uuid[6], _uuid[7],
|
||||
|
||||
# clock
|
||||
_uuid[8], _uuid[9],
|
||||
|
||||
# node
|
||||
_uuid[10], _uuid[11], _uuid[12], _uuid[13], _uuid[14], _uuid[15]
|
||||
]
|
||||
|
||||
func is_equal(other):
|
||||
# Godot Engine compares Array recursively
|
||||
# There's no need for custom comparison here.
|
||||
return _uuid == other._uuid
|
||||
1
addons/uuid/uuid.gd.uid
Normal file
1
addons/uuid/uuid.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bafv8ihtmdpf3
|
||||
42
export_presets.cfg
Normal file
42
export_presets.cfg
Normal file
@@ -0,0 +1,42 @@
|
||||
[preset.0]
|
||||
|
||||
name="Linux"
|
||||
platform="Linux"
|
||||
runnable=true
|
||||
advanced_options=true
|
||||
dedicated_server=false
|
||||
custom_features=""
|
||||
export_filter="all_resources"
|
||||
include_filter=""
|
||||
exclude_filter=""
|
||||
export_path="../../builds/desktop/billiards/lobby_server.x86_64"
|
||||
patches=PackedStringArray()
|
||||
encryption_include_filters=""
|
||||
encryption_exclude_filters=""
|
||||
seed=0
|
||||
encrypt_pck=false
|
||||
encrypt_directory=false
|
||||
script_export_mode=2
|
||||
|
||||
[preset.0.options]
|
||||
|
||||
custom_template/debug=""
|
||||
custom_template/release=""
|
||||
debug/export_console_wrapper=1
|
||||
binary_format/embed_pck=false
|
||||
texture_format/s3tc_bptc=true
|
||||
texture_format/etc2_astc=false
|
||||
shader_baker/enabled=false
|
||||
binary_format/architecture="x86_64"
|
||||
ssh_remote_deploy/enabled=false
|
||||
ssh_remote_deploy/host="user@host_ip"
|
||||
ssh_remote_deploy/port="22"
|
||||
ssh_remote_deploy/extra_args_ssh=""
|
||||
ssh_remote_deploy/extra_args_scp=""
|
||||
ssh_remote_deploy/run_script="#!/usr/bin/env bash
|
||||
export DISPLAY=:0
|
||||
unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"
|
||||
\"{temp_dir}/{exe_name}\" {cmd_args}"
|
||||
ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash
|
||||
kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\")
|
||||
rm -rf \"{temp_dir}\""
|
||||
7
globals/globals.gd
Normal file
7
globals/globals.gd
Normal file
@@ -0,0 +1,7 @@
|
||||
extends Node
|
||||
|
||||
|
||||
var game_data: GameData
|
||||
var game_state: GameState
|
||||
var lobby_data: LobbyData
|
||||
var multiplayer_data: MultiplayerData
|
||||
1
globals/globals.gd.uid
Normal file
1
globals/globals.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://biu64hvcxb1su
|
||||
69
globals/instance_launcher.gd
Normal file
69
globals/instance_launcher.gd
Normal file
@@ -0,0 +1,69 @@
|
||||
extends Node
|
||||
|
||||
|
||||
var port_range_start: int = 5000
|
||||
var port_range_end: int = 5010
|
||||
var threads: Dictionary = Dictionary()
|
||||
|
||||
|
||||
func _wait_for_child(id: String, port: String, mode: String) -> void:
|
||||
if port == "-1":
|
||||
call_deferred("_child_finished", id, -1)
|
||||
return
|
||||
|
||||
var output := []
|
||||
var exit_code := OS.execute(
|
||||
"./game.sh", ["--", "server_" + port, "game", mode],
|
||||
output,
|
||||
true
|
||||
)
|
||||
|
||||
call_deferred("_child_finished", id, exit_code)
|
||||
|
||||
func _child_finished(id: String, exit_code: int) -> void:
|
||||
var thread: Thread = threads.get(id)
|
||||
if not thread: return
|
||||
|
||||
push_warning("Game Server [ %s ] Exited: %d" % [id, exit_code])
|
||||
|
||||
thread.wait_to_finish()
|
||||
threads.erase(id)
|
||||
|
||||
func is_port_free(port: int) -> bool:
|
||||
var server := TCPServer.new()
|
||||
var state := server.listen(port)
|
||||
|
||||
match state:
|
||||
OK:
|
||||
server.stop()
|
||||
return true
|
||||
_:
|
||||
return false
|
||||
|
||||
func find_free_port(start_port: int = 1024, end_port: int = 65535) -> int:
|
||||
for port in range(start_port, end_port + 1):
|
||||
if is_port_free(port):
|
||||
return port
|
||||
|
||||
return -1
|
||||
|
||||
func launch_game_server(mode: String) -> String:
|
||||
var thread := Thread.new()
|
||||
var thread_id := str( thread.get_instance_id() )
|
||||
var port := str(
|
||||
find_free_port(
|
||||
port_range_start,
|
||||
port_range_end
|
||||
)
|
||||
)
|
||||
|
||||
thread.start(
|
||||
_wait_for_child.bind(
|
||||
thread_id,
|
||||
port,
|
||||
mode
|
||||
)
|
||||
)
|
||||
|
||||
threads.set(thread_id, thread)
|
||||
return port
|
||||
1
globals/instance_launcher.gd.uid
Normal file
1
globals/instance_launcher.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cru35twp27pa4
|
||||
1
icon.svg
Normal file
1
icon.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>
|
||||
|
After Width: | Height: | Size: 995 B |
43
icon.svg.import
Normal file
43
icon.svg.import
Normal file
@@ -0,0 +1,43 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b6xgtqmx8kjor"
|
||||
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://icon.svg"
|
||||
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
30
project.godot
Normal file
30
project.godot
Normal file
@@ -0,0 +1,30 @@
|
||||
; Engine configuration file.
|
||||
; It's best edited using the editor UI and not directly,
|
||||
; since the parameters that go here are not all obvious.
|
||||
;
|
||||
; Format:
|
||||
; [section] ; section goes between []
|
||||
; param=value ; assign values to parameters
|
||||
|
||||
config_version=5
|
||||
|
||||
[application]
|
||||
|
||||
config/name="Lobby Server"
|
||||
run/main_scene="uid://b0cqo3qo62y6n"
|
||||
config/features=PackedStringArray("4.5", "GL Compatibility")
|
||||
config/icon="res://icon.svg"
|
||||
|
||||
[autoload]
|
||||
|
||||
Globals="*res://globals/globals.gd"
|
||||
InstanceLauncher="*res://globals/instance_launcher.gd"
|
||||
|
||||
[display]
|
||||
|
||||
window/size/always_on_top=true
|
||||
|
||||
[rendering]
|
||||
|
||||
renderer/rendering_method="gl_compatibility"
|
||||
renderer/rendering_method.mobile="gl_compatibility"
|
||||
20
scenes/data_bridge/bridge.tscn
Normal file
20
scenes/data_bridge/bridge.tscn
Normal 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")
|
||||
14
scenes/data_bridge/game_data.gd
Normal file
14
scenes/data_bridge/game_data.gd
Normal 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
|
||||
1
scenes/data_bridge/game_data.gd.uid
Normal file
1
scenes/data_bridge/game_data.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dbnl4tjahkoun
|
||||
23
scenes/data_bridge/game_state.gd
Normal file
23
scenes/data_bridge/game_state.gd
Normal 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
|
||||
1
scenes/data_bridge/game_state.gd.uid
Normal file
1
scenes/data_bridge/game_state.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://65x4bq2wsh8k
|
||||
183
scenes/data_bridge/lobby_data.gd
Normal file
183
scenes/data_bridge/lobby_data.gd
Normal 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
|
||||
1
scenes/data_bridge/lobby_data.gd.uid
Normal file
1
scenes/data_bridge/lobby_data.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dyq4p5e06ib14
|
||||
10
scenes/data_bridge/multiplayer_data.gd
Normal file
10
scenes/data_bridge/multiplayer_data.gd
Normal 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
|
||||
1
scenes/data_bridge/multiplayer_data.gd.uid
Normal file
1
scenes/data_bridge/multiplayer_data.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://uyimqfjmuc34
|
||||
42
scenes/screens/lobby_screen/lobby.gd
Normal file
42
scenes/screens/lobby_screen/lobby.gd
Normal 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
|
||||
1
scenes/screens/lobby_screen/lobby.gd.uid
Normal file
1
scenes/screens/lobby_screen/lobby.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dk7afnf7ol7dy
|
||||
34
scenes/screens/lobby_screen/lobby.tscn
Normal file
34
scenes/screens/lobby_screen/lobby.tscn
Normal 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"]
|
||||
39
scenes/screens/lobby_screen/lobby_base.gd
Normal file
39
scenes/screens/lobby_screen/lobby_base.gd
Normal 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
|
||||
1
scenes/screens/lobby_screen/lobby_base.gd.uid
Normal file
1
scenes/screens/lobby_screen/lobby_base.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://5tvhtoe6fdu1
|
||||
29
scenes/screens/lobby_screen/lobby_rpc.gd
Normal file
29
scenes/screens/lobby_screen/lobby_rpc.gd
Normal 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
|
||||
1
scenes/screens/lobby_screen/lobby_rpc.gd.uid
Normal file
1
scenes/screens/lobby_screen/lobby_rpc.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://6sfwe1hwgf0g
|
||||
8
scenes/screens/lobby_screen/match_entry.gd
Normal file
8
scenes/screens/lobby_screen/match_entry.gd
Normal 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 = ""
|
||||
1
scenes/screens/lobby_screen/match_entry.gd.uid
Normal file
1
scenes/screens/lobby_screen/match_entry.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ck663xy8rqumo
|
||||
23
scenes/screens/lobby_screen/match_entry.tscn
Normal file
23
scenes/screens/lobby_screen/match_entry.tscn
Normal 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"
|
||||
107
scenes/ui_controls/lobby_screen/lobby_ui.tscn
Normal file
107
scenes/ui_controls/lobby_screen/lobby_ui.tscn
Normal 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
|
||||
51
scripts/server_networking.gd
Normal file
51
scripts/server_networking.gd
Normal file
@@ -0,0 +1,51 @@
|
||||
extends Node
|
||||
|
||||
|
||||
var peer: ENetMultiplayerPeer
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
pass
|
||||
|
||||
|
||||
func start_server(address: String = "0.0.0.0", port: int = 8080) -> void:
|
||||
if peer: return
|
||||
|
||||
push_warning("Server Starting... Address: ", address, " Port: ", port)
|
||||
|
||||
peer = ENetMultiplayerPeer.new()
|
||||
peer.set_bind_ip(address)
|
||||
|
||||
var state = peer.create_server(port)
|
||||
match state:
|
||||
OK:
|
||||
push_warning("Server Started: ", state)
|
||||
|
||||
multiplayer.multiplayer_peer = peer
|
||||
multiplayer.peer_connected.connect(server_client_connected)
|
||||
multiplayer.peer_disconnected.connect(server_client_disconnected)
|
||||
|
||||
get_parent()._server_host_started()
|
||||
ERR_ALREADY_IN_USE:
|
||||
peer.close()
|
||||
peer = null
|
||||
start_server(address, port)
|
||||
ERR_CANT_CREATE:
|
||||
push_warning("Couldn't create server...")
|
||||
|
||||
func close_connection() -> void:
|
||||
if not peer: return
|
||||
|
||||
push_warning("Server Closed...")
|
||||
|
||||
multiplayer.peer_connected.disconnect(server_client_connected)
|
||||
multiplayer.peer_disconnected.disconnect(server_client_disconnected)
|
||||
|
||||
peer.close()
|
||||
peer = null
|
||||
|
||||
func server_client_connected(id: int) -> void:
|
||||
Globals.lobby_data.server_client_connected(id)
|
||||
|
||||
func server_client_disconnected(id: int) -> void:
|
||||
Globals.lobby_data.server_client_disconnected(id)
|
||||
1
scripts/server_networking.gd.uid
Normal file
1
scripts/server_networking.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bvqtgf3vbsoj4
|
||||
50
server.gd
Normal file
50
server.gd
Normal file
@@ -0,0 +1,50 @@
|
||||
extends Node
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
# Note that the lobby server is looking for a script local to it titled 'game.sh'
|
||||
#
|
||||
# Editor -> Debug > Customize Run Instance
|
||||
#
|
||||
#
|
||||
# -- name_billiards server game_port_range 5000:5010
|
||||
#
|
||||
#
|
||||
# CLI
|
||||
#
|
||||
# ./lobby_server.sh -- name_billiards server game_port_range 5000:5010
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
for arg in OS.get_cmdline_user_args():
|
||||
if "name_" in arg:
|
||||
name_(arg)
|
||||
|
||||
match arg:
|
||||
"server":
|
||||
server(arg)
|
||||
"game_port_range":
|
||||
game_port_range(arg)
|
||||
_:
|
||||
pass
|
||||
|
||||
|
||||
func name_(arg: String) -> void:
|
||||
var game_name = arg.split("_")[-1]
|
||||
self.name = game_name
|
||||
|
||||
func server(_arg: String) -> void:
|
||||
Globals.game_state.set_game_scene(
|
||||
"res://scenes/screens/lobby_screen/lobby.tscn"
|
||||
)
|
||||
|
||||
$scene/lobby_screen.find_child("host_start_bttn", true, false).emit_signal("pressed")
|
||||
|
||||
func game_port_range(_arg: String) -> void:
|
||||
var port_range = OS.get_cmdline_user_args()[-1].split(":")
|
||||
|
||||
InstanceLauncher.port_range_start = port_range[0]
|
||||
InstanceLauncher.port_range_end = port_range[1]
|
||||
1
server.gd.uid
Normal file
1
server.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://chu1htrspx5su
|
||||
12
server.tscn
Normal file
12
server.tscn
Normal file
@@ -0,0 +1,12 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://b0cqo3qo62y6n"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://chu1htrspx5su" path="res://server.gd" id="1_ob30c"]
|
||||
[ext_resource type="PackedScene" uid="uid://dy51wny4x53f4" path="res://scenes/data_bridge/bridge.tscn" id="2_h8t3n"]
|
||||
|
||||
[node name="server" type="Node"]
|
||||
editor_description = "Note: The root node needs to match game's client root node in order for proper sync talk."
|
||||
script = ExtResource("1_ob30c")
|
||||
|
||||
[node name="bridge" parent="." instance=ExtResource("2_h8t3n")]
|
||||
|
||||
[node name="scene" type="Node" parent="."]
|
||||
Reference in New Issue
Block a user