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
4 changes: 3 additions & 1 deletion src/project.godot
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ Events="*uid://c656spc3ppdlw"
OAuth="*uid://jd7qlsley1no"
SessionQuery="*uid://bl3e1utjvw3ul"
Enum="*uid://b5amtwc5yahe3"
UrlParser="*uid://budprjmmpally"
Bootstrap="*uid://big7h126wcmk8"
NetworkCompression="*uid://b2iq75uom64x2"
HTTP="*uid://d3cnfdwjxopsx"
UrlParser="*uid://budprjmmpally"

[display]

Expand Down
4 changes: 4 additions & 0 deletions src/scenes/levels/base.tscn
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
[gd_scene format=3 uid="uid://bysrhijnau31g"]

[ext_resource type="Script" uid="uid://bx6abcqetw04c" path="res://scenes/managers/scene/entity.gd" id="1_5on25"]
[ext_resource type="Script" uid="uid://c13l6ywhxq6n5" path="res://scenes/managers/scene/player.gd" id="1_c3hqj"]
[ext_resource type="Script" uid="uid://ckxuws4l4alod" path="res://scenes/managers/scene/network.gd" id="1_fundk"]
[ext_resource type="Script" uid="uid://cxbdjoelope42" path="res://scenes/managers/scene/signalbus.gd" id="2_fundk"]

[node name="Base" type="Node3D" unique_id=2084163635]

[node name="EntityManager" type="Node" parent="." unique_id=1378414814]
script = ExtResource("1_5on25")

[node name="NetworkManager" type="Node" parent="." unique_id=2144728320]
script = ExtResource("1_fundk")

Expand Down
148 changes: 108 additions & 40 deletions src/scenes/managers/app/network.gd
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,9 @@ extends Node
const MAX_CLIENTS = 1000
const MINIMUM_INCREMENTAL_PORT = 20205

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

@onready var http = preload("res://scripts/network/http.gd").new()
@onready var scene_m = get_tree().current_scene.get_node("SceneManager")
@onready var rpc_lib = get_tree().current_scene.get_node("RpcManager")
@onready var scene_m = get_node("../SceneManager")

