diff --git a/godot/bomber/addons/rivet/api/rivet_api.gd b/godot/bomber/addons/rivet/api/rivet_api.gd index 22488a3..4cce84b 100644 --- a/godot/bomber/addons/rivet/api/rivet_api.gd +++ b/godot/bomber/addons/rivet/api/rivet_api.gd @@ -3,18 +3,25 @@ const RivetRequest = preload("rivet_request.gd") static var CONFIGURATION_CACHE +# This is needed to make sure that at runtime, +static func _get_bridge() -> Variant: + if Engine.is_editor_hint(): + return load("res://addons/rivet/devtools/rivet_plugin_bridge.gd") + else: + return null + static func _get_configuration(): if CONFIGURATION_CACHE: return CONFIGURATION_CACHE - if FileAccess.file_exists(RivetPluginBridge.RIVET_CONFIGURATION_FILE_PATH): - var config_file = ResourceLoader.load(RivetPluginBridge.RIVET_CONFIGURATION_FILE_PATH) + if FileAccess.file_exists(RivetConstants.RIVET_CONFIGURATION_FILE_PATH): + var config_file = ResourceLoader.load(RivetConstants.RIVET_CONFIGURATION_FILE_PATH) if config_file and 'new' in config_file: CONFIGURATION_CACHE = config_file.new() return CONFIGURATION_CACHE - if FileAccess.file_exists(RivetPluginBridge.RIVET_DEPLOYED_CONFIGURATION_FILE_PATH): - var deployed_config_file = ResourceLoader.load(RivetPluginBridge.RIVET_DEPLOYED_CONFIGURATION_FILE_PATH) + if FileAccess.file_exists(RivetConstants.RIVET_DEPLOYED_CONFIGURATION_FILE_PATH): + var deployed_config_file = ResourceLoader.load(RivetConstants.RIVET_DEPLOYED_CONFIGURATION_FILE_PATH) if deployed_config_file and 'new' in deployed_config_file: CONFIGURATION_CACHE = deployed_config_file.new() return CONFIGURATION_CACHE @@ -25,9 +32,11 @@ static func _get_configuration(): static func _get_api_url(): # Use plugin config if available - var plugin = RivetPluginBridge.get_plugin() - if plugin: - return plugin.api_endpoint + var bridge = _get_bridge() + if bridge != null: + var plugin = bridge.get_plugin() + if plugin: + return plugin.api_endpoint # Override shipped configuration endpoint var url_env = OS.get_environment("RIVET_API_ENDPOINT") @@ -46,11 +55,15 @@ static func _get_api_url(): ## actions. static func _get_cloud_token(): # Use plugin config if available - var plugin = RivetPluginBridge.get_plugin() - if plugin: - return plugin.cloud_token - - OS.crash("Rivet cloud token not found, this should only be called within the plugin") + var bridge = _get_bridge() + if bridge != null: + var plugin = bridge.get_plugin() + if plugin: + return plugin.cloud_token + # Explicit else, since if OS.crash is called from the engine, it will just + # crash the editor. + else: + OS.crash("Rivet cloud token not found, this should only be called within the plugin") ## Get authorization token used for making requests from within the game. ## @@ -61,9 +74,11 @@ static func _get_cloud_token(): ## - Assume config is provided by the game client static func _get_runtime_token(): # Use plugin config if available - var plugin = RivetPluginBridge.get_plugin() - if plugin: - return plugin.namespace_token + var bridge = _get_bridge() + if bridge != null: + var plugin = bridge.get_plugin() + if plugin: + return plugin.namespace_token # Use configuration shipped with game var token_env = OS.get_environment("RIVET_TOKEN") @@ -72,10 +87,12 @@ static func _get_runtime_token(): # Use configuration shipped with game var config = _get_configuration() - if config: + if config and config.namespace_token: return config.namespace_token - - OS.crash("Rivet token not found, validate a config is shipped with the game in the .rivet folder") + # Explicit else, since if OS.crash is called from the engine, it will just + # crash the editor. + else: + OS.crash("Rivet token not found, validate a config is shipped with the game in the .rivet folder") ## Builds the headers for a request, including the authorization token static func _build_headers(service: String) -> PackedStringArray: diff --git a/godot/bomber/addons/rivet/devtools/dock/deploy_tab.gd b/godot/bomber/addons/rivet/devtools/dock/deploy_tab.gd index c2654ac..904cce7 100644 --- a/godot/bomber/addons/rivet/devtools/dock/deploy_tab.gd +++ b/godot/bomber/addons/rivet/devtools/dock/deploy_tab.gd @@ -1,33 +1,82 @@ @tool extends MarginContainer @onready var namespace_selector: OptionButton = %DeployNamespaceSelector -@onready var manage_versions_button: Button = %ManageVersionButton @onready var build_deploy_button: Button = %BuildDeployButton +@onready var manage_versions_button: Button = %ManageVersionButton +@onready var logs_button: Button = %LogsButton +@onready var lobbies_button: Button = %LobbiesButton func _ready() -> void: - manage_versions_button.pressed.connect(_on_manage_versions_button_pressed) - build_deploy_button.pressed.connect(_on_build_deploy_button_pressed) + build_deploy_button.pressed.connect(_on_build_deploy_button_pressed) + manage_versions_button.pressed.connect(_on_manage_versions_button_pressed) + logs_button.pressed.connect(_on_logs_button_pressed) + lobbies_button.pressed.connect(_on_lobbies_button_pressed) func _on_manage_versions_button_pressed() -> void: - _all_actions_set_disabled(true) - - var result = await RivetPluginBridge.get_plugin().cli.run_command(["sidekick", "get-version", "--namespace", namespace_selector.current_value.namespace_id]) - if result.exit_code != 0 or !("Ok" in result.output): - RivetPluginBridge.display_cli_error(self, result) + _all_actions_set_disabled(true) + + var result = await RivetPluginBridge.get_plugin().cli.run_and_wait(["sidekick", "get-version", "--namespace", namespace_selector.current_value.namespace_id]) + if result.exit_code != 0 or !("Ok" in result.output): + RivetPluginBridge.display_cli_error(self, result) + + OS.shell_open(result.output["Ok"]["output"]) + _all_actions_set_disabled(false) + +func _on_logs_button_pressed() -> void: + _all_actions_set_disabled(true) + + var result = await RivetPluginBridge.get_plugin().cli.run_and_wait(["sidekick", "get-logs", "--namespace", namespace_selector.current_value.namespace_id]) + if result.exit_code != 0 or !("Ok" in result.output): + RivetPluginBridge.display_cli_error(self, result) + + OS.shell_open(result.output["Ok"]["output"]) + _all_actions_set_disabled(false) + +func _on_lobbies_button_pressed() -> void: + _all_actions_set_disabled(true) - OS.shell_open(result.output["Ok"]["output"]) - _all_actions_set_disabled(false) + var result = await RivetPluginBridge.get_plugin().cli.run_and_wait(["sidekick", "get-lobbies", "--namespace", namespace_selector.current_value.namespace_id]) + if result.exit_code != 0 or !("Ok" in result.output): + RivetPluginBridge.display_cli_error(self, result) + + OS.shell_open(result.output["Ok"]["output"]) + _all_actions_set_disabled(false) func _on_build_deploy_button_pressed() -> void: - _all_actions_set_disabled(true) + # First, ask the user if they want to save their scenes + var dialog = ConfirmationDialog.new() + dialog.dialog_text = "Would you like to save before building and deploying?" + dialog.connect("confirmed", save_before_build_and_deploy) + dialog.get_cancel_button().pressed.connect(build_and_deploy) + dialog.cancel_button_text = "No, just build and deploy" + self.add_child(dialog) + dialog.popup_centered() + + +func save_before_build_and_deploy() -> void: + # Save all + EditorInterface.save_all_scenes() + EditorInterface.get_script_editor().save_all_scripts() + + # Now, build and deploy + build_and_deploy() + + +func build_and_deploy() -> void: + _all_actions_set_disabled(true) + + var result = await RivetPluginBridge.get_plugin().cli.run_and_wait(["sidekick", "--show-terminal", "deploy", "--namespace", namespace_selector.current_value.name_id]) + if result.exit_code != 0: + RivetPluginBridge.display_cli_error(self, result) - var result = await RivetPluginBridge.get_plugin().cli.run_command(["sidekick", "--show-terminal", "deploy", "--namespace", namespace_selector.current_value.name_id]) - if result.exit_code != 0: - RivetPluginBridge.display_cli_error(self, result) + # Update the namespaces list + RivetPluginBridge.instance.bootstrap() - _all_actions_set_disabled(false) - + _all_actions_set_disabled(false) + func _all_actions_set_disabled(disabled: bool) -> void: - namespace_selector.disabled = disabled - manage_versions_button.disabled = disabled - build_deploy_button.disabled = disabled + namespace_selector.disabled = disabled + manage_versions_button.disabled = disabled + build_deploy_button.disabled = disabled + logs_button.disabled = disabled + lobbies_button.disabled = disabled diff --git a/godot/bomber/addons/rivet/devtools/dock/deploy_tab.tscn b/godot/bomber/addons/rivet/devtools/dock/deploy_tab.tscn index d4608b5..1d76ea5 100644 --- a/godot/bomber/addons/rivet/devtools/dock/deploy_tab.tscn +++ b/godot/bomber/addons/rivet/devtools/dock/deploy_tab.tscn @@ -10,10 +10,10 @@ offset_right = 734.0 offset_bottom = 109.0 script = ExtResource("1_7k6ip") -[node name="Deployment Fieds" type="VBoxContainer" parent="."] +[node name="Deployment Fields" type="VBoxContainer" parent="."] layout_mode = 2 -[node name="Deployment Label" type="RichTextLabel" parent="Deployment Fieds"] +[node name="Deployment Label" type="RichTextLabel" parent="Deployment Fields"] layout_mode = 2 theme_override_styles/normal = SubResource("StyleBoxEmpty_dfadg") bbcode_enabled = true @@ -22,35 +22,51 @@ fit_content = true scroll_active = false shortcut_keys_enabled = false -[node name="DeployNamespaceSelector" parent="Deployment Fieds" instance=ExtResource("2_5hxk2")] +[node name="DeployNamespaceSelector" parent="Deployment Fields" instance=ExtResource("2_5hxk2")] layout_mode = 2 -selected = -1 current_value = { -"create_ts": "2023-11-19T05:46:56.378Z", +"create_ts": "1970-01-01T00:00:00Z", "display_name": "Production", "name_id": "prod", -"namespace_id": "215bd313-b4c7-4932-b9bd-64f8f09b7fe8", +"namespace_id": "00000000-0000-0000-0000-000000000000", "version": { -"create_ts": "2023-11-19T05:46:56.171Z", +"create_ts": "1970-01-01T00:00:00Z", "display_name": "0.0.1", -"version_id": "73881376-21fa-4fb2-93f2-2f76fb3bac19" +"version_id": "00000000-0000-0000-0000-000000000000" }, -"version_id": "73881376-21fa-4fb2-93f2-2f76fb3bac19" +"version_id": "00000000-0000-0000-0000-000000000000" } -[node name="Actions" type="HBoxContainer" parent="Deployment Fieds"] +[node name="Actions" type="HBoxContainer" parent="Deployment Fields"] layout_mode = 2 -[node name="BuildDeployButton" type="Button" parent="Deployment Fieds/Actions"] +[node name="BuildDeployButton" type="Button" parent="Deployment Fields/Actions"] unique_name_in_owner = true layout_mode = 2 size_flags_horizontal = 3 mouse_default_cursor_shape = 2 text = "Build & Deploy" -[node name="ManageVersionButton" type="Button" parent="Deployment Fieds/Actions"] +[node name="ManageVersionButton" type="Button" parent="Deployment Fields/Actions"] unique_name_in_owner = true layout_mode = 2 size_flags_horizontal = 3 mouse_default_cursor_shape = 2 text = "Manage Versions" + +[node name="Links" type="HBoxContainer" parent="Deployment Fields"] +layout_mode = 2 + +[node name="LogsButton" type="Button" parent="Deployment Fields/Links"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +mouse_default_cursor_shape = 2 +text = "Logs" + +[node name="LobbiesButton" type="Button" parent="Deployment Fields/Links"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +mouse_default_cursor_shape = 2 +text = "Lobbies" diff --git a/godot/bomber/addons/rivet/devtools/dock/dock.gd b/godot/bomber/addons/rivet/devtools/dock/dock.gd index 5eac679..4b15c04 100644 --- a/godot/bomber/addons/rivet/devtools/dock/dock.gd +++ b/godot/bomber/addons/rivet/devtools/dock/dock.gd @@ -5,7 +5,7 @@ enum Screen { Login, Settings, - Loading, + LinkingPending, Installer, } @@ -19,10 +19,10 @@ func reload() -> void: instance.grab_focus() -func change_current_screen(scene: Screen): +func change_current_screen(scene: Screen, args: Dictionary = {}): for idx in get_child_count(): var child := get_child(idx) if "visible" in child: child.visible = idx == scene if idx == scene and child.has_method("prepare"): - child.prepare() + child.prepare(args) diff --git a/godot/bomber/addons/rivet/devtools/dock/dock.tscn b/godot/bomber/addons/rivet/devtools/dock/dock.tscn index ba952fd..c1b1c98 100644 --- a/godot/bomber/addons/rivet/devtools/dock/dock.tscn +++ b/godot/bomber/addons/rivet/devtools/dock/dock.tscn @@ -1,9 +1,9 @@ -[gd_scene load_steps=6 format=3 uid="uid://l8cfdaru7ibw"] +[gd_scene load_steps=5 format=3 uid="uid://l8cfdaru7ibw"] [ext_resource type="Script" path="res://addons/rivet/devtools/dock/dock.gd" id="1_xspk7"] [ext_resource type="PackedScene" uid="uid://mag2n5yvyus8" path="res://addons/rivet/devtools/dock/login.tscn" id="2_qo12a"] [ext_resource type="PackedScene" uid="uid://ceovepvn1782o" path="res://addons/rivet/devtools/dock/settings.tscn" id="3_8srmc"] -[ext_resource type="PackedScene" uid="uid://cpiafwq88eamc" path="res://addons/rivet/devtools/dock/loading.tscn" id="4_mdhqv"] +[ext_resource type="PackedScene" uid="uid://cpiafwq88eamc" path="res://addons/rivet/devtools/dock/linking_pending.tscn" id="4_mdhqv"] [ext_resource type="PackedScene" uid="uid://d3l0arylk0h43" path="res://addons/rivet/devtools/dock/installer.tscn" id="5_gdmi1"] [node name="Rivet" type="MarginContainer"] @@ -26,7 +26,7 @@ layout_mode = 2 visible = false layout_mode = 2 -[node name="Loading" parent="." instance=ExtResource("4_mdhqv")] +[node name="LinkingPending" parent="." instance=ExtResource("4_mdhqv")] visible = false layout_mode = 2 diff --git a/godot/bomber/addons/rivet/devtools/dock/elements/rivet_rich_text_label.gd b/godot/bomber/addons/rivet/devtools/dock/elements/rivet_rich_text_label.gd new file mode 100644 index 0000000..412523f --- /dev/null +++ b/godot/bomber/addons/rivet/devtools/dock/elements/rivet_rich_text_label.gd @@ -0,0 +1,25 @@ +@tool extends RichTextLabel + +var _spinner_tween: Tween + +func _ready(): + add_theme_stylebox_override(&"normal", get_theme_stylebox(&"bg", &"AssetLib")) + add_theme_font_override(&"mono_font", get_theme_font(&"output_source_mono", &"EditorFonts")) + add_theme_font_override(&"bold_font", get_theme_font(&"bold", &"EditorFonts")) + + meta_clicked.connect(func(meta): OS.shell_open(str(meta))) + +func _exit_tree() -> void: + if _spinner_tween: + _spinner_tween.kill() + +func append_spinner(): + if _spinner_tween: + _spinner_tween.kill() + add_image(get_theme_icon(&"Progress1", &"EditorIcons"), 0, 0, Color(1, 1, 1, 1), 5, Rect2(0,0,0,0), "loading") + _spinner_tween = get_tree().create_tween() + _spinner_tween.tween_method(_on_spinner_tween_method, 1, 8, 1).set_delay(0.1) + _spinner_tween.set_loops() + +func _on_spinner_tween_method(frame: int): + update_image("loading", ImageUpdateMask.UPDATE_TEXTURE, get_theme_icon("Progress" + str(frame), "EditorIcons")) \ No newline at end of file diff --git a/godot/bomber/addons/rivet/devtools/dock/installer.gd b/godot/bomber/addons/rivet/devtools/dock/installer.gd index 7c13b86..6db6447 100644 --- a/godot/bomber/addons/rivet/devtools/dock/installer.gd +++ b/godot/bomber/addons/rivet/devtools/dock/installer.gd @@ -4,7 +4,7 @@ @onready var InstallDialog: AcceptDialog = %InstallDialog @onready var InstallLabel: RichTextLabel = %InstallLabel -func prepare() -> void: +func prepare(_args: Dictionary) -> void: InstallLabel.add_theme_font_override(&"mono_font", get_theme_font(&"output_source_mono", &"EditorFonts")) InstallLabel.add_theme_font_override(&"bold_font", get_theme_font(&"bold", &"EditorFonts")) InstallLabel.add_theme_stylebox_override(&"normal", get_theme_stylebox(&"bg", &"AssetLib")) @@ -34,4 +34,4 @@ func _on_install_button_pressed() -> void: InstallDialog.title = &"Error!" InstallDialog.dialog_text = &"Rivet installation failed! Please try again.\n\n%s" % result.output InstallDialog.popup_centered() - InstallButton.loading = false \ No newline at end of file + InstallButton.loading = false diff --git a/godot/bomber/addons/rivet/devtools/dock/linking_pending.gd b/godot/bomber/addons/rivet/devtools/dock/linking_pending.gd new file mode 100644 index 0000000..5568d6a --- /dev/null +++ b/godot/bomber/addons/rivet/devtools/dock/linking_pending.gd @@ -0,0 +1,25 @@ +@tool extends VBoxContainer + +@onready var link_line_edit: LineEdit = %LinkLineEdit +@onready var link_instructions: RichTextLabel = %LinkInstructions + +var _on_cancel: Callable + +func _ready() -> void: + %CancelButton.pressed.connect(_on_cancel_button_pressed) + +func prepare(args: Dictionary) -> void: + if 'link' in args: + link_line_edit.text = args['link'] + link_instructions.clear() + link_instructions.push_paragraph(HORIZONTAL_ALIGNMENT_CENTER) + link_instructions.append_spinner() + link_instructions.append_text(" Linking game in browser...\n\n") + link_instructions.append_text("If your browser does not open, click [url={link}]here[/url], or use link below.".format({"link": args['link']})) + link_instructions.pop() + if 'on_cancel' in args: + _on_cancel = args['on_cancel'] + +func _on_cancel_button_pressed() -> void: + if _on_cancel.is_valid(): + _on_cancel.call() diff --git a/godot/bomber/addons/rivet/devtools/dock/linking_pending.tscn b/godot/bomber/addons/rivet/devtools/dock/linking_pending.tscn new file mode 100644 index 0000000..ee07e77 --- /dev/null +++ b/godot/bomber/addons/rivet/devtools/dock/linking_pending.tscn @@ -0,0 +1,55 @@ +[gd_scene load_steps=9 format=3 uid="uid://cpiafwq88eamc"] + +[ext_resource type="Script" path="res://addons/rivet/devtools/dock/linking_pending.gd" id="1_2ygnd"] +[ext_resource type="PackedScene" uid="uid://dldxcm1l8nnnf" path="res://addons/rivet/devtools/dock/elements/logo_container.tscn" id="1_oda17"] +[ext_resource type="PackedScene" uid="uid://bk1uwgw1hhq2p" path="res://addons/rivet/devtools/dock/elements/links_container.tscn" id="2_c2osa"] +[ext_resource type="Script" path="res://addons/rivet/devtools/dock/elements/rivet_rich_text_label.gd" id="4_1rtmw"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_3ibb0"] +content_margin_left = 4.0 +content_margin_top = 4.0 +content_margin_right = 4.0 +content_margin_bottom = 4.0 +bg_color = Color(1, 0.365, 0.365, 1) +draw_center = false +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +corner_detail = 1 + +[node name="LinkingPending" type="VBoxContainer"] +theme_override_constants/separation = 16 +script = ExtResource("1_2ygnd") + +[node name="LogoContainer" parent="." instance=ExtResource("1_oda17")] +layout_mode = 2 + +[node name="HSeparator" type="HSeparator" parent="."] +layout_mode = 2 + +[node name="LinksContainer" parent="." instance=ExtResource("2_c2osa")] +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 +theme_override_constants/separation = 16 + +[node name="LinkInstructions" type="RichTextLabel" parent="VBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(300, 2.08165e-12) +layout_mode = 2 +bbcode_enabled = true +fit_content = true +script = ExtResource("4_1rtmw") + +[node name="LinkLineEdit" type="LineEdit" parent="VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 3 +editable = false + +[node name="CancelButton" type="Button" parent="VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Cancel" diff --git a/godot/bomber/addons/rivet/devtools/dock/loading.gd b/godot/bomber/addons/rivet/devtools/dock/loading.gd deleted file mode 100644 index ab2136e..0000000 --- a/godot/bomber/addons/rivet/devtools/dock/loading.gd +++ /dev/null @@ -1,9 +0,0 @@ -extends VBoxContainer - - -func _ready() -> void: - %CancelButton.pressed.connect(_on_cancel_button_pressed) - -func _on_cancel_button_pressed() -> void: - # TODO(forest): cancel cli command - owner.change_current_screen(owner.Screen.Login) diff --git a/godot/bomber/addons/rivet/devtools/dock/loading.tscn b/godot/bomber/addons/rivet/devtools/dock/loading.tscn deleted file mode 100644 index f111cd9..0000000 --- a/godot/bomber/addons/rivet/devtools/dock/loading.tscn +++ /dev/null @@ -1,37 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://cpiafwq88eamc"] - -[ext_resource type="Script" path="res://addons/rivet/devtools/dock/loading.gd" id="1_2ygnd"] -[ext_resource type="PackedScene" uid="uid://dldxcm1l8nnnf" path="res://addons/rivet/devtools/dock/elements/logo_container.tscn" id="1_oda17"] -[ext_resource type="PackedScene" uid="uid://bk1uwgw1hhq2p" path="res://addons/rivet/devtools/dock/elements/links_container.tscn" id="2_c2osa"] - -[node name="Loading" type="VBoxContainer"] -theme_override_constants/separation = 16 -script = ExtResource("1_2ygnd") - -[node name="LogoContainer" parent="." instance=ExtResource("1_oda17")] -layout_mode = 2 - -[node name="HSeparator" type="HSeparator" parent="."] -layout_mode = 2 - -[node name="LinksContainer" parent="." instance=ExtResource("2_c2osa")] -layout_mode = 2 - -[node name="CenterContainer" type="CenterContainer" parent="."] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer"] -layout_mode = 2 -theme_override_constants/separation = 16 - -[node name="Label" type="Label" parent="CenterContainer/VBoxContainer"] -layout_mode = 2 -text = "Loading..." -horizontal_alignment = 1 -vertical_alignment = 1 - -[node name="CancelButton" type="Button" parent="CenterContainer/VBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -text = "Cancel" diff --git a/godot/bomber/addons/rivet/devtools/dock/login.gd b/godot/bomber/addons/rivet/devtools/dock/login.gd index 7a29fa4..882952d 100644 --- a/godot/bomber/addons/rivet/devtools/dock/login.gd +++ b/godot/bomber/addons/rivet/devtools/dock/login.gd @@ -1,13 +1,15 @@ @tool extends Control ## A button that logs the user in to the Rivet using Rivet CLI. +const RivetCliOutput = preload("../rivet_cli_output.gd") + @onready var log_in_button: Button = %LogInButton @onready var api_endpoint_line_edit: LineEdit = %ApiEndpointLineEdit @onready var advanced_options_button: Button = %AdvancedOptionsButton @onready var api_endpoint_field: Control = %ApiEndpointField -func prepare() -> void: - var result = await RivetPluginBridge.get_plugin().cli.run_command([ +func prepare(_args: Dictionary) -> void: + var result = await RivetPluginBridge.get_plugin().cli.run_and_wait([ "sidekick", "check-login-state", ]) @@ -23,7 +25,7 @@ func _ready(): func _on_button_pressed() -> void: log_in_button.disabled = true var api_address = api_endpoint_line_edit.text - var result = await RivetPluginBridge.get_plugin().cli.run_command([ + var result = await RivetPluginBridge.get_plugin().cli.run_and_wait([ "--api-endpoint", api_address, "sidekick", @@ -35,13 +37,12 @@ func _on_button_pressed() -> void: return var data: Dictionary = result.output["Ok"] + var link = data["device_link_url"] + # Now that we have the link, open it in the user's browser - OS.shell_open(data["device_link_url"]) - - owner.change_current_screen(owner.Screen.Loading) + OS.shell_open(link) - # Long-poll the Rivet API until the user has logged in - result = await RivetPluginBridge.get_plugin().cli.run_command([ + var command = RivetPluginBridge.get_plugin().cli.run([ "--api-endpoint", api_address, "sidekick", @@ -49,14 +50,29 @@ func _on_button_pressed() -> void: "--device-link-token", data["device_link_token"], ]) + + owner.change_current_screen(owner.Screen.LinkingPending, { + "link": link, + "on_cancel": func() -> void: + print("Killing command") + command.kill() + }) - if result.exit_code != result.ExitCode.SUCCESS or !("Ok" in result.output): - RivetPluginBridge.display_cli_error(self, result) - log_in_button.disabled = false - return + command.finished.connect( + func(result: RivetCliOutput) -> void: + if result.exit_code != result.ExitCode.SUCCESS or !("Ok" in result.output): + RivetPluginBridge.display_cli_error(self, result) + log_in_button.disabled = false + owner.change_current_screen(owner.Screen.Login) + return + owner.change_current_screen(owner.Screen.Settings) + ) - log_in_button.disabled = false - owner.change_current_screen(owner.Screen.Settings) + command.killed.connect( + func() -> void: + log_in_button.disabled = false + owner.change_current_screen(owner.Screen.Login) + ) func _on_advanced_options_button_pressed(): api_endpoint_field.visible = !api_endpoint_field.visible diff --git a/godot/bomber/addons/rivet/devtools/dock/playtest_tab.gd b/godot/bomber/addons/rivet/devtools/dock/playtest_tab.gd index f00f5d4..f1c7e07 100644 --- a/godot/bomber/addons/rivet/devtools/dock/playtest_tab.gd +++ b/godot/bomber/addons/rivet/devtools/dock/playtest_tab.gd @@ -82,7 +82,10 @@ func _all_actions_set_disabled(disabled: bool) -> void: func _generate_dev_auth_token(ns) -> void: _actions_disabled_while(func(): - var result = await RivetPluginBridge.get_plugin().cli.run_command(["sidekick", "get-namespace-development-token", "--namespace", ns.name_id]) + if "name_id" not in ns: + return + + var result = await RivetPluginBridge.get_plugin().cli.run_and_wait(["sidekick", "get-namespace-development-token", "--namespace", ns.name_id]) if result.exit_code != 0 or !("Ok" in result.output): RivetPluginBridge.display_cli_error(self, result) return @@ -93,7 +96,10 @@ func _generate_dev_auth_token(ns) -> void: func _generate_public_auth_token(ns) -> void: _actions_disabled_while(func(): - var result = await RivetPluginBridge.get_plugin().cli.run_command(["sidekick", "get-namespace-public-token", "--namespace", ns.name_id]) + if "name_id" not in ns: + return + + var result = await RivetPluginBridge.get_plugin().cli.run_and_wait(["sidekick", "get-namespace-public-token", "--namespace", ns.name_id]) if result.exit_code != 0 or !("Ok" in result.output): RivetPluginBridge.display_cli_error(self, result) return diff --git a/godot/bomber/addons/rivet/devtools/dock/settings.gd b/godot/bomber/addons/rivet/devtools/dock/settings.gd index 3ff0aa1..bbec11d 100644 --- a/godot/bomber/addons/rivet/devtools/dock/settings.gd +++ b/godot/bomber/addons/rivet/devtools/dock/settings.gd @@ -5,7 +5,7 @@ @onready var buttons_bar: HBoxContainer = %ButtonsBar @onready var deploy_tab = %Deploy -func prepare(): +func prepare(_args: Dictionary) -> void: var error = await RivetPluginBridge.instance.bootstrap() if error: errorDialog.popup_centered() diff --git a/godot/bomber/addons/rivet/devtools/dock/settings_tab.gd b/godot/bomber/addons/rivet/devtools/dock/settings_tab.gd index cd0660d..aadbf0a 100644 --- a/godot/bomber/addons/rivet/devtools/dock/settings_tab.gd +++ b/godot/bomber/addons/rivet/devtools/dock/settings_tab.gd @@ -10,7 +10,7 @@ func _ready() -> void: func _on_unlink_game_button_pressed() -> void: unlink_game_button.disabled = true - var result = await RivetPluginBridge.get_plugin().cli.run_command([ + var result = await RivetPluginBridge.get_plugin().cli.run_and_wait([ "unlink" ]) diff --git a/godot/bomber/addons/rivet/devtools/rivet_cli.gd b/godot/bomber/addons/rivet/devtools/rivet_cli.gd index 0fb36d2..dd2916e 100644 --- a/godot/bomber/addons/rivet/devtools/rivet_cli.gd +++ b/godot/bomber/addons/rivet/devtools/rivet_cli.gd @@ -1,9 +1,9 @@ extends RefCounted -## Wrapper aroudn the Rivet CLI, allowing you to run it from GDScript in non-blocking way, and get the output. +## Wrapper around the Rivet CLI, allowing you to run it from GDScript in non-blocking way, and get the output. ## ## @experimental -const REQUIRED_RIVET_CLI_VERSION = "v1.1.0" +const REQUIRED_RIVET_CLI_VERSION = "v1.3.1" const _RivetEditorSettings = preload("rivet_editor_settings.gd") const _RivetThread = preload("rivet_thread.gd") @@ -13,7 +13,7 @@ func check_existence() -> Error: var editor_rivet_path = _RivetEditorSettings.get_setting(_RivetEditorSettings.RIVET_CLI_PATH_SETTING.name) if not editor_rivet_path or editor_rivet_path.is_empty(): return FAILED - var result: _RivetCliOutput = await run_command(["sidekick", "get-cli-version"]) + var result: _RivetCliOutput = await run_and_wait(["sidekick", "get-cli-version"]) if result.exit_code != 0 or !("Ok" in result.output): return FAILED var cli_version = result.output["Ok"].version @@ -21,10 +21,13 @@ func check_existence() -> Error: return FAILED return OK -func run_command(args: PackedStringArray) -> _RivetCliOutput: +func run_and_wait(args: PackedStringArray) -> _RivetCliOutput: var thread: _RivetThread = _RivetThread.new(_run.bind(args)) return await thread.wait_to_finish() +func run(args:PackedStringArray) -> _RivetThread: + return _RivetThread.new(_run.bind(args)) + func get_bin_dir() -> String: var home_path: String = OS.get_environment("USERPROFILE") if OS.get_name() == "Windows" else OS.get_environment("HOME") diff --git a/godot/bomber/addons/rivet/devtools/rivet_export_plugin.gd b/godot/bomber/addons/rivet/devtools/rivet_export_plugin.gd index bbb7419..e0927b8 100644 --- a/godot/bomber/addons/rivet/devtools/rivet_export_plugin.gd +++ b/godot/bomber/addons/rivet/devtools/rivet_export_plugin.gd @@ -11,19 +11,27 @@ func _get_name(): return _plugin_name func _export_begin(features: PackedStringArray, is_debug: bool, path: String, flags: int) -> void: - if not FileAccess.file_exists(RivetPluginBridge.RIVET_CONFIGURATION_FILE_PATH): + if not FileAccess.file_exists(RivetConstants.RIVET_CONFIGURATION_FILE_PATH): push_warning("Rivet plugin not configured. Please configure it using plugin interface.") return - var configuration_file = FileAccess.open(RivetPluginBridge.RIVET_CONFIGURATION_FILE_PATH, FileAccess.READ) + # Set up the Rivet config file for this namespace + var configuration_file = FileAccess.open(RivetConstants.RIVET_CONFIGURATION_FILE_PATH, FileAccess.READ) var source = configuration_file.get_as_text() var script = GDScript.new() script.source_code = source - var error: Error = ResourceSaver.save(script, RivetPluginBridge.RIVET_DEPLOYED_CONFIGURATION_FILE_PATH) + var error: Error = ResourceSaver.save(script, RivetConstants.RIVET_DEPLOYED_CONFIGURATION_FILE_PATH) if not error: has_added_file = true - func _export_end() -> void: if has_added_file: - DirAccess.remove_absolute(RivetPluginBridge.RIVET_DEPLOYED_CONFIGURATION_FILE_PATH) \ No newline at end of file + DirAccess.remove_absolute(RivetConstants.RIVET_DEPLOYED_CONFIGURATION_FILE_PATH) + +func _export_file(path: String, type: String, features: PackedStringArray) -> void: + # If any files are part of the path rivet/devtools/*, skip them for the + # export build + print("Exporting file: " + path) + if path.contains("rivet/devtools/dock"): + print("Skipping file: " + path) + skip() \ No newline at end of file diff --git a/godot/bomber/addons/rivet/devtools/rivet_plugin_bridge.gd b/godot/bomber/addons/rivet/devtools/rivet_plugin_bridge.gd index 018e3b3..b76a7c2 100644 --- a/godot/bomber/addons/rivet/devtools/rivet_plugin_bridge.gd +++ b/godot/bomber/addons/rivet/devtools/rivet_plugin_bridge.gd @@ -1,4 +1,6 @@ -@tool class_name RivetPluginBridge +@tool + +class_name RivetPluginBridge ## Scaffolding for the plugin to be used in the editor, this is not meant to be ## used in the game. It's a way to get the plugin instance from the engine's ## perspective. @@ -7,16 +9,6 @@ signal bootstrapped -const RIVET_CONFIGURATION_PATH: String = "res://.rivet" -const RIVET_CONFIGURATION_FILE_PATH: String = "res://.rivet/config.gd" -const RIVET_DEPLOYED_CONFIGURATION_FILE_PATH: String = "res://.rivet_config.gd" -const SCRIPT_TEMPLATE: String = """ -extends RefCounted -const api_endpoint: String = \"{api_endpoint}\" -const namespace_token: String = \"{namespace_token}\" -const cloud_token: String = \"{cloud_token}\" -const game_id: String = \"{game_id}\" -""" const _global := preload("../rivet_global.gd") const _RivetEditorSettings = preload("./rivet_editor_settings.gd") @@ -53,8 +45,9 @@ static func get_plugin() -> _global: return null static func log(args): - if _RivetEditorSettings.get_setting(_RivetEditorSettings.RIVET_DEBUG_SETTING.name): - print("[Rivet] ", args) + if Engine.is_editor_hint(): + if _RivetEditorSettings.get_setting(_RivetEditorSettings.RIVET_DEBUG_SETTING.name): + print("[Rivet] ", args) static func warning(args): push_warning("[Rivet] ", args) @@ -63,22 +56,27 @@ static func error(args): push_error("[Rivet] ", args) func save_configuration(): - DirAccess.make_dir_recursive_absolute(RIVET_CONFIGURATION_PATH) + DirAccess.make_dir_recursive_absolute(RivetConstants.RIVET_CONFIGURATION_PATH) - var gd_ignore_path = RIVET_CONFIGURATION_PATH.path_join(".gdignore") + var gd_ignore_path = RivetConstants.RIVET_CONFIGURATION_PATH.path_join(".gdignore") if not FileAccess.file_exists(gd_ignore_path): var gd_ignore = FileAccess.open(gd_ignore_path, FileAccess.WRITE) gd_ignore.store_string("") - var git_ignore_path = RIVET_CONFIGURATION_PATH.path_join(".gitignore") + var git_ignore_path = RivetConstants.RIVET_CONFIGURATION_PATH.path_join(".gitignore") if not FileAccess.file_exists(git_ignore_path): var git_ignore = FileAccess.open(git_ignore_path, FileAccess.WRITE) git_ignore.store_string("*") var plg = get_plugin() var script: GDScript = GDScript.new() - script.source_code = SCRIPT_TEMPLATE.format({"api_endpoint": plg.api_endpoint, "namespace_token": plg.namespace_token, "cloud_token": plg.cloud_token, "game_id": plg.game_id}) - var err: Error = ResourceSaver.save(script, RIVET_CONFIGURATION_FILE_PATH) + script.source_code = RivetConstants.SCRIPT_TEMPLATE.format({ + "api_endpoint": plg.api_endpoint, + "namespace_token": plg.namespace_token, + "cloud_token": plg.cloud_token, + "game_id": plg.game_id + }) + var err: Error = ResourceSaver.save(script, RivetConstants.RIVET_CONFIGURATION_FILE_PATH) if err: push_warning("Error saving Rivet data: %s" % err) @@ -87,7 +85,7 @@ func bootstrap() -> Error: if not plugin: return FAILED - var result = await get_plugin().cli.run_command([ + var result = await get_plugin().cli.run_and_wait([ "sidekick", "get-bootstrap-data", ]) diff --git a/godot/bomber/addons/rivet/devtools/rivet_thread.gd b/godot/bomber/addons/rivet/devtools/rivet_thread.gd index 2f181f0..6dae124 100644 --- a/godot/bomber/addons/rivet/devtools/rivet_thread.gd +++ b/godot/bomber/addons/rivet/devtools/rivet_thread.gd @@ -4,9 +4,11 @@ extends RefCounted ## @experimental signal finished(output: Variant) +signal killed() var _mutex: Mutex var _thread: Thread +var _is_killed: bool = false ## Result of the thread. var output: Variant = null @@ -22,8 +24,15 @@ func _init(fn: Callable) -> void: _thread.start(func(): var result = fn.call() _mutex.lock() - output = result - call_deferred("emit_signal", "finished", result) + if not _is_killed: + output = result + call_deferred("emit_signal", "finished", result) _mutex.unlock() return result ) + +func kill() -> void: + _mutex.lock() + _is_killed = true + call_deferred("emit_signal", "killed") + _mutex.unlock() \ No newline at end of file diff --git a/godot/bomber/addons/rivet/plugin.cfg b/godot/bomber/addons/rivet/plugin.cfg index 67ebb72..d8a458e 100644 --- a/godot/bomber/addons/rivet/plugin.cfg +++ b/godot/bomber/addons/rivet/plugin.cfg @@ -1,8 +1,9 @@ [plugin] -name="Rivet API" -description="" +name="Rivet - Multiplayer Game Servers and Backend" +description="Managed game servers, matchmaking, and DDoS mitigation that lets you focus on building your game.\n\nLearn more at https://rivet.gg" author="Rivet Gaming, Inc." -version="1.1.4" +; x-release-please-start-version +version="1.3.4" +; x-release-please-end script="rivet.gd" - diff --git a/godot/bomber/addons/rivet/rivet_constants.gd b/godot/bomber/addons/rivet/rivet_constants.gd new file mode 100644 index 0000000..05c8f87 --- /dev/null +++ b/godot/bomber/addons/rivet/rivet_constants.gd @@ -0,0 +1,13 @@ +class_name RivetConstants + + +const RIVET_CONFIGURATION_PATH: String = "res://.rivet" +const RIVET_CONFIGURATION_FILE_PATH: String = "res://.rivet/config.gd" +const RIVET_DEPLOYED_CONFIGURATION_FILE_PATH: String = "res://.rivet_config.gd" +const SCRIPT_TEMPLATE: String = """ +extends RefCounted +const api_endpoint: String = \"{api_endpoint}\" +const namespace_token: String = \"{namespace_token}\" +const cloud_token: String = \"{cloud_token}\" +const game_id: String = \"{game_id}\" +"""