Move server calls to MusicServerClient and give players stable ids
Server requests move out of Settings into a new MusicServerClient autoload with one function per endpoint. It sends requests through a swappable HttpTransport so tests can fake the server, and it frees its HTTPRequest nodes after use. Players now have a UUID that never changes. Their position in Settings.player_array is only used for the Alt+<number> keybinds. Previously the position doubled as the id, so removing a player made points and wins land on the wrong player, and could delete another player's point from a song. Also fixes: - format_time showed 59.6 seconds as "00:60" - searches containing regex characters such as "Q*bert" broke search - SongObject and PlayerObject were Nodes that were never freed; they are now RefCounted - search matching is split out of the UI code into find_matches()
This commit is contained in:
1 parent
ab338b0696
commit
56e9fe66d3
18 files changed
+281
-162
No files matched your search
+27
-31
@@ -257,7 +257,7 @@ func fetch_song_list_at_start() -> void:
|
|||||||
print("Unexpected data")
|
print("Unexpected data")
|
||||||
Playlist.update_last_played_song()
|
Playlist.update_last_played_song()
|
||||||
update_song_list()
|
update_song_list()
|
||||||
Settings.make_request2("/music/list", fetch_song_list_at_start_done, true)
|
MusicServerClient.fetch_song_list(fetch_song_list_at_start_done)
|
||||||
|
|
||||||
func play_next_song() -> void:
|
func play_next_song() -> void:
|
||||||
print("play_next_song ", Playlist.latest_played_song)
|
print("play_next_song ", Playlist.latest_played_song)
|
||||||
@@ -277,11 +277,6 @@ func play_next_song() -> void:
|
|||||||
func fetch_song() -> void:
|
func fetch_song() -> void:
|
||||||
print("fetch_song")
|
print("fetch_song")
|
||||||
Playlist.is_song_downloading = true
|
Playlist.is_song_downloading = true
|
||||||
var url: String = ""
|
|
||||||
if Settings.use_low_played_mode:
|
|
||||||
url = "/music/rand/low"
|
|
||||||
else:
|
|
||||||
url = "/music/rand"
|
|
||||||
var new_song_object: SongObject = SongObject.new()
|
var new_song_object: SongObject = SongObject.new()
|
||||||
var fetch_song_done: Callable = func fetch_song_done(body: PackedByteArray) -> void:
|
var fetch_song_done: Callable = func fetch_song_done(body: PackedByteArray) -> void:
|
||||||
print("fetch_song_done")
|
print("fetch_song_done")
|
||||||
@@ -306,11 +301,11 @@ func fetch_song() -> void:
|
|||||||
Playlist.is_song_downloading = false
|
Playlist.is_song_downloading = false
|
||||||
if Settings.is_debug:
|
if Settings.is_debug:
|
||||||
update_song_list()
|
update_song_list()
|
||||||
Settings.make_request2("/music/info", fetch_song_info_done, true)
|
MusicServerClient.fetch_song_info(fetch_song_info_done)
|
||||||
|
|
||||||
Settings.make_request2("/music/addQue", added_to_que_done, false)
|
MusicServerClient.add_to_queue(added_to_que_done)
|
||||||
|
|
||||||
Settings.make_request2(url, fetch_song_done, true)
|
MusicServerClient.fetch_random_song(Settings.use_low_played_mode, fetch_song_done)
|
||||||
|
|
||||||
func update_song_list() -> void:
|
func update_song_list() -> void:
|
||||||
print("update_song_list")
|
print("update_song_list")
|
||||||
@@ -335,7 +330,7 @@ func song_object_clicked(event: InputEvent, song_no: int) -> void:
|
|||||||
sound.data = body
|
sound.data = body
|
||||||
Playlist.add_song_to_song_object(song_no, sound)
|
Playlist.add_song_to_song_object(song_no, sound)
|
||||||
music_player_container.play_song_object(song_no)
|
music_player_container.play_song_object(song_no)
|
||||||
Settings.make_request2("/music?song=" + str(song_no), song_downloaded, true)
|
MusicServerClient.fetch_song(song_no, song_downloaded)
|
||||||
else:
|
else:
|
||||||
print("song already downloaded")
|
print("song already downloaded")
|
||||||
music_player_container.play_song_object(song_no)
|
music_player_container.play_song_object(song_no)
|
||||||
@@ -347,7 +342,7 @@ func reset_playlist() -> void:
|
|||||||
fetch_song_list_at_start()
|
fetch_song_list_at_start()
|
||||||
fetch_song()
|
fetch_song()
|
||||||
|
|
||||||
Settings.make_request2("/music/reset", playlist_reset_done, false)
|
MusicServerClient.reset_playlist(playlist_reset_done)
|
||||||
|
|
||||||
func reset_points() -> void:
|
func reset_points() -> void:
|
||||||
print("reset_points")
|
print("reset_points")
|
||||||
@@ -412,7 +407,7 @@ func get_suggestion_list() -> void:
|
|||||||
inspiration_list.add_child(inspiration_label)
|
inspiration_list.add_child(inspiration_label)
|
||||||
else:
|
else:
|
||||||
print("Unexpected data")
|
print("Unexpected data")
|
||||||
Settings.make_request2("/music/all", populate_list, true)
|
MusicServerClient.fetch_all_soundtracks(populate_list)
|
||||||
|
|
||||||
func add_players() -> void:
|
func add_players() -> void:
|
||||||
print("add_players")
|
print("add_players")
|
||||||
@@ -423,15 +418,15 @@ func add_players() -> void:
|
|||||||
func add_player() -> void:
|
func add_player() -> void:
|
||||||
print("add_player")
|
print("add_player")
|
||||||
if new_player_name_field.text != "" && Settings.player_array.size() < Settings.MAX_NUMBER_OF_PLAYERS:
|
if new_player_name_field.text != "" && Settings.player_array.size() < Settings.MAX_NUMBER_OF_PLAYERS:
|
||||||
var new_player_object: PlayerObject = PlayerObject.new(new_player_name_field.text, Settings.player_array.size())
|
var new_player_object: PlayerObject = PlayerObject.new(new_player_name_field.text)
|
||||||
new_player_name_field.text = ""
|
new_player_name_field.text = ""
|
||||||
Settings.player_array.append(new_player_object)
|
Settings.player_array.append(new_player_object)
|
||||||
new_player_object.connect("first_point_triggerd", music_player_container._on_point_triggered.bind("first"))
|
new_player_object.connect("first_point_triggerd", music_player_container._on_point_triggered.bind("first"))
|
||||||
new_player_object.connect("match_point_triggerd", music_player_container._on_point_triggered.bind("match"))
|
new_player_object.connect("match_point_triggerd", music_player_container._on_point_triggered.bind("match"))
|
||||||
new_player_object.connect("winner_triggerd", _on_player_won.bind(new_player_object.id))
|
new_player_object.connect("winner_triggerd", _on_player_won.bind(new_player_object))
|
||||||
new_player_object.connect("point_given_sound", _on_make_point_given_sound)
|
new_player_object.connect("point_given_sound", _on_make_point_given_sound)
|
||||||
new_player_object.connect("player_point_given", _on_point_given.bind(new_player_object.id))
|
new_player_object.connect("player_point_given", _on_point_given.bind(new_player_object))
|
||||||
new_player_object.connect("player_point_taken", _on_point_taken.bind(new_player_object.id))
|
new_player_object.connect("player_point_taken", _on_point_taken.bind(new_player_object))
|
||||||
load_players()
|
load_players()
|
||||||
|
|
||||||
func load_players() -> void:
|
func load_players() -> void:
|
||||||
@@ -442,43 +437,44 @@ func load_players() -> void:
|
|||||||
print(player_object.player_name)
|
print(player_object.player_name)
|
||||||
|
|
||||||
var new_player: Player = player.instantiate()
|
var new_player: Player = player.instantiate()
|
||||||
new_player.id = counter
|
new_player.player_object = player_object
|
||||||
|
new_player.list_index = counter
|
||||||
|
|
||||||
new_player.connect("change_character_clicked", _on_player_change_character_clicked.bind(new_player, player_object.player_name))
|
new_player.connect("change_character_clicked", _on_player_change_character_clicked.bind(new_player, player_object.player_name))
|
||||||
new_player.connect("player_removed", _on_player_removed.bind(counter))
|
new_player.connect("player_removed", _on_player_removed.bind(player_object))
|
||||||
|
|
||||||
players_list_container.add_child(new_player)
|
players_list_container.add_child(new_player)
|
||||||
counter += 1
|
counter += 1
|
||||||
|
|
||||||
func _on_point_given(player_given_point: int) -> void:
|
func _on_point_given(player_object: PlayerObject) -> void:
|
||||||
print("_on_point_given")
|
print("_on_point_given")
|
||||||
log_window.add_log_row(Settings.player_array[player_given_point].player_name + " got a point")
|
log_window.add_log_row(player_object.player_name + " got a point")
|
||||||
if Playlist.currently_playing_song >= 0:
|
if Playlist.currently_playing_song >= 0:
|
||||||
Playlist.add_point(player_given_point)
|
Playlist.add_point(player_object.id)
|
||||||
update_song_list()
|
update_song_list()
|
||||||
|
|
||||||
func _on_make_point_given_sound() -> void:
|
func _on_make_point_given_sound() -> void:
|
||||||
music_player_container.play_sound_effect(preload("res://sounds/itemopen.wav"))
|
music_player_container.play_sound_effect(preload("res://sounds/itemopen.wav"))
|
||||||
|
|
||||||
func _on_point_taken(player_taken_point: int) -> void:
|
func _on_point_taken(player_object: PlayerObject) -> void:
|
||||||
print("_on_point_taken")
|
print("_on_point_taken")
|
||||||
log_window.add_log_row(Settings.player_array[player_taken_point].player_name + " lost a point")
|
log_window.add_log_row(player_object.player_name + " lost a point")
|
||||||
music_player_container.play_sound_effect(preload("res://sounds/itemequip.wav"))
|
music_player_container.play_sound_effect(preload("res://sounds/itemequip.wav"))
|
||||||
if Playlist.currently_playing_song >= 0:
|
if Playlist.currently_playing_song >= 0:
|
||||||
Playlist.remove_point(player_taken_point)
|
Playlist.remove_point(player_object.id)
|
||||||
update_song_list()
|
update_song_list()
|
||||||
|
|
||||||
func _on_player_won(winning_player_id: int) -> void:
|
func _on_player_won(player_object: PlayerObject) -> void:
|
||||||
print("_on_player_won")
|
print("_on_player_won")
|
||||||
winner_window.show_winner(winning_player_id)
|
winner_window.show_winner(player_object)
|
||||||
music_player_container.play_song(preload("res://sounds/winning.mp3"))
|
music_player_container.play_song(preload("res://sounds/winning.mp3"))
|
||||||
Settings.add_to_stats = false
|
Settings.add_to_stats = false
|
||||||
|
|
||||||
func _on_player_removed(player_to_remove: int) -> void:
|
func _on_player_removed(player_object: PlayerObject) -> void:
|
||||||
print("_on_player_removed ", player_to_remove)
|
print("_on_player_removed ", player_object.player_name)
|
||||||
Settings.player_array.remove_at(player_to_remove)
|
Settings.player_array.erase(player_object)
|
||||||
load_players()
|
load_players()
|
||||||
Playlist.remove_player_from_list(player_to_remove)
|
Playlist.remove_player_from_list(player_object.id)
|
||||||
update_song_list()
|
update_song_list()
|
||||||
|
|
||||||
func _on_player_change_character_clicked(new_player: Player, player_name: String) -> void:
|
func _on_player_change_character_clicked(new_player: Player, player_name: String) -> void:
|
||||||
|
|||||||
+5
-5
@@ -63,12 +63,12 @@ func _process(_delta: float) -> void:
|
|||||||
music_time_label.text = format_text(progress_slider.value, 0.0)
|
music_time_label.text = format_text(progress_slider.value, 0.0)
|
||||||
|
|
||||||
func format_time(time: float) -> String:
|
func format_time(time: float) -> String:
|
||||||
var mins: String = "%02d" % floor(time / 60)
|
var total_seconds: int = roundi(time)
|
||||||
var sec: String = "%02d" % round(fmod(time, 60))
|
@warning_ignore("integer_division")
|
||||||
return mins + ":" + sec
|
return "%02d:%02d" % [total_seconds / 60, total_seconds % 60]
|
||||||
|
|
||||||
func format_text(part: float, total: float) -> String:
|
func format_text(part: float, total: float) -> String:
|
||||||
if (Settings.hide_beginning && part <= Settings.hide_for_seconds) && Settings.hide_length:
|
if (Settings.hide_beginning && part < Settings.hide_for_seconds) && Settings.hide_length:
|
||||||
return "??:?? / ??:??"
|
return "??:?? / ??:??"
|
||||||
elif Settings.hide_length:
|
elif Settings.hide_length:
|
||||||
return format_time(part) + " / ??:??"
|
return format_time(part) + " / ??:??"
|
||||||
@@ -209,7 +209,7 @@ func get_sound_test_song() -> void:
|
|||||||
var sound: AudioStream = AudioStreamMP3.new()
|
var sound: AudioStream = AudioStreamMP3.new()
|
||||||
sound.data = body
|
sound.data = body
|
||||||
play_song(sound)
|
play_song(sound)
|
||||||
Settings.make_request2("/music/soundTest", test_sound, true)
|
MusicServerClient.fetch_sound_test_song(test_sound)
|
||||||
|
|
||||||
##### LOCAL
|
##### LOCAL
|
||||||
var local_path: String = '/Users/sebastian/ResilioSync/Sorterat_test/Metal Gear Solid 4 - Guns of the Patriots/2-16 Metal Gear Saga.mp3'
|
var local_path: String = '/Users/sebastian/ResilioSync/Sorterat_test/Metal Gear Solid 4 - Guns of the Patriots/2-16 Metal Gear Saga.mp3'
|
||||||
|
|||||||
@@ -19,15 +19,19 @@ var remove_player := $HBoxContainer/RemovePlayer
|
|||||||
signal change_character_clicked
|
signal change_character_clicked
|
||||||
signal player_removed
|
signal player_removed
|
||||||
|
|
||||||
@export
|
## The player shown in this row.
|
||||||
var id: int
|
var player_object: PlayerObject
|
||||||
|
|
||||||
|
## Position in Settings.player_array. Only used for the keybinds: Alt+<list_index + 1>
|
||||||
|
## gives this player a point and Ctrl+Alt+<list_index + 1> takes one away.
|
||||||
|
var list_index: int
|
||||||
|
|
||||||
# Called when the node enters the scene tree for the first time.
|
# Called when the node enters the scene tree for the first time.
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
add_button.pressed.connect(add_point)
|
add_button.pressed.connect(add_point)
|
||||||
add_button.set_shortcut(create_button_shortcut(id, false))
|
add_button.set_shortcut(create_button_shortcut(list_index, false))
|
||||||
minus_button.pressed.connect(minus_point)
|
minus_button.pressed.connect(minus_point)
|
||||||
minus_button.set_shortcut(create_button_shortcut(id, true))
|
minus_button.set_shortcut(create_button_shortcut(list_index, true))
|
||||||
character.pressed.connect(change_character)
|
character.pressed.connect(change_character)
|
||||||
remove_player.pressed.connect(func() -> void: player_removed.emit())
|
remove_player.pressed.connect(func() -> void: player_removed.emit())
|
||||||
update_score()
|
update_score()
|
||||||
@@ -36,21 +40,21 @@ func _ready() -> void:
|
|||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
remove_player.visible = Settings.edit_players
|
remove_player.visible = Settings.edit_players
|
||||||
|
|
||||||
func create_button_shortcut(scancode : int, ctrl_pressed: bool) -> Shortcut:
|
func create_button_shortcut(index: int, ctrl_pressed: bool) -> Shortcut:
|
||||||
var button_shortcut: Shortcut = Shortcut.new()
|
var button_shortcut: Shortcut = Shortcut.new()
|
||||||
var button_event : InputEventKey = InputEventKey.new()
|
var button_event : InputEventKey = InputEventKey.new()
|
||||||
button_event.keycode = scancode + 49
|
button_event.keycode = KEY_1 + index
|
||||||
button_event.alt_pressed = true
|
button_event.alt_pressed = true
|
||||||
button_event.ctrl_pressed = ctrl_pressed
|
button_event.ctrl_pressed = ctrl_pressed
|
||||||
button_shortcut.events.append(button_event)
|
button_shortcut.events.append(button_event)
|
||||||
return button_shortcut
|
return button_shortcut
|
||||||
|
|
||||||
func add_point() -> void:
|
func add_point() -> void:
|
||||||
Settings.player_array[id].add_point()
|
player_object.add_point()
|
||||||
update_score()
|
update_score()
|
||||||
|
|
||||||
func minus_point() -> void:
|
func minus_point() -> void:
|
||||||
Settings.player_array[id].minus_point()
|
player_object.minus_point()
|
||||||
update_score()
|
update_score()
|
||||||
|
|
||||||
func change_character() -> void:
|
func change_character() -> void:
|
||||||
@@ -58,22 +62,22 @@ func change_character() -> void:
|
|||||||
|
|
||||||
func character_selected(file_name: String) -> void:
|
func character_selected(file_name: String) -> void:
|
||||||
print("Back in player list with: " + file_name)
|
print("Back in player list with: " + file_name)
|
||||||
Settings.player_array[id].character = load("res://characters/" + file_name)
|
player_object.character = load("res://characters/" + file_name)
|
||||||
set_player_character()
|
set_player_character()
|
||||||
|
|
||||||
func new_character_selected(character_texture: ImageTexture) -> void:
|
func new_character_selected(character_texture: ImageTexture) -> void:
|
||||||
print("Back in player list with new")
|
print("Back in player list with new")
|
||||||
Settings.player_array[id].character = character_texture
|
player_object.character = character_texture
|
||||||
set_player_character()
|
set_player_character()
|
||||||
|
|
||||||
func set_player_character() -> void:
|
func set_player_character() -> void:
|
||||||
character.custom_minimum_size = Vector2(80, 40)
|
character.custom_minimum_size = Vector2(80, 40)
|
||||||
character.ignore_texture_size = true
|
character.ignore_texture_size = true
|
||||||
character.stretch_mode = TextureButton.STRETCH_KEEP_ASPECT_CENTERED
|
character.stretch_mode = TextureButton.STRETCH_KEEP_ASPECT_CENTERED
|
||||||
character.texture_normal = Settings.player_array[id].character
|
character.texture_normal = player_object.character
|
||||||
|
|
||||||
func update_score() -> void:
|
func update_score() -> void:
|
||||||
if OS.has_feature("debug"):
|
if OS.has_feature("debug"):
|
||||||
player_name_field.text = str(Settings.player_array[id].id) + " " + Settings.player_array[id].player_name + ": " + str(Settings.player_array[id].player_score)
|
player_name_field.text = str(list_index + 1) + " " + player_object.player_name + ": " + str(player_object.player_score)
|
||||||
else:
|
else:
|
||||||
player_name_field.text = Settings.player_array[id].player_name + ": " + str(Settings.player_array[id].player_score)
|
player_name_field.text = player_object.player_name + ": " + str(player_object.player_score)
|
||||||
+12
-5
@@ -1,4 +1,4 @@
|
|||||||
extends Node
|
extends RefCounted
|
||||||
class_name PlayerObject
|
class_name PlayerObject
|
||||||
|
|
||||||
signal first_point_triggerd
|
signal first_point_triggerd
|
||||||
@@ -8,8 +8,8 @@ signal point_given_sound
|
|||||||
signal player_point_given
|
signal player_point_given
|
||||||
signal player_point_taken
|
signal player_point_taken
|
||||||
|
|
||||||
@export
|
## Unique id that never changes, unlike the player's position in Settings.player_array.
|
||||||
var id: int
|
var id: String = _generate_uuid()
|
||||||
|
|
||||||
@export
|
@export
|
||||||
var player_name: String
|
var player_name: String
|
||||||
@@ -21,11 +21,18 @@ var is_first_point: bool = true
|
|||||||
|
|
||||||
var character: Texture = load("res://noCharacter.png")
|
var character: Texture = load("res://noCharacter.png")
|
||||||
|
|
||||||
func _init(new_name: String, new_id: int) -> void:
|
func _init(new_name: String) -> void:
|
||||||
player_name = new_name
|
player_name = new_name
|
||||||
id = new_id
|
|
||||||
player_score = 0
|
player_score = 0
|
||||||
|
|
||||||
|
## Returns a random version 4 UUID, e.g. "3f2b8c1e-9a4d-4e7f-b2c6-5d8e1f0a7b93".
|
||||||
|
static func _generate_uuid() -> String:
|
||||||
|
var bytes: PackedByteArray = Crypto.new().generate_random_bytes(16)
|
||||||
|
bytes[6] = (bytes[6] & 0x0f) | 0x40
|
||||||
|
bytes[8] = (bytes[8] & 0x3f) | 0x80
|
||||||
|
var hex: String = bytes.hex_encode()
|
||||||
|
return "%s-%s-%s-%s-%s" % [hex.substr(0, 8), hex.substr(8, 4), hex.substr(12, 4), hex.substr(16, 4), hex.substr(20, 12)]
|
||||||
|
|
||||||
func add_point() -> void:
|
func add_point() -> void:
|
||||||
if player_score < Settings.winning_score:
|
if player_score < Settings.winning_score:
|
||||||
player_score += 1
|
player_score += 1
|
||||||
|
|||||||
+26
-17
@@ -66,12 +66,18 @@ func perform_search(search_text: String) -> void:
|
|||||||
child.visible = false
|
child.visible = false
|
||||||
label_pool.append(child)
|
label_pool.append(child)
|
||||||
|
|
||||||
|
for soundtrack: String in find_matches(search_text):
|
||||||
|
add_soundtrack_reuse(soundtrack)
|
||||||
|
|
||||||
|
## Returns the soundtracks matching [param search_text], best matches first: plain
|
||||||
|
## case-insensitive matches, then matches ignoring spaces and special characters,
|
||||||
|
## then matches with the letters in order but not next to each other.
|
||||||
|
func find_matches(search_text: String) -> Array[String]:
|
||||||
var seen: Dictionary = {}
|
var seen: Dictionary = {}
|
||||||
var search_text_lower: String = search_text.to_lower()
|
var search_text_lower: String = search_text.to_lower()
|
||||||
var clean_search_text: String = clean_term(search_text)
|
var clean_search_text: String = clean_term(search_text)
|
||||||
|
|
||||||
# Collect all matches first, then display in order
|
var matches: Array[String] = []
|
||||||
var matches: Array = []
|
|
||||||
|
|
||||||
# Pass 1: Exact case-insensitive contains match on lowercase versions
|
# Pass 1: Exact case-insensitive contains match on lowercase versions
|
||||||
for i in range(precomputed_soundtracks.size()):
|
for i in range(precomputed_soundtracks.size()):
|
||||||
@@ -98,9 +104,7 @@ func perform_search(search_text: String) -> void:
|
|||||||
seen[st_data["original"]] = true
|
seen[st_data["original"]] = true
|
||||||
matches.append(st_data["original"])
|
matches.append(st_data["original"])
|
||||||
|
|
||||||
# Display all matches in the order they appear in soundtracks
|
return matches
|
||||||
for soundtrack: String in matches:
|
|
||||||
add_soundtrack_reuse(soundtrack)
|
|
||||||
|
|
||||||
# Cleans a term by removing spaces and replacing special characters.
|
# Cleans a term by removing spaces and replacing special characters.
|
||||||
# Matches MusicServer's clean_term() function.
|
# Matches MusicServer's clean_term() function.
|
||||||
@@ -113,6 +117,9 @@ func compile_regex_cached(search_term: String) -> RegEx:
|
|||||||
var regex = RegEx.new()
|
var regex = RegEx.new()
|
||||||
var regText: String = ".*"
|
var regText: String = ".*"
|
||||||
for letter: String in search_term:
|
for letter: String in search_term:
|
||||||
|
# Escape regex metacharacters so searches like "Q*bert" or "(Remix)" work
|
||||||
|
if "\\^$.|?*+()[]{}".contains(letter):
|
||||||
|
regText += "\\"
|
||||||
regText += letter + ".*"
|
regText += letter + ".*"
|
||||||
regex.compile(regText)
|
regex.compile(regText)
|
||||||
regex_cache[search_term] = regex
|
regex_cache[search_term] = regex
|
||||||
@@ -149,26 +156,28 @@ func get_list_of_soundtracks() -> void:
|
|||||||
print("get_list_of_soundtracks")
|
print("get_list_of_soundtracks")
|
||||||
var handle_soundtracks: Callable = func handle_soundtracks(array) -> void:
|
var handle_soundtracks: Callable = func handle_soundtracks(array) -> void:
|
||||||
if typeof(array) == TYPE_ARRAY:
|
if typeof(array) == TYPE_ARRAY:
|
||||||
soundtracks = []
|
|
||||||
precomputed_soundtracks = []
|
|
||||||
# Reuse existing labels: hide all and add to pool
|
# Reuse existing labels: hide all and add to pool
|
||||||
for child: Label in search_list.get_children():
|
for child: Label in search_list.get_children():
|
||||||
child.visible = false
|
child.visible = false
|
||||||
label_pool.append(child)
|
label_pool.append(child)
|
||||||
|
set_soundtracks(array)
|
||||||
soundtracks.append_array(array)
|
|
||||||
# Precompute cleaned versions for all soundtracks
|
|
||||||
for soundtrack: String in soundtracks:
|
for soundtrack: String in soundtracks:
|
||||||
var cleaned = clean_term(soundtrack)
|
|
||||||
precomputed_soundtracks.append({
|
|
||||||
"original": soundtrack,
|
|
||||||
"lowercase": soundtrack.to_lower(),
|
|
||||||
"cleaned": cleaned
|
|
||||||
})
|
|
||||||
add_soundtrack_reuse(soundtrack)
|
add_soundtrack_reuse(soundtrack)
|
||||||
else:
|
else:
|
||||||
print("Unexpected data")
|
print("Unexpected data")
|
||||||
Settings.make_request2("/music/all/order", handle_soundtracks, true)
|
MusicServerClient.fetch_all_soundtracks_ordered(handle_soundtracks)
|
||||||
|
|
||||||
|
## Replaces the searchable soundtracks and precomputes their search forms.
|
||||||
|
func set_soundtracks(list: Array) -> void:
|
||||||
|
soundtracks = []
|
||||||
|
precomputed_soundtracks = []
|
||||||
|
soundtracks.append_array(list)
|
||||||
|
for soundtrack: String in soundtracks:
|
||||||
|
precomputed_soundtracks.append({
|
||||||
|
"original": soundtrack,
|
||||||
|
"lowercase": soundtrack.to_lower(),
|
||||||
|
"cleaned": clean_term(soundtrack)
|
||||||
|
})
|
||||||
|
|
||||||
func _input(event: InputEvent) -> void:
|
func _input(event: InputEvent) -> void:
|
||||||
if self.visible == true:
|
if self.visible == true:
|
||||||
|
|||||||
-60
@@ -30,66 +30,6 @@ var character_select_open: bool = false
|
|||||||
|
|
||||||
var version: String = "1.9.0"
|
var version: String = "1.9.0"
|
||||||
|
|
||||||
func make_request2(address: String, func_name: Callable, expect_data: bool) -> void:
|
|
||||||
var error_handling: Callable = func(_result: int, response_code: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
|
|
||||||
print("request done to address: ", default_path + address + " response_code: ", response_code)
|
|
||||||
if response_code == 200:
|
|
||||||
print("func_name: ", func_name.get_method())
|
|
||||||
if !expect_data:
|
|
||||||
func_name.call()
|
|
||||||
else:
|
|
||||||
var json: JSON = JSON.new()
|
|
||||||
var error: int = json.parse(body.get_string_from_utf8())
|
|
||||||
if error == OK:
|
|
||||||
var data_received = json.get_data()
|
|
||||||
print("data_received type: ", type_string(typeof(data_received)))
|
|
||||||
if typeof(data_received) == TYPE_ARRAY:
|
|
||||||
func_name.call(data_received)
|
|
||||||
elif func_name != null:
|
|
||||||
func_name.call(data_received)
|
|
||||||
else:
|
|
||||||
print("data_received type: ", type_string(typeof(body)))
|
|
||||||
func_name.call(body)
|
|
||||||
|
|
||||||
var http_request: HTTPRequest = 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.
|
|
||||||
print("address: ", default_path + address)
|
|
||||||
var request_error: int = http_request.request(default_path + address)
|
|
||||||
if request_error != OK:
|
|
||||||
push_error("An error occurred in the HTTP request.")
|
|
||||||
|
|
||||||
func make_request3(address: String) -> void:
|
|
||||||
var error_handling: Callable = func(_result: int, response_code: int, _headers: PackedStringArray, _body: PackedByteArray) -> void:
|
|
||||||
print("request done to address: ", default_path + address + " response_code: ", response_code)
|
|
||||||
if response_code != 200:
|
|
||||||
print("Error: " + str(response_code))
|
|
||||||
|
|
||||||
var http_request: HTTPRequest = 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 request_error: int = http_request.request(default_path + address)
|
|
||||||
if request_error != OK:
|
|
||||||
push_error("An error occurred in the HTTP request.")
|
|
||||||
|
|
||||||
func make_put_request(address: String) -> void:
|
|
||||||
var error_handling: Callable = func(_result: int, response_code: int, _headers: PackedStringArray, _body: PackedByteArray) -> void:
|
|
||||||
print("request done to address: ", default_path + address + " response_code: ", response_code)
|
|
||||||
if response_code != 200:
|
|
||||||
print("Error: " + str(response_code))
|
|
||||||
|
|
||||||
var http_request: HTTPRequest = 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 headers: PackedStringArray = ["Content-Type: application/json"]
|
|
||||||
var request_error: int = http_request.request(default_path + address, headers, HTTPClient.METHOD_PUT)
|
|
||||||
if request_error != OK:
|
|
||||||
push_error("An error occurred in the HTTP request.")
|
|
||||||
|
|
||||||
func delete_children(node: Node) -> void:
|
func delete_children(node: Node) -> void:
|
||||||
for n: Node in node.get_children():
|
for n: Node in node.get_children():
|
||||||
node.remove_child(n)
|
node.remove_child(n)
|
||||||
|
|||||||
+8
-9
@@ -1,4 +1,4 @@
|
|||||||
extends Node
|
extends RefCounted
|
||||||
|
|
||||||
class_name SongObject
|
class_name SongObject
|
||||||
|
|
||||||
@@ -8,7 +8,8 @@ var song_title: String
|
|||||||
|
|
||||||
var soundtrack_title: String
|
var soundtrack_title: String
|
||||||
|
|
||||||
var players_given_point: Array[int] = []
|
## Ids of the players who got a point for this song.
|
||||||
|
var players_given_point: Array[String] = []
|
||||||
|
|
||||||
var is_answered: bool = false
|
var is_answered: bool = false
|
||||||
|
|
||||||
@@ -40,16 +41,14 @@ func get_song_info() -> String:
|
|||||||
else:
|
else:
|
||||||
return "??? - ???"
|
return "??? - ???"
|
||||||
|
|
||||||
func add_point(id: int) -> void:
|
func add_point(player_id: String) -> void:
|
||||||
print("add_point")
|
print("add_point")
|
||||||
players_given_point.append(id)
|
if !players_given_point.has(player_id):
|
||||||
players_given_point.sort()
|
players_given_point.append(player_id)
|
||||||
|
|
||||||
func remove_point(id: int) -> void:
|
func remove_point(player_id: String) -> void:
|
||||||
print("remove_point")
|
print("remove_point")
|
||||||
if players_given_point.has(id):
|
players_given_point.erase(player_id)
|
||||||
players_given_point.remove_at(players_given_point.find(id))
|
|
||||||
players_given_point.sort()
|
|
||||||
|
|
||||||
func _to_string() -> String:
|
func _to_string() -> String:
|
||||||
var format_string: String = "song_number: %d | soundtrack_title: %s | song_title: %s | is_answered: %s | has_played: %s | is_playing: %s"
|
var format_string: String = "song_number: %d | soundtrack_title: %s | song_title: %s | is_answered: %s | has_played: %s | is_playing: %s"
|
||||||
|
|||||||
+1
-1
@@ -35,7 +35,7 @@ func set_character_name(character_name: String) -> void:
|
|||||||
character_image.expand_mode = TextureRect.EXPAND_FIT_WIDTH_PROPORTIONAL
|
character_image.expand_mode = TextureRect.EXPAND_FIT_WIDTH_PROPORTIONAL
|
||||||
character_image.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
character_image.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||||
character_image.texture = new_image
|
character_image.texture = new_image
|
||||||
Settings.make_request2("/character?name=" + character_name.uri_encode(), image_fetched, true)
|
MusicServerClient.fetch_character_image(character_name, image_fetched)
|
||||||
|
|
||||||
func _input(event: InputEvent) -> void:
|
func _input(event: InputEvent) -> void:
|
||||||
if self.visible == true && Settings.character_select_open == true:
|
if self.visible == true && Settings.character_select_open == true:
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
class_name HttpTransport
|
||||||
|
extends RefCounted
|
||||||
|
## Sends HTTP requests for [code]MusicServerClient[/code] using [HTTPRequest] nodes.
|
||||||
|
##
|
||||||
|
## Tests subclass this to answer requests without a network connection.
|
||||||
|
|
||||||
|
var _owner: Node
|
||||||
|
|
||||||
|
|
||||||
|
func _init(owner: Node) -> void:
|
||||||
|
_owner = owner
|
||||||
|
|
||||||
|
|
||||||
|
## Requests [param url] and calls [param on_complete] with
|
||||||
|
## [code](response_code: int, body: PackedByteArray)[/code]. Connection errors are
|
||||||
|
## reported with response code 0.
|
||||||
|
func request(url: String, method: int, on_complete: Callable) -> void:
|
||||||
|
var http_request: HTTPRequest = HTTPRequest.new()
|
||||||
|
_owner.add_child(http_request)
|
||||||
|
http_request.request_completed.connect(
|
||||||
|
func(
|
||||||
|
result: int,
|
||||||
|
response_code: int,
|
||||||
|
_headers: PackedStringArray,
|
||||||
|
body: PackedByteArray,
|
||||||
|
) -> void:
|
||||||
|
http_request.queue_free()
|
||||||
|
on_complete.call(response_code if result == HTTPRequest.RESULT_SUCCESS else 0, body)
|
||||||
|
)
|
||||||
|
var headers: PackedStringArray = []
|
||||||
|
if method == HTTPClient.METHOD_PUT:
|
||||||
|
headers.append("Content-Type: application/json")
|
||||||
|
var error: int = http_request.request(url, headers, method)
|
||||||
|
if error != OK:
|
||||||
|
http_request.queue_free()
|
||||||
|
push_error("Could not send request to %s (error %d)" % [url, error])
|
||||||
|
on_complete.call(0, PackedByteArray())
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://uinuvqrxeppl
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
extends Node
|
||||||
|
## Client for the MusicServer REST API.
|
||||||
|
##
|
||||||
|
## Registered as the [code]MusicServerClient[/code] autoload, so every script can call it
|
||||||
|
## directly, e.g. [code]MusicServerClient.fetch_song_list(on_done)[/code]. All HTTP traffic
|
||||||
|
## goes through [member transport]; tests replace it with a fake to answer requests
|
||||||
|
## without a running server.
|
||||||
|
|
||||||
|
## Sends the actual HTTP requests. Swap it out in tests.
|
||||||
|
var transport: HttpTransport
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
if transport == null:
|
||||||
|
transport = HttpTransport.new(self)
|
||||||
|
|
||||||
|
|
||||||
|
## Fetches the songs already in the server playlist, as an Array of
|
||||||
|
## [code]{SongNo, Soundtrack, Song}[/code] dictionaries.
|
||||||
|
func fetch_song_list(on_done: Callable) -> void:
|
||||||
|
get_json("/music/list", on_done)
|
||||||
|
|
||||||
|
|
||||||
|
## Downloads a random song as MP3 bytes. With [param low_played] the server prefers
|
||||||
|
## soundtracks that have been played the least.
|
||||||
|
func fetch_random_song(low_played: bool, on_done: Callable) -> void:
|
||||||
|
get_bytes("/music/rand/low" if low_played else "/music/rand", on_done)
|
||||||
|
|
||||||
|
|
||||||
|
## Adds the most recently fetched random song to the server playlist.
|
||||||
|
func add_to_queue(on_done: Callable) -> void:
|
||||||
|
send("/music/addQue", on_done)
|
||||||
|
|
||||||
|
|
||||||
|
## Fetches [code]{SongNo, Soundtrack, Song}[/code] for the most recently queued song.
|
||||||
|
func fetch_song_info(on_done: Callable) -> void:
|
||||||
|
get_json("/music/info", on_done)
|
||||||
|
|
||||||
|
|
||||||
|
## Downloads a song from the server playlist as MP3 bytes.
|
||||||
|
func fetch_song(song_no: int, on_done: Callable) -> void:
|
||||||
|
get_bytes("/music?song=" + str(song_no), on_done)
|
||||||
|
|
||||||
|
|
||||||
|
## Downloads the sound test song as MP3 bytes.
|
||||||
|
func fetch_sound_test_song(on_done: Callable) -> void:
|
||||||
|
get_bytes("/music/soundTest", on_done)
|
||||||
|
|
||||||
|
|
||||||
|
## Clears the server playlist.
|
||||||
|
func reset_playlist(on_done: Callable) -> void:
|
||||||
|
send("/music/reset", on_done)
|
||||||
|
|
||||||
|
|
||||||
|
## Fetches every soundtrack name as an Array of Strings.
|
||||||
|
func fetch_all_soundtracks(on_done: Callable) -> void:
|
||||||
|
get_json("/music/all", on_done)
|
||||||
|
|
||||||
|
|
||||||
|
## Fetches every soundtrack name, sorted, as an Array of Strings.
|
||||||
|
func fetch_all_soundtracks_ordered(on_done: Callable) -> void:
|
||||||
|
get_json("/music/all/order", on_done)
|
||||||
|
|
||||||
|
|
||||||
|
## Records in the server statistics that a song has been played.
|
||||||
|
func mark_song_played(song_no: int) -> void:
|
||||||
|
send("/music/played?song=" + str(song_no), Callable(), HTTPClient.METHOD_PUT)
|
||||||
|
|
||||||
|
|
||||||
|
## Fetches the names of all character images.
|
||||||
|
func fetch_character_list(on_done: Callable) -> void:
|
||||||
|
get_json("/characters", on_done)
|
||||||
|
|
||||||
|
|
||||||
|
## Downloads a character image as PNG bytes.
|
||||||
|
func fetch_character_image(character_name: String, on_done: Callable) -> void:
|
||||||
|
get_bytes("/character?name=" + character_name.uri_encode(), on_done)
|
||||||
|
|
||||||
|
|
||||||
|
## Starts syncing the server's soundtrack library with its music folder.
|
||||||
|
func start_sync(on_done: Callable) -> void:
|
||||||
|
send("/sync", on_done)
|
||||||
|
|
||||||
|
|
||||||
|
## Fetches the sync state: [code]{progress, time_spent}[/code] while running, or the
|
||||||
|
## sync result once finished.
|
||||||
|
func fetch_sync_progress(on_done: Callable) -> void:
|
||||||
|
get_json("/sync/progress", on_done)
|
||||||
|
|
||||||
|
|
||||||
|
## Requests [param path] and calls [param on_done] with the parsed JSON.
|
||||||
|
## Nothing is called if the request fails or the body is not valid JSON.
|
||||||
|
func get_json(path: String, on_done: Callable) -> void:
|
||||||
|
_request(path, HTTPClient.METHOD_GET, func(body: PackedByteArray) -> void:
|
||||||
|
var json: JSON = JSON.new()
|
||||||
|
if json.parse(body.get_string_from_utf8()) != OK:
|
||||||
|
push_warning("Invalid JSON from %s: %s" % [path, json.get_error_message()])
|
||||||
|
return
|
||||||
|
on_done.call(json.data)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
## Requests [param path] and calls [param on_done] with the raw response body.
|
||||||
|
func get_bytes(path: String, on_done: Callable) -> void:
|
||||||
|
_request(path, HTTPClient.METHOD_GET, on_done)
|
||||||
|
|
||||||
|
|
||||||
|
## Requests [param path] and calls [param on_done] with no arguments when it succeeds.
|
||||||
|
## [param on_done] may be an empty Callable when the result does not matter.
|
||||||
|
func send(path: String, on_done: Callable, method: int = HTTPClient.METHOD_GET) -> void:
|
||||||
|
_request(path, method, func(_body: PackedByteArray) -> void:
|
||||||
|
if on_done.is_valid():
|
||||||
|
on_done.call()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func _request(path: String, method: int, on_success: Callable) -> void:
|
||||||
|
var url: String = Settings.default_path + path
|
||||||
|
transport.request(url, method, func(response_code: int, body: PackedByteArray) -> void:
|
||||||
|
if response_code != 200:
|
||||||
|
push_warning("Request to %s failed with response code %d" % [url, response_code])
|
||||||
|
return
|
||||||
|
on_success.call(body)
|
||||||
|
)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cbb0fpkj7k38w
|
||||||
@@ -45,7 +45,7 @@ func load_characters() -> void:
|
|||||||
character_box.size = Vector2(235, 145)
|
character_box.size = Vector2(235, 145)
|
||||||
character_box.set_character_name(character_name)
|
character_box.set_character_name(character_name)
|
||||||
character_box.connect("new_character_selected", _on_character_selected)
|
character_box.connect("new_character_selected", _on_character_selected)
|
||||||
Settings.make_request2("/characters", fetch_character_list, true)
|
MusicServerClient.fetch_character_list(fetch_character_list)
|
||||||
|
|
||||||
func show_grid(player_name: String) -> void:
|
func show_grid(player_name: String) -> void:
|
||||||
print("show_grid")
|
print("show_grid")
|
||||||
|
|||||||
+7
-6
@@ -40,7 +40,7 @@ func song_is_answered(song_no: int = currently_playing_song) -> void:
|
|||||||
song_object_array[song_no].is_answered = true
|
song_object_array[song_no].is_answered = true
|
||||||
if Settings.add_to_stats:
|
if Settings.add_to_stats:
|
||||||
print("add to stats: ", song_no)
|
print("add to stats: ", song_no)
|
||||||
Settings.make_put_request("/music/played?song="+str(song_no))
|
MusicServerClient.mark_song_played(song_no)
|
||||||
|
|
||||||
func add_to_playlist(new_song_object: SongObject) -> void:
|
func add_to_playlist(new_song_object: SongObject) -> void:
|
||||||
song_object_array.append(new_song_object)
|
song_object_array.append(new_song_object)
|
||||||
@@ -76,15 +76,16 @@ func get_current_soundtrack_title() -> String:
|
|||||||
func get_current_song_title() -> String:
|
func get_current_song_title() -> String:
|
||||||
return song_object_array[currently_playing_song].get_song_title()
|
return song_object_array[currently_playing_song].get_song_title()
|
||||||
|
|
||||||
func add_point(player_id: int) -> void:
|
func add_point(player_id: String) -> void:
|
||||||
song_object_array[currently_playing_song].add_point(player_id)
|
song_object_array[currently_playing_song].add_point(player_id)
|
||||||
|
|
||||||
func remove_point(player_id: int) -> void:
|
func remove_point(player_id: String) -> void:
|
||||||
song_object_array[currently_playing_song].remove_point(player_id)
|
song_object_array[currently_playing_song].remove_point(player_id)
|
||||||
|
|
||||||
func remove_player_from_list(player_to_remove: int) -> void:
|
## Removes a player's points from every song.
|
||||||
for song_list_object: SongObject in song_object_array:
|
func remove_player_from_list(player_id: String) -> void:
|
||||||
song_object_array[song_list_object.song_number].players_given_point.remove_at(song_object_array[song_list_object.song_number].players_given_point.find(player_to_remove))
|
for song_object: SongObject in song_object_array:
|
||||||
|
song_object.remove_point(player_id)
|
||||||
|
|
||||||
func get_song(song_no: int) -> AudioStream:
|
func get_song(song_no: int) -> AudioStream:
|
||||||
return song_object_array[song_no].song
|
return song_object_array[song_no].song
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ config/icon="res://icon.svg"
|
|||||||
|
|
||||||
Settings="*res://Settings.gd"
|
Settings="*res://Settings.gd"
|
||||||
Playlist="*res://playlist.gd"
|
Playlist="*res://playlist.gd"
|
||||||
|
MusicServerClient="*res://music_server_client.gd"
|
||||||
|
|
||||||
[debug]
|
[debug]
|
||||||
|
|
||||||
|
|||||||
+9
-9
@@ -39,12 +39,12 @@ func set_label() -> void:
|
|||||||
func update_players() -> void:
|
func update_players() -> void:
|
||||||
Settings.delete_children(song_list_players)
|
Settings.delete_children(song_list_players)
|
||||||
if song_object != null:
|
if song_object != null:
|
||||||
for player_id: int in song_object.players_given_point:
|
# Show players in the same order as the player list
|
||||||
for player: PlayerObject in Settings.player_array:
|
for player: PlayerObject in Settings.player_array:
|
||||||
if player.id == player_id:
|
if song_object.players_given_point.has(player.id):
|
||||||
var texture: TextureRect = TextureRect.new()
|
var texture: TextureRect = TextureRect.new()
|
||||||
texture.texture = player.character
|
texture.texture = player.character
|
||||||
texture.expand_mode = TextureRect.EXPAND_FIT_WIDTH_PROPORTIONAL
|
texture.expand_mode = TextureRect.EXPAND_FIT_WIDTH_PROPORTIONAL
|
||||||
texture.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
texture.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||||
texture.custom_minimum_size = Vector2(50, 25)
|
texture.custom_minimum_size = Vector2(50, 25)
|
||||||
song_list_players.add_child(texture)
|
song_list_players.add_child(texture)
|
||||||
+2
-2
@@ -105,7 +105,7 @@ func start_sync() -> void:
|
|||||||
sync_started.emit()
|
sync_started.emit()
|
||||||
show_sync_progress()
|
show_sync_progress()
|
||||||
if !Settings.currently_syncing:
|
if !Settings.currently_syncing:
|
||||||
Settings.make_request2("/sync", sync_request_sent, false)
|
MusicServerClient.start_sync(sync_request_sent)
|
||||||
|
|
||||||
func _on_sync_timeout() -> void:
|
func _on_sync_timeout() -> void:
|
||||||
print("_on_sync_timeout!")
|
print("_on_sync_timeout!")
|
||||||
@@ -118,7 +118,7 @@ func _on_sync_timeout() -> void:
|
|||||||
sync_time.text = data_received.time_spent if data_received.has("time_spent") else ""
|
sync_time.text = data_received.time_spent if data_received.has("time_spent") else ""
|
||||||
else:
|
else:
|
||||||
on_sync_finished(data_received)
|
on_sync_finished(data_received)
|
||||||
Settings.make_request2("/sync/progress", get_progress, true)
|
MusicServerClient.fetch_sync_progress(get_progress)
|
||||||
|
|
||||||
func on_sync_finished(data_received: Dictionary) -> void:
|
func on_sync_finished(data_received: Dictionary) -> void:
|
||||||
has_synced = true
|
has_synced = true
|
||||||
|
|||||||
+2
-3
@@ -17,10 +17,9 @@ func _ready() -> void:
|
|||||||
visible = false
|
visible = false
|
||||||
|
|
||||||
|
|
||||||
func show_winner(winning_player_id: int) -> void:
|
func show_winner(winner: PlayerObject) -> void:
|
||||||
visible = true
|
visible = true
|
||||||
# Set winner info
|
# Set winner info
|
||||||
var winner: PlayerObject = Settings.player_array[winning_player_id]
|
|
||||||
winner_label.text = winner.player_name + " won with " + str(winner.player_score) + \
|
winner_label.text = winner.player_name + " won with " + str(winner.player_score) + \
|
||||||
" points!!"
|
" points!!"
|
||||||
winner_picture.texture = winner.character
|
winner_picture.texture = winner.character
|
||||||
@@ -41,7 +40,7 @@ func show_winner(winning_player_id: int) -> void:
|
|||||||
|
|
||||||
var placing: int = 2
|
var placing: int = 2
|
||||||
for player: PlayerObject in sorted_players:
|
for player: PlayerObject in sorted_players:
|
||||||
if player.id == winning_player_id:
|
if player == winner:
|
||||||
continue # Skip the winner, already shown above
|
continue # Skip the winner, already shown above
|
||||||
var label: Label = Label.new()
|
var label: Label = Label.new()
|
||||||
label.text = str(placing) + ". " + player.player_name + " - " + \
|
label.text = str(placing) + ". " + player.player_name + " - " + \
|
||||||
|
|||||||
Reference in new issue
Block a user