Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/project.godot
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ boot_splash/minimum_display_time=1000

[autoload]

LaunchArguments="*res://scripts/LaunchArguments.gd"
GlobalLogger="*res://scripts/Logger.gd"
FileManager="*res://scripts/Files.gd"
Util="*res://scripts/Util.gd"
CredentialStore="*res://scripts/credential_store.gd"
AccountServers="*res://scripts/account_servers.gd"
LaunchArguments="*uid://c45jrfmrjtnyn"
GlobalLogger="*uid://dgmfafi41y1nk"
FileManager="*uid://d2s50p717g3n"
AccountServers="*uid://bpysjoq7n0ytu"
CredentialStore="*uid://cs4c0ctis2flp"
Random="*uid://1js68qt8w0mv"

[display]

Expand Down
181 changes: 49 additions & 132 deletions src/scenes/managers/app/network_manager.gd
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
extends Node

var n_c = preload("res://scripts/network_compression.gd").new()
var jwt = preload("res://scripts/jwt.gd").new()
var n_c = preload("res://scripts/network/network_compression.gd").new()
var jwt = preload("res://scripts/crypto/jwt.gd").new()
var rsa = preload("res://scripts/crypto/rsa.gd").new()
var url_regex = RegEx.create_from_string("^(https?)://([^/:]+)(?::(\\d+))?(.*)$")

# TODO: Bandwidth toggles
@onready var scene_manager = get_tree().current_scene.get_node("SceneManager")
@onready var multiplayer_manager = get_tree().current_scene.get_node("MultiplayerManager")
@onready var rpc_lib = get_tree().current_scene.get_node("RpcManager")

var active_session = ""

# This file contains all of the session management and client communication.
# Anything that goes through the network should first route through here at some point.
Expand Down Expand Up @@ -34,40 +37,47 @@ var info = {
"clients": []
}

func _ready():
multiplayer.peer_connected.connect(_on_peer_connected)
multiplayer.peer_disconnected.connect(_on_peer_disconnected)

multiplayer.connected_to_server.connect(_on_connected)
multiplayer.connection_failed.connect(_on_connection_failed)

func start_server(port: int = config.port, max_clients: int = config.max_clients) -> void:
func start_server(port: int = config.port, max_clients: int = config.max_clients, ignore_port: bool = false) -> void:
# TODO: In ignore_port = true, keep trying to make a server until it succeeds.
if status.hosting:
# This ideally should not trigger
GlobalLogger.log_string("Can not start server: Server is already running.", 2)
GlobalLogger.logs("Can not start server: Server is already running.", 2)
status.hosting = false
status.client = false
return

var new_peer = ENetMultiplayerPeer.new()
# FIXME: Error handling is required here
info.clients.append({"username": "Me!", "multiplayer_id": 1})
var err = new_peer.create_server(port, max_clients)
# FIXME: This client append is happening too early, this is a debug position
info.clients.append({"display_name": "Me!", "multiplayer_id": 1})

if err == 20:
# Port is in use
GlobalLogger.logs("Failed to start server: Is the port in use?", 1)
# FIXME: HACK: Just try again with the default port + 1.
err = new_peer.create_server(port + 1, max_clients)
status.hosting = false
status.client = false

if err != OK:
GlobalLogger.log_string("Failed to start server.", 3)
GlobalLogger.logs("Failed to start server. Error: '%s'" % err, 1)
status.hosting = false
status.client = false
return


multiplayer.multiplayer_peer = new_peer
GlobalLogger.log_string("Successfully started server.", 1)
GlobalLogger.logs("Successfully started server.", 1)

while status.hosting == false:
await get_tree().process_frame
status.hosting = true
status.client = false


# TODO: Hardcoded spawn host value, is there a better way?
rpc_lib.com.on_spawn_player(1)

func close_server():
# Disconnect all players.
# Remove listings from all used networking.
Expand All @@ -82,65 +92,43 @@ func close_server():
func update_server():
# Update our config.
# Submit a update to any active networking service.
GlobalLogger.logs("Not implemented.", 3)
return

func join_server(ip: String = "", port: int = config.port) -> void:
# Client connects to a server.
if ip.is_empty():
GlobalLogger.log_string("No IP to connect to.", 2)
GlobalLogger.logs("No IP to connect to.", 2)
return