var _database = {
"heartbeats": {},
Expand All @@ -33,6 +30,7 @@ const _instance_database_template = {
"port": 0,
"max_connected_users": 1,
"privacy": null,
"active": false,

"connected_players": [],
"start_time": 0,
Expand All @@ -45,6 +43,7 @@ const _instance_database_template = {

func start_server(port: int = 0, root_scene: Enum.BaseLevel = Enum.BaseLevel.GRID) -> Dictionary:
var response_dict = {"ok": false, "error": null, "data": null}
GlobalLogger.logs("Starting a new server.")

# Get an available port. If port was defined, force that port or fail.
if port != 0:
Expand Down Expand Up @@ -76,13 +75,13 @@ func start_server(port: int = 0, root_scene: Enum.BaseLevel = Enum.BaseLevel.GRI
get_tree().set_multiplayer(_mp_api, master_scene.get_path())
_mp_api.set_root_path(master_scene.get_path())
var net_manager = master_scene.get_node("NetworkManager")
net_manager.setup_connection(_mp_api)
net_manager.setup_connection(_mp_api, _scene)

_database.sessions_api.set(_scene, _mp_api)
_database.sessions.set(_scene, _instance)

if _create_server_response != OK:
GlobalLogger.logs("Failed to start server. Error: '%s'" % _create_server_response, 1)
GlobalLogger.logs("Failed to start server. Error: '%s'" % _create_server_response, Enum.LogLevel.INFO)
response_dict.error = str(_create_server_response)

_database.sessions_api.erase(_scene)
Expand All @@ -95,34 +94,55 @@ func start_server(port: int = 0, root_scene: Enum.BaseLevel = Enum.BaseLevel.GRI
return start_server(0, root_scene)

return response_dict

# Create server root scene.
if root_scene:
scene_m.set_master_root_from_program(_scene, root_scene)
else:
scene_m.set_master_root_from_program(_scene, Enum.BaseLevel.GRID)

scene_m.start_master_scene(_scene)

# DEV: Force spawn the host.
scene_m.get_master_scene(_scene).get_node("PlayerManager").spawn_player(1)
scene_m.get_master_scene(_scene).get_node("PlayerManager").add_player(1)
scene_m.set_active_session(_scene)

return response_dict

func stop_server(_id: String):
GlobalLogger.logs("'%s' is not implemented." % get_stack()[0]["function"], 3)
# Kick all players (Server closing).
# Turn off all join requests.
# Destroy multiplayer api.
# Stop all managers.
# Destroy server master scene.
func stop_server(id: String):
var database_has_sessions: bool = _database.sessions.has(id)
var database_has_sessions_api: bool = _database.sessions_api.has(id)
GlobalLogger.logs("Stopping server '%s'." % id)

# TODO: Disable join requests to server

if !database_has_sessions && !database_has_sessions_api:
GlobalLogger.logs("Session '%s' does not exist, cannot stop the server." % id, Enum.LogLevel.WARNING)
return

if database_has_sessions_api:
var mp_api: SceneMultiplayer = _database.sessions_api.get(id)
var all_peers = mp_api.get_peers()

# Kick all players
for _peer in all_peers:
kick_player(id, _peer, "Server Closing")

# Close the server
mp_api.multiplayer_peer.close()
mp_api.multiplayer_peer = null

# Application cleanup
scene_m.stop_master_scene(id)
scene_m.destroy_master_scene(id)

# Database cleanup
_database.sessions_api.erase(id)
_database.sessions.erase(id)
return

func update_server(id: String, server_info: Dictionary):
# Get server from database.
# Validate server updated data.
# Update the database entry.
# Emit server updated event to the server.
GlobalLogger.logs("Updating server '%s'." % id)
var _saved_session_servers = SettingsManager.get_session_servers()

if server_info.privacy > Enum.PrivacyLevel.INVITE:
Expand All @@ -141,19 +161,21 @@ func update_server(id: String, server_info: Dictionary):
if _database.heartbeats.has(id):
GlobalLogger.logs("Destroying session heartbeat for '%s'" % id)
_database.heartbeats.erase(id)

for _server in _saved_session_servers:
_remove_session_from_server(id, _server.url)

Events.emit_signal("instance_updated")
return

func join_server(ip: String, port: int):
var response_dict = {"ok": false, "error": null, "data": null}

GlobalLogger.logs("Joining server at '%s:%s'" % [ip, port], 1)
GlobalLogger.logs("Joining server at '%s:%s'" % [ip, port], Enum.LogLevel.INFO)
var _port_is_valid = port > 0 && port < 65535

if ip.is_empty() || !_port_is_valid:
GlobalLogger.logs("Server information is invalid '%s:%s'." % [ip, port], 1)
GlobalLogger.logs("Server information is invalid '%s:%s'." % [ip, port], Enum.LogLevel.INFO)
response_dict.error = "Server information is invalid."
return response_dict

Expand All @@ -171,9 +193,8 @@ func join_server(ip: String, port: int):
var _session_peer = ENetMultiplayerPeer.new()
var connect_error = _session_peer.create_client(ip, port)


if connect_error != OK:
GlobalLogger.logs("Failed to join server. Error: '%s'" % connect_error, 1)
GlobalLogger.logs("Failed to join server. Error: '%s'" % connect_error, Enum.LogLevel.INFO)
response_dict.error = "Failed to join server. Error: '%s'" % connect_error
return response_dict

Expand All @@ -183,19 +204,50 @@ func join_server(ip: String, port: int):
get_tree().set_multiplayer(_mp_api, master_scene.get_path())
_mp_api.set_root_path(master_scene.get_path())
var net_manager = master_scene.get_node("NetworkManager")
net_manager.setup_connection(_mp_api)
net_manager.setup_connection(_mp_api, _scene)

_database.sessions_api.set(_scene, _mp_api)
_database.sessions.set(_scene, _instance)


Events.emit_signal("session_joined")
return

func leave_server(id: String):
GlobalLogger.logs("Trying to leave server '%s'." % id)
var database_has_sessions: bool = _database.sessions.has(id)
var database_has_sessions_api: bool = _database.sessions_api.has(id)

if !database_has_sessions && !database_has_sessions_api:
GlobalLogger.logs("Session '%s' does not exist, cannot disconnect." % id, Enum.LogLevel.WARNING)
return

if database_has_sessions_api:
var mp_api: SceneMultiplayer = _database.sessions_api.get(id)

if mp_api.multiplayer_peer:
mp_api.multiplayer_peer.close()
GlobalLogger.logs("Disconnected from session '%s'." % id, Enum.LogLevel.DEBUG)

scene_m.set_active_session(get_connected_sessions()[0].id)

scene_m.stop_master_scene(id)
scene_m.destroy_master_scene(id)

_database.sessions_api.erase(id)
_database.sessions.erase(id)

GlobalLogger.logs("Successfully disconnected from session '%s' and cleaned up." % id, Enum.LogLevel.DEBUG)
Events.emit_signal("session_left")
return

func leave_server(_id: String):
GlobalLogger.logs("'%s' is not implemented." % get_stack()[0]["function"], 3)
# Get server from database.
# Send leave packet.
# Destroy multiplayer API.
# Destroy server master scene.
func kick_player(server_id:String, peer_id: int, reason: String):
GlobalLogger.logs("Kicking peer '%s' from '%s' for reason '%s'" % [peer_id, server_id, reason], Enum.LogLevel.DEBUG)
var database_has_sessions_api: bool = _database.sessions_api.has(server_id)
# TODO: Check if peer exists
if database_has_sessions_api:
var mp_api: SceneMultiplayer = _database.sessions_api.get(server_id)
# TODO: Notify user of kick
mp_api.disconnect_peer(peer_id)
return

func get_connected_sessions():
Expand All @@ -206,6 +258,22 @@ func get_connected_sessions():

return result

func set_active_session(id: String):
if _database.sessions.has(id):
GlobalLogger.logs("Tried to mark an invalid session as active: '%s'" % id, Enum.LogLevel.WARNING)
return

for session_id in _database.sessions.keys():
var my_id = _database.sessions_api[session_id].multiplayer.get_unique_id()
_database.sessions[session_id].active = false
scene_m.get_master_root(session_id).get_node("PlayerManager").players.get(my_id).get("node").camera.current = false

var my_id = _database.sessions_api[id].multiplayer.get_unique_id()
scene_m.get_master_root(id).get_node("PlayerManager").players.get(my_id).get("node").camera.current = true
_database.sessions[id].active = true
scene_m.set_active_session(id)
return

func _update_session_server_listing(session_info: Dictionary, session_server: String) -> Dictionary:
var response_dict = {"ok": false, "error": null, "data": null}

Expand All @@ -226,7 +294,7 @@ func _update_session_server_listing(session_info: Dictionary, session_server: St
"session_privacy": session_info.privacy,
}

var _update_response = await http.req(
var _update_response = await HTTP.req(
HTTPClient.Method.METHOD_POST,
url.host,
url.path,
Expand Down Expand Up @@ -255,7 +323,7 @@ func _remove_session_from_server(server_id: String, session_server: String) -> D
"id": _database.sessions_id.get(server_id),
}

var _removal_response = await http.req(
var _removal_response = await HTTP.req(
HTTPClient.Method.METHOD_DELETE,
url.host,
url.path,
Expand Down Expand Up @@ -335,8 +403,8 @@ func _heartbeat_session(session_id: String, session_server_url: String) -> void:

_url = _url.data
var body = {"session_id": _database.sessions_id.get(session_id)}
var response = await http.req(

var response = await HTTP.req(
HTTPClient.Method.METHOD_POST,
_url.host,
_url.path,
Expand All @@ -346,7 +414,7 @@ func _heartbeat_session(session_id: String, session_server_url: String) -> void:
)

if response and response.get("ok"):
GlobalLogger.logs("Heartbeat sent for session '%s'" % session_id, 0)
GlobalLogger.logs("Heartbeat sent for session '%s'" % session_id)
return

func _advertise_session(session_info: Dictionary, session_server: String) -> Dictionary:
Expand All @@ -369,7 +437,7 @@ func _advertise_session(session_info: Dictionary, session_server: String) -> Dic
"session_port": session_info.port,
}

var advertise_response = await http.req(
var advertise_response = await HTTP.req(
HTTPClient.Method.METHOD_POST,
url.host,
url.path,
Expand Down
25 changes: 0 additions & 25 deletions src/scenes/managers/app/rpc.gd

This file was deleted.

1 change: 0 additions & 1 deletion src/scenes/managers/app/rpc.gd.uid

This file was deleted.

6 changes: 0 additions & 6 deletions src/scenes/managers/app/rpc.tscn

This file was deleted.

Loading