diff --git a/.gitignore b/.gitignore index 4709183..e6e57d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ # Godot 4+ specific ignores .godot/ +/web/ +*.exe +*.dmg \ No newline at end of file diff --git a/MainWindow.gd b/MainWindow.gd index 65479de..b422088 100644 --- a/MainWindow.gd +++ b/MainWindow.gd @@ -1,5 +1,17 @@ extends Control +# 601 LOC 11/9 - 2023 + +##TODO +# 2. Fix reset buttons +# 3. Fix settings +# 11. Refactor components +# 13. Fix graphics in lists +# 14. Fix layout +# 15. Fix for local play +# 16. Change all calls to make_request and function in function +# 17. Change some buttons to icons + @onready var open_button := $Open @@ -22,10 +34,7 @@ var song_label := $VBoxContainer/SongLabel var play_button := $PanelContainer/HBoxContainer/PlayButton @onready -var pause_button := $PanelContainer/HBoxContainer/PauseButton - -@onready -var stop_button := $PanelContainer/HBoxContainer/StopButton +var restart_button := $PanelContainer/HBoxContainer/RestartButton @onready var audio := $AudioStreamPlayer @@ -37,7 +46,46 @@ var progress := $PanelContainer/HBoxContainer/HSlider var label := $PanelContainer/HBoxContainer/Label @onready -var add_player := $Players/VBoxContainer/HBoxContainer/AddPlayer +var add_player_container := $Players/VBoxContainer/AddPlayerContainer + +@onready +var add_players_button := $Players/VBoxContainer/HBoxContainer/AddPlayersButton + +@onready +var add_player_button := $Players/VBoxContainer/AddPlayerContainer/AddPlayerButton + +@onready +var new_player_name_field := $Players/VBoxContainer/AddPlayerContainer/PlayerNameField + +@onready +var sound_test_button := $SoundTestButton + +@onready +var sync_button := $SyncButton + +@onready +var sync_popup := $SyncPopupPanel + +@onready +var settings_button := $SettingsButton + +@onready +var settings_popup := $SettingsPopupPanel + +@onready +var statistics_button := $StatisticsButton + +@onready +var statistic_popup := $StatisticsPopupPanel + +@onready +var statistic_label := $StatisticsPopupPanel/StatisticsLabel + +@onready +var about_button := $AboutButton + +@onready +var about_popup := $AboutPopupPanel @onready var show_answer_button := $ShowAnswerButton @@ -57,41 +105,166 @@ var players := $Players/VBoxContainer @onready var character_select := $CharacterSelect +@onready +var search_button := $SearchButton + +@onready +var search_view := $Search + +@onready +var version_label := $AboutPopupPanel/VBoxContainer/VersionLabel + +@onready +var new_label := $AboutPopupPanel/VBoxContainer/HBoxContainer/NewLabel + +@onready +var shortcut_label := $AboutPopupPanel/VBoxContainer/HBoxContainer/ShortcutsLabel + +@onready +var comming_label := $AboutPopupPanel/VBoxContainer/HBoxContainer/CommingLabel + +@onready +var winner_popup := $WinnerPopupPanel + +@onready +var winner_label := $WinnerPopupPanel/WinnerLabel + var Player := preload("res://Player.tscn") @onready var path = '/Users/sebastian/ResilioSync/Sorterat_test/Metal Gear Solid 4 - Guns of the Patriots/2-16 Metal Gear Saga.mp3' -func get_suggestion_list() -> void: - var http_request = HTTPRequest.new() - add_child(http_request) - http_request.request_completed.connect(self._http_request_completed) - - # Perform a GET request. The URL below returns JSON as of writing. - var error = http_request.request("https://music.sanplex.tech/music/all") - if error != OK: - push_error("An error occurred in the HTTP request.") - -func add_players(): - var new_player := Player.instantiate() - players.add_child(new_player) - new_player.connect("change_character_clicked", _on_player_change_character_clicked.bind(new_player)) - # Called when the node enters the scene tree for the first time. func _ready(): - next_button.pressed.connect(fetch_first_song) - pause_button.pressed.connect(pause) - stop_button.pressed.connect(stop) + next_button.pressed.connect(fetch_next_song) + play_button.pressed.connect(play_or_pause) + restart_button.pressed.connect(restart) show_answer_button.pressed.connect(show_answer) + search_button.pressed.connect(show_search) + sync_button.pressed.connect(sync_games) + sound_test_button.pressed.connect(get_sound_test_song) + statistics_button.pressed.connect(get_statistics) + about_button.pressed.connect(show_about) + settings_button.pressed.connect(show_settings) progress.drag_started.connect(_on_drag_started) progress.drag_ended.connect(_on_drag_ended) character_select.connect("character_selected", _on_character_selected) - - add_player.pressed.connect(add_players) + new_player_name_field.connect("enter_key_pressed", add_player) + add_players_button.pressed.connect(add_players) + add_player_button.pressed.connect(add_player) open_button.pressed.connect(open) get_suggestion_list() + fetch_full_music_list_at_start() + +func show_about(): + about_popup.visible = true + version_label.text = Settings.version + new_label.text = Settings.whats_new + shortcut_label.text = Settings.shortcuts + comming_label.text = Settings.whats_left + +func show_settings(): + settings_popup.visible = true + +func get_statistics(): + statistic_popup.visible = true + statistic_label.text = "Total amount of games in the playlist: " + str(games.size()) + +func get_sound_test_song(): + var play_sound_test_song = func(result, response_code, headers, body): + if result != HTTPRequest.RESULT_SUCCESS: + push_error("Song couldn't be downloaded. Try a different song.") + var sound = AudioStreamMP3.new() + sound.data = body + audio.stream = sound + audio.play() + stream = audio.stream + progress.max_value = round(stream.get_length()) + progress.tick_count = round(stream.get_length() / 60) + + make_request(Settings.default_path + "/music/first", play_sound_test_song) + +func sound_test_local(): + path = "res://01. Opening.mp3" + audio.stream = load_mp3(path) + audio.play() + stream = audio.stream + progress.max_value = round(stream.get_length()) + progress.tick_count = round(stream.get_length() / 60) + +func sync_games(): + var http_request = HTTPRequest.new() + add_child(http_request) + http_request.request_completed.connect(games_synced) + + # Perform a GET request. The URL below returns JSON as of writing. + var error = http_request.request(Settings.default_path + "/sync") + if error != OK: + push_error("An error occurred in the HTTP request.") + +func games_synced(result, response_code, headers, body): + if response_code == 200: + sync_popup.visible = true + +func get_suggestion_list() -> void: + var populate_list = func(array): + if typeof(array) == TYPE_ARRAY: + games.append_array(array) + for game in games: + var label := Label.new() + label.text = game + label.autowrap_mode = TextServer.AUTOWRAP_WORD + insperation_list.add_child(label) + insperation_scroll.scroll_to_bottom() + else: + print("Unexpected data") + Settings.make_request2("/music/all", populate_list) + +func add_players(): + add_player_container.visible = !add_player_container.visible + new_player_name_field.grab_focus() + +func add_player(): + var new_player := Player.instantiate() + new_player.new_name(new_player_name_field.text) + new_player_name_field.text = "" + players.add_child(new_player) + new_player.connect("change_character_clicked", _on_player_change_character_clicked.bind(new_player)) + new_player.connect("first_point_triggerd", _on_point_triggerd.bind("first", "")) + new_player.connect("match_point_triggerd", _on_point_triggerd.bind("match", "")) + new_player.connect("winner_triggerd", _on_point_triggerd.bind("winner", new_player.player_name)) + +func _on_point_triggerd(point: String, name: String): + var song_path: String + if point == "first": + var value = randi_range(0, 10) + if value == 0: + song_path = "res://sounds/sound1.mp3" + elif value < 5: + song_path = "res://sounds/intro_long.mp3" + else: + song_path = "res://sounds/intro_short.mp3" + elif point == "match": + song_path = "res://sounds/sound0.mp3" + elif point == "winner": + song_path = "res://sounds/winning.mp3" + winner_popup.visible = true + winner_label.text = name + " won!!" + + audio.stream = load_mp3(song_path) + audio.play() + play_button.text = "Pause" + stream = audio.stream + progress.max_value = round(stream.get_length()) + progress.tick_count = round(stream.get_length() / 60) + +func show_search(): + if search_view.visible == false: + search_view.visible = true + else: + search_view.visible = false func show_answer(): var http_request = HTTPRequest.new() @@ -99,17 +272,86 @@ func show_answer(): http_request.request_completed.connect(show_fetched) # Perform a GET request. The URL below returns JSON as of writing. - var error = http_request.request("https://music.sanplex.tech/music/info") + var error = http_request.request(Settings.default_path + "/music/info") if error != OK: push_error("An error occurred in the HTTP request.") + +func fetch_full_music_list_at_start(): + var show_fetched_list = func(data): + if data == null: return + if typeof(data) == TYPE_ARRAY: + song_list = [] + song_list.append_array(data) + for song in song_list: + var label := Label.new() + var format_string = "%d. %s - %s" + var actual_string = format_string % [(song.SongNo+1), song.Game, song.Song] + label.text = actual_string + label.mouse_filter = Control.MOUSE_FILTER_PASS + label.gui_input.connect(song_clicked.bind(label, song.SongNo)) + music_list.add_child(label) + else: + print("Unexpected data") + Settings.make_request2("/music/list", show_fetched_list) +func fetch_full_music_list(event, song_no: int): + if (event is InputEventMouseButton && event.pressed && event.button_index == MOUSE_BUTTON_LEFT): + var show_fetched_list = func(result, response_code, headers, body): + var json = JSON.new() + var error = json.parse(body.get_string_from_utf8()) + + if error == OK: + var data_received = json.get_data() + if typeof(data_received) == TYPE_ARRAY: + song_list = [] + song_list.append_array(data_received) + delete_children(music_list) + for song in song_list: + var label := Label.new() + game_label.text = song.Game + song_label.text = song.Song + var format_string = "%d. %s - %s" + var actual_string = format_string % [(song.SongNo+1), song.Game, song.Song] + label.text = actual_string + label.mouse_filter = Control.MOUSE_FILTER_PASS + label.gui_input.connect(song_clicked.bind(label, song.SongNo)) + print(str(music_list.get_child_count()) + " | " + str(song_list.size() - 1)) + if music_list.get_child_count() == song_list.size() - 1: + label.add_theme_color_override("font_color", Color(1, 0.5, 0)) + music_list.add_child(label) + else: + print("Unexpected data") + make_request(Settings.default_path + "/music/list", show_fetched_list) + var play_clicked_song = func(result, response_code, headers, body): + if result != HTTPRequest.RESULT_SUCCESS: + push_error("Song couldn't be downloaded. Try a different song.") + var sound = AudioStreamMP3.new() + sound.data = body + audio.stream = sound + audio.play() + play_button.text = "Pause" + stream = audio.stream + progress.max_value = round(stream.get_length()) + progress.tick_count = round(stream.get_length() / 60) + make_request(Settings.default_path + "/music?song=" + str(song_no), play_clicked_song) + var show_answer = func(result, response_code, headers, body): + var json = JSON.new() + var error = json.parse(body.get_string_from_utf8()) + + if error == OK: + var data_received = json.get_data() + game_label.text = data_received.Game + song_label.text = data_received.Song + make_request(Settings.default_path + "/music/info", show_answer) + + func fetched(): var http_request2 = HTTPRequest.new() add_child(http_request2) http_request2.request_completed.connect(show_fetched_list) # Perform a GET request. The URL below returns JSON as of writing. - var error2 = http_request2.request("https://music.sanplex.tech/music/list") + var error2 = http_request2.request(Settings.default_path + "/music/list") if error2 != OK: push_error("An error occurred in the HTTP request.") @@ -146,49 +388,55 @@ func show_fetched_list(result, response_code, headers, body) -> void: var actual_string = format_string % [(song.SongNo+1), song.Game, song.Song] label.text = actual_string label.mouse_filter = Control.MOUSE_FILTER_PASS - label.gui_input.connect(song_clicked.bind(song.SongNo)) + label.gui_input.connect(song_clicked.bind(label, song.SongNo)) music_list.add_child(label) - + + var songs := music_list.get_children() + for song in songs: + song.remove_theme_color_override("font_color") next_label = Label.new() + next_label.add_theme_color_override("font_color", Color(1, 0.5, 0)) next_label.text = "??? - ???" next_label.mouse_filter = Control.MOUSE_FILTER_PASS - next_label.gui_input.connect(show_fetched) + next_label.gui_input.connect(fetch_full_music_list.bind(songs.size())) music_list.add_child(next_label) else: print("Unexpected data") -func song_clicked(event, song_no): +func song_clicked(event, label: Label, song_no: int): if (event is InputEventMouseButton && event.pressed && event.button_index == MOUSE_BUTTON_LEFT): - print("Clicked: " + str(song_no)) + print("Song Clicked: " + str(song_no)) + var songs := music_list.get_children() + for song in songs: + song.remove_theme_color_override("font_color") + label.add_theme_color_override("font_color", Color(1, 0.5, 0)) + var play_clicked_song = func(result, response_code, headers, body): + if result != HTTPRequest.RESULT_SUCCESS: + push_error("Song couldn't be downloaded. Try a different song.") + var sound = AudioStreamMP3.new() + sound.data = body + audio.stream = sound + audio.play() + play_button.text = "Pause" + stream = audio.stream + progress.max_value = round(stream.get_length()) + progress.tick_count = round(stream.get_length() / 60) + make_request(Settings.default_path + "/music?song=" + str(song_no), play_clicked_song) + var show_answer = func(result, response_code, headers, body): + var json = JSON.new() + var error = json.parse(body.get_string_from_utf8()) + + if error == OK: + var data_received = json.get_data() + game_label.text = data_received.Game + song_label.text = data_received.Song + make_request(Settings.default_path + "/music/info", show_answer) -# Called when the HTTP request is completed. -func _http_request_completed(result, response_code, headers, body): - var json = JSON.new() - var error = json.parse(body.get_string_from_utf8()) - - if error == OK: - var data_received = json.get_data() - if typeof(data_received) == TYPE_ARRAY: - games.append_array(data_received) - for game in games: - var label := Label.new() - label.text = game - label.autowrap_mode = TextServer.AUTOWRAP_WORD - insperation_list.add_child(label) - insperation_scroll.scroll_to_bottom() - else: - print("Unexpected data") - - - # Will print the user agent string used by the HTTPRequest node (as recognized by httpbin.org). - #print(response) func open(): fileDialog.popup() - - # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): if audio.has_stream_playback() && !is_changing && !audio.stream_paused: @@ -258,14 +506,13 @@ func format_text(part: float, total: float) -> String: return format_time(part) + " / " + format_time(total) -func fetch_first_song() -> void: +func fetch_next_song() -> void: var http_request = HTTPRequest.new() add_child(http_request) - #http.set_download_file("https://music.sanplex.tech/music/first") http_request.request_completed.connect(first_song_fetched) # Perform a GET request. The URL below returns JSON as of writing. - var error = http_request.request("https://music.sanplex.tech/music/rand") + var error = http_request.request(Settings.default_path + "/music/rand") if error != OK: push_error("An error occurred in the HTTP request.") @@ -277,44 +524,51 @@ func first_song_fetched(result, response_code, headers, body) -> void: push_error("Song couldn't be downloaded. Try a different song.") var sound = AudioStreamMP3.new() sound.data = body - make_request("https://music.sanplex.tech/music/addQue", add_que) - play(sound) + make_request(Settings.default_path + "/music/addQue", add_que) + print("play given song") + audio.stream = sound + audio.play() + stream = audio.stream + progress.max_value = round(stream.get_length()) + progress.tick_count = round(stream.get_length() / 60) func add_que(result, response_code, headers, body) -> void: print("response_code", response_code) fetched() -func play(song) -> void: - if audio.stream_paused: - audio.stream_paused = false - audio.seek(playback_position) - print("continue") - elif song: - print("play given song") - audio.stream = song - audio.play() - stream = audio.stream - else: - if songs: - #print(songs) - path = songs[0] +func play_local_song(song) -> void: + if songs: + path = songs[0] print(path) print(FileAccess.file_exists(path)) audio.stream = load_mp3(path) print("play") audio.play() stream = audio.stream - progress.max_value = round(stream.get_length()) - progress.tick_count = round(stream.get_length() / 60) + progress.max_value = round(stream.get_length()) + progress.tick_count = round(stream.get_length() / 60) + +func play_or_pause(): + if audio.stream_paused: + play_button.text = "Pause" + audio.stream_paused = false + audio.seek(playback_position) + print("continue") + progress.max_value = round(stream.get_length()) + progress.tick_count = round(stream.get_length() / 60) + else: + audio.stream_paused = true + playback_position = audio.get_playback_position() + play_button.text = "Play" -func pause() -> void: - audio.stream_paused = true - playback_position = audio.get_playback_position() - -func stop() -> void: +func restart() -> void: audio.stop() audio.stream_paused = false progress.value = 0 + playback_position = audio.get_playback_position() + audio.seek(playback_position) + play_button.text = "Pause" + audio.play() func _on_drag_started() -> void: is_changing = true diff --git a/MainWindow.tscn b/MainWindow.tscn index fd22513..26f63c6 100644 --- a/MainWindow.tscn +++ b/MainWindow.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=11 format=3 uid="uid://xwq863o6uvsu"] +[gd_scene load_steps=26 format=3 uid="uid://xwq863o6uvsu"] [ext_resource type="Script" path="res://MainWindow.gd" id="1_eu0t5"] [ext_resource type="PackedScene" uid="uid://b16on0oscg1bv" path="res://CharacterSelect.tscn" id="2_76kf4"] @@ -7,7 +7,13 @@ [ext_resource type="AudioStream" uid="uid://n2g8jddr85h2" path="res://01. Opening.mp3" id="4_5kvsq"] [ext_resource type="Texture2D" uid="uid://o5go6smk7hm1" path="res://person_add_alt_1-black-36dp.svg" id="4_op458"] [ext_resource type="Script" path="res://MusicListScrollContainer.gd" id="7_dj026"] +[ext_resource type="Script" path="res://PlayerNameField.gd" id="7_qsdfy"] [ext_resource type="Theme" uid="uid://rxexo3ur85as" path="res://LightGrayTheme.tres" id="7_wxbv6"] +[ext_resource type="PackedScene" uid="uid://bxydgil1yifps" path="res://SearchWindow.tscn" id="9_5ijvr"] +[ext_resource type="PackedScene" uid="uid://dldpeo5y3l5hq" path="res://SettingsWindow.tscn" id="11_k62u5"] + +[sub_resource type="LabelSettings" id="LabelSettings_ychxr"] +font_size = 25 [sub_resource type="LabelSettings" id="LabelSettings_qspbu"] font_size = 50 @@ -15,6 +21,53 @@ font_size = 50 [sub_resource type="LabelSettings" id="LabelSettings_3m52w"] font_size = 35 +[sub_resource type="InputEventKey" id="InputEventKey_n2hsq"] +device = -1 +alt_pressed = true +keycode = 88 +unicode = 8776 + +[sub_resource type="Shortcut" id="Shortcut_6mgjo"] +events = [SubResource("InputEventKey_n2hsq")] + +[sub_resource type="InputEventKey" id="InputEventKey_03bm3"] +device = -1 +alt_pressed = true +keycode = 65 +unicode = 63743 + +[sub_resource type="Shortcut" id="Shortcut_jafqj"] +events = [SubResource("InputEventKey_03bm3")] + +[sub_resource type="InputEventKey" id="InputEventKey_06rl4"] +device = -1 +alt_pressed = true +keycode = 86 +unicode = 8249 + +[sub_resource type="Shortcut" id="Shortcut_a7fvb"] +events = [SubResource("InputEventKey_06rl4")] + +[sub_resource type="InputEventKey" id="InputEventKey_7dnqw"] +device = -1 +alt_pressed = true +keycode = 67 +unicode = 231 + +[sub_resource type="Shortcut" id="Shortcut_d6fml"] +events = [SubResource("InputEventKey_7dnqw")] + +[sub_resource type="InputEventKey" id="InputEventKey_ujjlu"] +device = -1 +alt_pressed = true +keycode = 83 + +[sub_resource type="Shortcut" id="Shortcut_fbju4"] +events = [SubResource("InputEventKey_ujjlu")] + +[sub_resource type="LabelSettings" id="LabelSettings_hr75l"] +font_size = 35 + [node name="Control" type="Control"] layout_mode = 3 anchors_preset = 0 @@ -23,15 +76,17 @@ script = ExtResource("1_eu0t5") [node name="TopPanelContainer" type="PanelContainer" parent="."] layout_mode = 0 offset_right = 1920.0 -offset_bottom = 52.0 +offset_bottom = 56.0 -[node name="HBoxContainer" type="HBoxContainer" parent="TopPanelContainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="TopPanelContainer/HBoxContainer"] +[node name="Title" type="Label" parent="."] layout_mode = 2 +offset_left = 32.0 +offset_top = 8.0 +offset_right = 337.0 +offset_bottom = 46.0 size_flags_horizontal = 0 text = "Music Player Randomizer" +label_settings = SubResource("LabelSettings_ychxr") [node name="Open" type="Button" parent="."] layout_mode = 2 @@ -57,6 +112,7 @@ offset_top = 95.0 offset_right = 1845.0 offset_bottom = 465.0 horizontal_scroll_mode = 0 +vertical_scroll_mode = 3 script = ExtResource("2_gxtxm") [node name="VBoxContainer" type="VBoxContainer" parent="ScrollContainer"] @@ -64,15 +120,6 @@ layout_mode = 2 size_flags_horizontal = 3 size_flags_vertical = 3 -[node name="Label" type="Label" parent="ScrollContainer/VBoxContainer"] -layout_mode = 2 -text = "Test -" - -[node name="Label2" type="Label" parent="ScrollContainer/VBoxContainer"] -layout_mode = 2 -text = "Test2" - [node name="VBoxContainer" type="VBoxContainer" parent="."] layout_mode = 0 offset_left = 52.0 @@ -82,14 +129,12 @@ offset_bottom = 368.0 [node name="GameLabel" type="Label" parent="VBoxContainer"] layout_mode = 2 -text = "????????" label_settings = SubResource("LabelSettings_qspbu") horizontal_alignment = 1 autowrap_mode = 2 [node name="SongLabel" type="Label" parent="VBoxContainer"] layout_mode = 2 -text = "??????" label_settings = SubResource("LabelSettings_3m52w") horizontal_alignment = 1 autowrap_mode = 2 @@ -110,15 +155,12 @@ size_flags_vertical = 4 [node name="PlayButton" type="Button" parent="PanelContainer/HBoxContainer"] layout_mode = 2 +shortcut = SubResource("Shortcut_6mgjo") text = "Play" -[node name="PauseButton" type="Button" parent="PanelContainer/HBoxContainer"] +[node name="RestartButton" type="Button" parent="PanelContainer/HBoxContainer"] layout_mode = 2 -text = "Pause" - -[node name="StopButton" type="Button" parent="PanelContainer/HBoxContainer"] -layout_mode = 2 -text = "Stop" +text = "Restart" [node name="HSlider" type="HSlider" parent="PanelContainer/HBoxContainer"] layout_mode = 2 @@ -158,11 +200,36 @@ size_flags_horizontal = 3 text = "Players" horizontal_alignment = 1 -[node name="AddPlayer" type="TextureButton" parent="Players/VBoxContainer/HBoxContainer"] +[node name="AddPlayersButton" type="TextureButton" parent="Players/VBoxContainer/HBoxContainer"] layout_mode = 2 size_flags_horizontal = 8 +shortcut = SubResource("Shortcut_jafqj") texture_normal = ExtResource("4_op458") +[node name="AddPlayerContainer" type="HBoxContainer" parent="Players/VBoxContainer"] +visible = false +layout_mode = 2 + +[node name="Panel" type="Panel" parent="Players/VBoxContainer/AddPlayerContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 + +[node name="PlayerNameField" type="TextEdit" parent="Players/VBoxContainer/AddPlayerContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "Player name" +script = ExtResource("7_qsdfy") + +[node name="AddPlayerButton" type="Button" parent="Players/VBoxContainer/AddPlayerContainer"] +layout_mode = 2 +text = "Add" + +[node name="Panel2" type="Panel" parent="Players/VBoxContainer/AddPlayerContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 + [node name="ResetPlaylistButton" type="Button" parent="."] layout_mode = 0 offset_left = 125.0 @@ -179,7 +246,7 @@ offset_right = 358.0 offset_bottom = 1049.0 text = "Reset points" -[node name="SuncButton" type="Button" parent="."] +[node name="SyncButton" type="Button" parent="."] layout_mode = 0 offset_left = 370.0 offset_top = 1016.0 @@ -201,6 +268,7 @@ offset_left = 611.0 offset_top = 1016.0 offset_right = 722.0 offset_bottom = 1047.0 +shortcut = SubResource("Shortcut_a7fvb") text = "Show answer" [node name="NextButton" type="Button" parent="."] @@ -209,6 +277,7 @@ offset_left = 729.0 offset_top = 1017.0 offset_right = 904.0 offset_bottom = 1048.0 +shortcut = SubResource("Shortcut_d6fml") text = "Randomize new track" [node name="MusicListPanel" type="PanelContainer" parent="."] @@ -227,4 +296,154 @@ script = ExtResource("7_dj026") [node name="MusicList" type="VBoxContainer" parent="MusicListPanel/ScrollContainer"] layout_mode = 2 +[node name="SearchButton" type="Button" parent="."] +layout_mode = 0 +offset_left = 1528.0 +offset_top = 8.0 +offset_right = 1598.0 +offset_bottom = 48.0 +shortcut = SubResource("Shortcut_fbju4") +text = "Search" + +[node name="SettingsButton" type="Button" parent="."] +layout_mode = 0 +offset_left = 1624.0 +offset_top = 8.0 +offset_right = 1694.0 +offset_bottom = 48.0 +text = "Settings" + +[node name="StatisticsButton" type="Button" parent="."] +layout_mode = 0 +offset_left = 1720.0 +offset_top = 8.0 +offset_right = 1798.0 +offset_bottom = 48.0 +text = "Statistics" + +[node name="AboutButton" type="Button" parent="."] +layout_mode = 0 +offset_left = 1824.0 +offset_top = 8.0 +offset_right = 1894.0 +offset_bottom = 48.0 +text = "About" + +[node name="Search" parent="." instance=ExtResource("9_5ijvr")] +visible = false +layout_mode = 1 +offset_left = 349.196 +offset_top = 81.2367 +offset_right = 349.196 +offset_bottom = 81.2367 + +[node name="SyncPopupPanel" type="PopupPanel" parent="."] +initial_position = 2 +size = Vector2i(140, 70) + +[node name="Label" type="Label" parent="SyncPopupPanel"] +offset_left = 4.0 +offset_top = 4.0 +offset_right = 136.0 +offset_bottom = 66.0 +text = "Games synced!" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="StatisticsPopupPanel" type="PopupPanel" parent="."] +initial_position = 2 +size = Vector2i(450, 100) + +[node name="Label" type="Label" parent="StatisticsPopupPanel"] +offset_left = 4.0 +offset_top = 4.0 +offset_right = 446.0 +offset_bottom = 96.0 +text = "Statistics" +horizontal_alignment = 1 + +[node name="StatisticsLabel" type="Label" parent="StatisticsPopupPanel"] +offset_left = 4.0 +offset_top = 4.0 +offset_right = 446.0 +offset_bottom = 96.0 +text = "Total amount of games in the playlist: 9000" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="AboutPopupPanel" type="PopupPanel" parent="."] +initial_position = 2 +size = Vector2i(848, 272) + +[node name="VBoxContainer" type="VBoxContainer" parent="AboutPopupPanel"] +offset_left = 4.0 +offset_top = 4.0 +offset_right = 844.0 +offset_bottom = 273.0 + +[node name="Label" type="Label" parent="AboutPopupPanel/VBoxContainer"] +layout_mode = 2 +text = "Music Player Randomizer" +horizontal_alignment = 1 + +[node name="VersionLabel" type="Label" parent="AboutPopupPanel/VBoxContainer"] +layout_mode = 2 +horizontal_alignment = 1 + +[node name="AboutLabel" type="Label" parent="AboutPopupPanel/VBoxContainer"] +layout_mode = 2 +text = "Try your video game music knowledge with this VGM randomizer, invite your friends and see who is the best." +horizontal_alignment = 1 + +[node name="HBoxContainer" type="HBoxContainer" parent="AboutPopupPanel/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="NewLabel" type="Label" parent="AboutPopupPanel/VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 +text = "0.7-Beta: Can now hop between songs" +autowrap_mode = 2 + +[node name="ShortcutsLabel" type="Label" parent="AboutPopupPanel/VBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="CommingLabel" type="Label" parent="AboutPopupPanel/VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 +text = "Fix reset buttons +Fix settings +Fix winner +Fix graphics in lists +Fix layout +Fix for local play +Change some buttons to icons +Add shortcuts" +autowrap_mode = 2 + +[node name="SettingsPopupPanel" type="PopupPanel" parent="."] +initial_position = 2 +size = Vector2i(268, 233) + +[node name="SettingsWindow" parent="SettingsPopupPanel" instance=ExtResource("11_k62u5")] +offset_left = 4.0 +offset_top = 4.0 +offset_right = 264.0 +offset_bottom = 252.0 + +[node name="WinnerPopupPanel" type="PopupPanel" parent="."] +initial_position = 2 +size = Vector2i(350, 100) + +[node name="WinnerLabel" type="Label" parent="WinnerPopupPanel"] +offset_left = 4.0 +offset_top = 4.0 +offset_right = 346.0 +offset_bottom = 96.0 +text = "Sansan won!!" +label_settings = SubResource("LabelSettings_hr75l") +horizontal_alignment = 1 + [connection signal="dir_selected" from="FileDialog" to="." method="_on_file_dialog_dir_selected"] diff --git a/Player.gd b/Player.gd index 4b9c087..5ba39f1 100644 --- a/Player.gd +++ b/Player.gd @@ -1,5 +1,8 @@ extends Control +@onready +var player_name_field := $HBoxContainer/Name + @onready var points := $HBoxContainer/Points @@ -13,31 +16,52 @@ var minus := $HBoxContainer/RemovePoint var character := $HBoxContainer/Character signal change_character_clicked +signal first_point_triggerd +signal match_point_triggerd +signal winner_triggerd + +@export +var player_name: String + +var is_first_point: bool = true + # Called when the node enters the scene tree for the first time. func _ready(): - print("_ready") add.pressed.connect(add_point) minus.pressed.connect(minus_point) character.pressed.connect(change_character) + player_name_field.text = player_name + +func new_name(new_name: String): + player_name = new_name func add_point(): - var value := int(points.text) - points.text = str(value + 1) + if is_first_point: + is_first_point = false + first_point_triggerd.emit() + + var new_value := int(points.text) + 1 + points.text = str(new_value) + if new_value == Settings.winning_score - 1: + match_point_triggerd.emit() + + if new_value == Settings.winning_score: + winner_triggerd.emit() + func minus_point(): - var value := int(points.text) - points.text = str(value - 1) + var new_value := int(points.text) - 1 + points.text = str(new_value) + if new_value == 0: + is_first_point = true + func change_character(): print("change_character") change_character_clicked.emit() -# Called every frame. 'delta' is the elapsed time since the previous frame. -func _process(delta): - pass - func _on_control_character_selected_clicked(file_name: String): print("Back in player list with: " + file_name) diff --git a/PlayerNameField.gd b/PlayerNameField.gd new file mode 100644 index 0000000..fd2c69d --- /dev/null +++ b/PlayerNameField.gd @@ -0,0 +1,12 @@ +extends TextEdit + +signal enter_key_pressed +signal close_pressed + +func _input(event): + if event is InputEventKey and event.pressed: + if event.alt_pressed && event.keycode == KEY_A: + close_pressed.emit() + + if event.keycode == KEY_ENTER: + enter_key_pressed.emit() diff --git a/SearchWindow.gd b/SearchWindow.gd new file mode 100644 index 0000000..ee1138c --- /dev/null +++ b/SearchWindow.gd @@ -0,0 +1,78 @@ +extends Control + +@onready +var search_list := $ScrollContainer/VBoxContainer + +@onready +var clear_button := $ClearButton + +@onready +var close_button := $CloseButton + +@onready +var search_bar := $Searchbar + +var games := [] + +# Called when the node enters the scene tree for the first time. +func _ready(): + get_list_of_games() + clear_button.pressed.connect(clear) + close_button.pressed.connect(close) + search_bar.grab_focus() + search_bar.text_changed.connect(search) + visibility_changed.connect(focus) + +func focus(): + if self.visible == true: + search_bar.grab_focus() + +func close(): + clear() + self.visible = false + +func search(): + print(search_bar.text) + delete_children(search_list) + for game in games: + if search_bar.text == "" || game.replace(" ", "").to_lower().contains(search_bar.text.replace(" ", "").to_lower()): + var label := Label.new() + label.text = game + label.autowrap_mode = TextServer.AUTOWRAP_WORD + search_list.add_child(label) + +static func delete_children(node): + for n in node.get_children(): + node.remove_child(n) + n.queue_free() + +func get_list_of_games() -> void: + var http_request = HTTPRequest.new() + add_child(http_request) + http_request.request_completed.connect(self._http_request_completed) + + # Perform a GET request. The URL below returns JSON as of writing. + var error = http_request.request(Settings.default_path + "/music/all/order") + if error != OK: + push_error("An error occurred in the HTTP request.") + +# Called when the HTTP request is completed. +func _http_request_completed(result, response_code, headers, body): + var json = JSON.new() + var error = json.parse(body.get_string_from_utf8()) + + if error == OK: + var data_received = json.get_data() + if typeof(data_received) == TYPE_ARRAY: + games.append_array(data_received) + for game in games: + var label := Label.new() + label.text = game + label.autowrap_mode = TextServer.AUTOWRAP_WORD + search_list.add_child(label) + else: + print("Unexpected data") + +func clear(): + search_bar.text = "" + search_bar.grab_focus() diff --git a/SearchWindow.tscn b/SearchWindow.tscn new file mode 100644 index 0000000..3c0dfca --- /dev/null +++ b/SearchWindow.tscn @@ -0,0 +1,55 @@ +[gd_scene load_steps=2 format=3 uid="uid://bxydgil1yifps"] + +[ext_resource type="Script" path="res://SearchWindow.gd" id="1_m7bij"] + +[node name="Control" 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_m7bij") + +[node name="Panel" type="Panel" parent="."] +layout_mode = 0 +offset_right = 1152.0 +offset_bottom = 640.0 + +[node name="ClearButton" type="Button" parent="."] +layout_mode = 0 +offset_left = 880.0 +offset_top = 24.0 +offset_right = 944.0 +offset_bottom = 64.0 +scale = Vector2(2, 2) +text = "Clear" + +[node name="CloseButton" type="Button" parent="."] +layout_mode = 2 +offset_left = 1032.0 +offset_top = 24.0 +offset_right = 1082.0 +offset_bottom = 64.0 +scale = Vector2(2, 2) +text = "Close" + +[node name="Searchbar" type="TextEdit" parent="."] +layout_mode = 0 +offset_left = 64.0 +offset_top = 24.0 +offset_right = 448.0 +offset_bottom = 64.0 +scale = Vector2(2, 2) +placeholder_text = "Search" + +[node name="ScrollContainer" type="ScrollContainer" parent="."] +layout_mode = 2 +offset_top = 128.0 +offset_right = 576.0 +offset_bottom = 384.0 +scale = Vector2(2, 2) + +[node name="VBoxContainer" type="VBoxContainer" parent="ScrollContainer"] +layout_mode = 2 +size_flags_horizontal = 3 diff --git a/Settings.gd b/Settings.gd new file mode 100644 index 0000000..0011ee5 --- /dev/null +++ b/Settings.gd @@ -0,0 +1,60 @@ +extends Node + +#var default_path: String = "http://192.168.86.100:8085" +#var default_path: String = "https://music.sanplex.tech" +var default_path: String = "https://tmusic.sanplex.tech" +var selected_server = 0 + +var is_local: bool = false + +var stop_after_current: bool = false +var hide_next_track: bool = false +var add_to_stats: bool = false +var use_low_played_mode: bool = false +var winning_score: int = 20 + +var version: String = "0.7.8-Beta" +var whats_new: String = "Changelog: +0.7.8-Beta: Added shortcuts. Added dialog for winner. Started cleaning code. +0.7.5-Beta: Added settings menu, most things don't do anythig yet +0.7-Beta: Can now hop between songs" +var whats_left: String = "Things left to do: +Fix reset buttons +Fix settings +Fix graphics in lists +Fix layout +Fix for local play +Change some buttons to icons" + +var shortcuts: String = "Shortcuts: +Alt + S = Search +Alt + A = Add Players +Alt + X = Play/Pause +Alt + C = Next Song +Alt + V = Show Answer" + + +#play = X +#nästa = c +#visa svar = v +#lägga till poäng? 1, 2, 3, 4, 5, 6 + + +func make_request2(address: String, func_name: Callable) -> void: + var error_handling = func(result, response_code, headers, body): + var json = JSON.new() + var error = json.parse(body.get_string_from_utf8()) + if error == OK: + var data_received = json.get_data() + print("data_received: ", data_received) + func_name.call(data_received) + + var http_request = HTTPRequest.new() + add_child(http_request) + http_request.request_completed.connect(error_handling) + + # Perform a GET request. The URL below returns JSON as of writing. + var error = http_request.request(default_path + address) + if error != OK: + push_error("An error occurred in the HTTP request.") + diff --git a/SettingsWindow.gd b/SettingsWindow.gd new file mode 100644 index 0000000..cfa486a --- /dev/null +++ b/SettingsWindow.gd @@ -0,0 +1,65 @@ +extends VBoxContainer + +@onready +var stop_after_current_button := $StopAfterCurrentCheckButton + +@onready +var hide_next_track_button := $HideNextTrackCheckButton + +@onready +var add_to_database_button := $AddToDatabaseCheckButton + +@onready +var low_played_button := $LowPlayedCheckButton + +@onready +var score_label := $HBoxContainer/ScoreLabel + +@onready +var lower_winning_score_button := $HBoxContainer/LowerButton + +@onready +var increase_winning_score_button := $HBoxContainer/IncreaseButton + +@onready +var select_server_button := $SelectServerButton + +# Called when the node enters the scene tree for the first time. +func _ready(): + stop_after_current_button.pressed.connect(stop_after_current) + hide_next_track_button.pressed.connect(hide_next_track) + add_to_database_button.pressed.connect(add_to_database) + low_played_button.pressed.connect(low_played) + lower_winning_score_button.pressed.connect(lower_winning_score) + increase_winning_score_button.pressed.connect(increase_winning_score) + select_server_button.pressed.connect(select_server) + + stop_after_current_button.button_pressed = Settings.stop_after_current + hide_next_track_button.button_pressed = Settings.hide_next_track + add_to_database_button.button_pressed = Settings.add_to_stats + low_played_button.button_pressed = Settings.use_low_played_mode + select_server_button.select(Settings.selected_server) + +func stop_after_current(): + Settings.stop_after_current = !Settings.stop_after_current + +func hide_next_track(): + Settings.hide_next_track = !Settings.hide_next_track + +func add_to_database(): + Settings.add_to_stats = !Settings.add_to_stats + +func low_played(): + Settings.use_low_played_mode = !Settings.use_low_played_mode + +func lower_winning_score(): + Settings.winning_score -= 1 + score_label.text = str(Settings.winning_score) + +func increase_winning_score(): + Settings.winning_score += 1 + score_label.text = str(Settings.winning_score) + +func select_server() -> void: + Settings.default_path = select_server_button.get_item_text(select_server_button.selected) + Settings.selected_server = select_server_button.selected diff --git a/SettingsWindow.tscn b/SettingsWindow.tscn new file mode 100644 index 0000000..51f7a5d --- /dev/null +++ b/SettingsWindow.tscn @@ -0,0 +1,80 @@ +[gd_scene load_steps=3 format=3 uid="uid://dldpeo5y3l5hq"] + +[ext_resource type="Script" path="res://SettingsWindow.gd" id="1_bt55j"] + +[sub_resource type="LabelSettings" id="LabelSettings_3xrlm"] +font_size = 25 + +[node name="VBoxContainer" type="VBoxContainer"] +clip_contents = true +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +script = ExtResource("1_bt55j") + +[node name="Label" type="Label" parent="."] +layout_mode = 2 +size_flags_vertical = 0 +text = "Settings" +label_settings = SubResource("LabelSettings_3xrlm") +horizontal_alignment = 1 + +[node name="StopAfterCurrentCheckButton" type="CheckButton" parent="."] +layout_mode = 2 +size_flags_horizontal = 0 +action_mode = 0 +text = "Stop after current" + +[node name="HideNextTrackCheckButton" type="CheckButton" parent="."] +layout_mode = 2 +size_flags_horizontal = 0 +action_mode = 0 +text = "Hide next track" + +[node name="AddToDatabaseCheckButton" type="CheckButton" parent="."] +layout_mode = 2 +size_flags_horizontal = 0 +action_mode = 0 +text = "Turn on played to database" + +[node name="LowPlayedCheckButton" type="CheckButton" parent="."] +layout_mode = 2 +size_flags_horizontal = 0 +action_mode = 0 +text = "Use low played mode" + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="Label2" type="Label" parent="HBoxContainer"] +layout_mode = 2 +text = "Winning Score: " + +[node name="ScoreLabel" type="Label" parent="HBoxContainer"] +layout_mode = 2 +text = "20" + +[node name="LowerButton" type="Button" parent="HBoxContainer"] +custom_minimum_size = Vector2(30, 2.08165e-12) +layout_mode = 2 +text = "-1" + +[node name="IncreaseButton" type="Button" parent="HBoxContainer"] +custom_minimum_size = Vector2(30, 2.08165e-12) +layout_mode = 2 +text = "+1" + +[node name="SelectServerButton" type="OptionButton" parent="."] +layout_mode = 2 +item_count = 3 +selected = 0 +popup/item_0/text = "https://tmusic.sanplex.tech" +popup/item_0/id = 0 +popup/item_1/text = "https://music.sanplex.tech" +popup/item_1/id = 1 +popup/item_2/text = "http://192.168.86.100:8085" +popup/item_2/id = 2 diff --git a/export_presets.cfg b/export_presets.cfg index 89dcd54..f454433 100644 --- a/export_presets.cfg +++ b/export_presets.cfg @@ -8,28 +8,24 @@ custom_features="" export_filter="all_resources" include_filter="" exclude_filter="" -export_path="" +export_path="../../ResilioSync/Sorterat/MusicPlayer_0.7.8_Beta.exe" encryption_include_filters="" encryption_exclude_filters="" encrypt_pck=false encrypt_directory=false -script_encryption_key="" [preset.0.options] custom_template/debug="" custom_template/release="" -debug/export_console_script=1 -binary_format/embed_pck=false +debug/export_console_wrapper=0 +binary_format/embed_pck=true texture_format/bptc=true texture_format/s3tc=true texture_format/etc=false texture_format/etc2=false binary_format/architecture="x86_64" codesign/enable=false -codesign/identity_type=0 -codesign/identity="" -codesign/password="" codesign/timestamp=true codesign/timestamp_server_url="" codesign/digest_algorithm=1 @@ -63,6 +59,7 @@ Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorActi ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue Remove-Item -Recurse -Force '{temp_dir}'" +debug/export_console_script=1 [preset.1] @@ -74,33 +71,40 @@ custom_features="" export_filter="all_resources" include_filter="" exclude_filter="" -export_path="" +export_path="./MusicPlayer_0.6_Beta.dmg" encryption_include_filters="" encryption_exclude_filters="" encrypt_pck=false encrypt_directory=false -script_encryption_key="" [preset.1.options] +export/distribution_type=1 binary_format/architecture="universal" custom_template/debug="" custom_template/release="" -debug/export_console_script=1 +debug/export_console_wrapper=0 application/icon="" application/icon_interpolation=4 -application/bundle_identifier="" +application/bundle_identifier="tech.sanplex.musicplayer" application/signature="" -application/app_category="Games" +application/app_category="Music-games" application/short_version="1.0" application/version="1.0" application/copyright="" application/copyright_localized={} +application/min_macos_version="10.12" display/high_res=true +xcode/platform_build="14C18" +xcode/sdk_version="13.1" +xcode/sdk_build="22C55" +xcode/sdk_name="macosx13.1" +xcode/xcode_version="1420" +xcode/xcode_build="14C18" codesign/codesign=3 +codesign/installer_identity="" +codesign/apple_team_id="" codesign/identity="" -codesign/certificate_file="" -codesign/certificate_password="" codesign/entitlements/custom_file="" codesign/entitlements/allow_jit_code_execution=false codesign/entitlements/allow_unsigned_executable_memory=false @@ -126,12 +130,6 @@ codesign/entitlements/app_sandbox/files_movies=0 codesign/entitlements/app_sandbox/helper_executables=[] codesign/custom_options=PackedStringArray() notarization/notarization=0 -notarization/apple_id_name="" -notarization/apple_id_password="" -notarization/apple_team_id="" -notarization/api_uuid="" -notarization/api_key="" -notarization/api_key_id="" privacy/microphone_usage_description="" privacy/microphone_usage_description_localized={} privacy/camera_usage_description="" @@ -165,66 +163,26 @@ open \"{temp_dir}/{exe_name}.app\" --args {cmd_args}" ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash kill $(pgrep -x -f \"{temp_dir}/{exe_name}.app/Contents/MacOS/{exe_name} {cmd_args}\") rm -rf \"{temp_dir}\"" +debug/export_console_script=1 +notarization/apple_team_id="" [preset.2] -name="Linux/X11" -platform="Linux/X11" -runnable=true -dedicated_server=false -custom_features="" -export_filter="all_resources" -include_filter="" -exclude_filter="" -export_path="" -encryption_include_filters="" -encryption_exclude_filters="" -encrypt_pck=false -encrypt_directory=false -script_encryption_key="" - -[preset.2.options] - -custom_template/debug="" -custom_template/release="" -debug/export_console_script=1 -binary_format/embed_pck=false -texture_format/bptc=true -texture_format/s3tc=true -texture_format/etc=false -texture_format/etc2=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}\"" - -[preset.3] - name="Web" platform="Web" -runnable=true +runnable=false dedicated_server=false custom_features="" export_filter="all_resources" include_filter="" exclude_filter="" -export_path="" +export_path="web/index.html" encryption_include_filters="" encryption_exclude_filters="" encrypt_pck=false encrypt_directory=false -script_encryption_key="" -[preset.3.options] +[preset.2.options] custom_template/debug="" custom_template/release="" diff --git a/project.godot b/project.godot index 6c57609..4dda3e4 100644 --- a/project.godot +++ b/project.godot @@ -16,6 +16,10 @@ config/features=PackedStringArray("4.2", "Forward Plus") run/low_processor_mode=true config/icon="res://icon.svg" +[autoload] + +Settings="*res://Settings.gd" + [display] window/size/viewport_width=1920