if status.hosting:
# This ideally should not trigger
GlobalLogger.log_string("Can not join server: We are currently hosting a server.", 2)
return
GlobalLogger.logs("Can not join server: We are currently hosting a server.", 2)
close_server()
# return

var new_peer = ENetMultiplayerPeer.new()
new_peer.create_client(ip, port)
multiplayer.multiplayer_peer = new_peer

status.hosting = false
status.client = true
GlobalLogger.log_string("Connected to the server.", 1)
GlobalLogger.logs("Connected to the server.", 1)
return

func kick_player(player_id: int, reason: String = "No reason specified"):
# Server kicks a player from the session.
GlobalLogger.logs("Not implemented.", 3)
return

func ban_player():
# Server permanatly bans a user.
return

func _on_connected():
# We are connected to the server.
GlobalLogger.log_string("Connected to the server as '%s'." % multiplayer.get_unique_id(), 1)
return

func _on_connection_failed():
GlobalLogger.log_string("Connection to server failed.", 1)
return

func _on_peer_connected(client_id):
info.level_node_name = get_tree().current_scene.get_node("Scenes").get_child(0).name

# A client has been connected to our server.
if multiplayer.is_server() == false:
return

# TODO: Preform validation to determine if the player is allowed to be here

GlobalLogger.log_string("'%s' connected to us. Sending our server info." % multiplayer.get_unique_id(), 1)
_receive_server_info.rpc_id(client_id, info)

return

func _on_peer_disconnected():
GlobalLogger.logs("Not implemented.", 3)
return

func set_networking_config(options: Dictionary) -> void:
if !options:
GlobalLogger.log_string("Tried to set networking config without options", 2)
GlobalLogger.logs("Tried to set networking config without options", 2)
return

# LAN connections
Expand All @@ -155,90 +143,6 @@ func set_networking_config(options: Dictionary) -> void:
else:
config.use_steam = false

@rpc("authority", "reliable")
func _receive_server_info(server_info: Dictionary):
GlobalLogger.log_string("Received server information.")
# TODO: Do not change scene until connection is finalized.

if server_info.level:
await scene_manager.load_multiplayer_scene(server_info.level, server_info.level_node_name)

_send_player_info(CredentialStore.info.token)

@rpc("any_peer", "reliable")
func _receive_player_info(player_info: String):
# TODO: Error checks for JWT
if multiplayer.is_server() == false:
# We are a client. We should not process any farther.
return

GlobalLogger.log_string("Received '%s' player info." % multiplayer.get_remote_sender_id())

# TODO: Preform validation to determine if the player is allowed to be here
# TODO: Preform validation to determine if the player supplied cridentials are good, where they need to be.

# Preform validation of JWT token
var player_info_dic = _sanity_check_player_info(player_info, multiplayer.get_remote_sender_id())
var player_decoded_jwt = jwt.decode_jwt(player_info_dic.jwt)

# TODO: util function to break down a url to the key parts.
var url_parts = parse_url(player_decoded_jwt.payload.issuer)
var host_pub_key = await AccountServers._request_server_pem(url_parts.host, url_parts.port)

var jwt_is_valid = jwt.verify(player_info_dic.jwt, host_pub_key)

if jwt_is_valid == false:
# TODO: Refuse connection
multiplayer.multiplayer_peer.disconnect_peer(multiplayer.get_remote_sender_id())
return

info.clients.append(player_info_dic)

# Spawn player
multiplayer_manager.spawn_player(player_info_dic.multiplayer_id)
multiplayer_manager.rpc("spawn_player", player_info_dic.multiplayer_id)

# Spawn all connected clients on the new client
for client in info.clients:
if client.multiplayer_id == player_info_dic.multiplayer_id:
continue
multiplayer_manager.rpc_id(player_info_dic.multiplayer_id, "spawn_player", client.multiplayer_id)

send_server_session_info()

func _send_player_info(player_info: String):
GlobalLogger.log_string("Starting server handshake: Sending information about ourself.")
_receive_player_info.rpc_id(1, player_info)

func send_server_session_info() -> void:
rpc("received_server_session_info", info)

@rpc("authority", "reliable")
func received_server_session_info(received_info: Dictionary) -> void:
GlobalLogger.log_string("Session information updated.")
info = received_info
return

# TODO: Handle kick from server
# TODO: Handle ban from server
# TODO: Add item to player inventory
# TODO: Remove item from player inventory
# TODO: Check if item exists in player inventory
# TODO: Get player inventory

func _sanity_check_player_info(player_info: String, multiplayer_id: int) -> Dictionary:
var sane_player_info = {
"jwt": "",
"multiplayer_id": "",
"display_name": "Greetings!"
}

sane_player_info.jwt = str(player_info)
sane_player_info.multiplayer_id = int(multiplayer_id)

return sane_player_info


func parse_url(url: String) -> Dictionary:
var result = {
"scheme": "",
Expand All @@ -254,4 +158,17 @@ func parse_url(url: String) -> Dictionary:
result["port"] = int(matches.get_string(3)) if matches.get_string(3) != "" else (443 if result["scheme"] == "https" else 80)
result["path"] = matches.get_string(4) if matches.get_string(4) != "" else "/"

return result
return result

func spawn_player(player):
# FIXME: Placeholder for refactor
while scene_manager.get_current_session_node() == null:
await get_tree().process_frame

scene_manager.get_current_session_node().call_deferred("add_child", player)

func player_exists(name: String) -> Node3D:
# FIXME: Placeholder for refactor
var target_node = scene_manager.get_current_session_node().get_node_or_null(name)

return target_node
16 changes: 16 additions & 0 deletions src/scenes/managers/app/rpc_manager.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
extends Node

var c := preload("res://scripts/rpc/client.gd").new()
var s := preload("res://scripts/rpc/server.gd").new()
var com := preload("res://scripts/rpc/common.gd").new()

func _ready():
# RPCs can not be called from outside of the scene tree, we are required to add them.
add_child(c)
add_child(s)
add_child(com)

multiplayer.peer_connected.connect(s.on_peer_connected)
multiplayer.peer_disconnected.connect(s.on_peer_disconnected)
multiplayer.connected_to_server.connect(c.connected_to_server)
multiplayer.connection_failed.connect(c.connection_failed)
1 change: 1 addition & 0 deletions src/scenes/managers/app/rpc_manager.gd.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://x23lqbiivx1q
6 changes: 6 additions & 0 deletions src/scenes/managers/app/rpc_manager.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[gd_scene format=3 uid="uid://by0vghgshvbhd"]

[ext_resource type="Script" uid="uid://x23lqbiivx1q" path="res://scenes/managers/app/rpc_manager.gd" id="1_6timl"]

[node name="RpcManager" type="Node" unique_id=1836544617]
script = ExtResource("1_6timl")
11 changes: 5 additions & 6 deletions src/scenes/managers/app/scene_manager.gd
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ extends Node

# Game managers
@onready var network_manager = get_tree().current_scene.get_node("NetworkManager")
@onready var multiplayer_manager = get_tree().current_scene.get_node("MultiplayerManager")

@onready var scene_work_root = get_tree().current_scene.get_node("Scenes")
@onready var player_home_scene: PackedScene = load("res://scenes/levels/home.tscn")
Expand All @@ -14,10 +13,10 @@ var server_init: bool = false

func _ready():
await network_manager.start_server()
var session_name = Util.random_string(6)
var session_name = Random.random_string(6)
var new_home = player_home_scene.instantiate()
new_home.name = session_name
multiplayer_manager.active_session = session_name
network_manager.active_session = session_name
scene_work_root.add_child(new_home)

_spawn_host_player()
Expand All @@ -29,20 +28,20 @@ func load_multiplayer_scene(scene_dir: String, scene_name: String):
var scene = scene_packed.instantiate()
scene.name = scene_name
scene_work_root.add_child(scene)
multiplayer_manager.active_session = scene_name
network_manager.active_session = scene_name
await get_tree().process_frame
return

func _clean_scene_work_root():
multiplayer_manager.active_session = ""
network_manager.active_session = ""
var nodes_to_destroy = scene_work_root.get_children()
for node in nodes_to_destroy:
node.queue_free()
await get_tree().process_frame
return

func _spawn_host_player():
multiplayer_manager.spawn_player(1)
network_manager.spawn_player(1)

func get_current_session_node():
return get_tree().current_scene.get_node("Scenes").get_child(0)
29 changes: 0 additions & 29 deletions src/scenes/managers/level/multiplayer_manager.gd

This file was deleted.

1 change: 0 additions & 1 deletion src/scenes/managers/level/multiplayer_manager.gd.uid

This file was deleted.

6 changes: 0 additions & 6 deletions src/scenes/managers/level/multiplayer_manager.tscn

This file was deleted.

Loading