Skip to content

Commit

Permalink
Highscores, joystick scrolling, play count tracking, OnlineLibrary fe…
Browse files Browse the repository at this point in the history
…atures (#18)

* Adds joystick scolling

* Fixes UIRayCast offset issue when switching from hand tracking

* Fixes relative scrolling bug I introduced

* Hides track while pause menu is displayed

* Added features to Online_library_Panel

* Scroll to load new pages
* Search by song uploader

* Adds ignore for non-demo songs

* Creates HighscoreTable

* Creates HighscorePanel

* Adds export to hide close button on HighscorePanel

* Adds HighscorePanel to game and populates when map is selected

* Allows user to submit highscore after song

* Makes keyboard text input gain focus on visible change

* Adds NameSelector to game

* Adds get_all_player_names() method to HighscoreTable

* NameSelector is usable in game

* Adds play count tracking

* Adds button style to theme

* Hides song info on highscore panel

* Removes old mainmenu

* Themes only NameSelector. Adds record/count removal.

* Adds playlist selector to main menu

* Connects keyboard enter signal so highscore gets submitted

* Names the two keyboard nodes better so we can distinguish them

* Saves highscores on each addition rather than tree exit signal

* Clean up GameState TODO. Documents desired behavior in the future.
  • Loading branch information
hankedan000 authored Jun 11, 2021
1 parent c1c0813 commit 52c7ed2
Show file tree
Hide file tree
Showing 27 changed files with 1,731 additions and 418 deletions.
2 changes: 1 addition & 1 deletion OQ_Toolkit/OQ_ARVRController/scripts/Feature_UIRayCast.gd
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func _set_raycast_transform():
else:
ui_raycast_position.transform.basis = Basis(Vector3(deg2rad(-90),0,0));
else:
ui_raycast_position.transform.basis = Basis();
ui_raycast_position.transform = Transform();

# center the ray cast better to the actual controller position
if (adjust_left_right):
Expand Down
5 changes: 1 addition & 4 deletions OQ_Toolkit/OQ_UI2D/OQ_UI2DKeyboard.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,11 @@
script = ExtResource( 3 )

[node name="OQ_UI2DCanvas_Keyboard" parent="." instance=ExtResource( 1 )]
editor_live_update = false
transparent = false

[node name="VirtualKeyboard" parent="OQ_UI2DCanvas_Keyboard" instance=ExtResource( 2 )]

[node name="OQ_UI2DCanvas_TextInput" parent="." instance=ExtResource( 1 )]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.2, 0 )
editor_live_update = false
transparent = false

[node name="TextEdit" type="TextEdit" parent="OQ_UI2DCanvas_TextInput"]
margin_right = 512.0
Expand All @@ -26,3 +22,4 @@ theme = ExtResource( 4 )
__meta__ = {
"_edit_use_anchors_": false
}
[connection signal="visibility_changed" from="." to="." method="_on_OQ_UI2DKeyboard_visibility_changed"]
11 changes: 9 additions & 2 deletions OQ_Toolkit/OQ_UI2D/scripts/OQ_UI2DKeyboard.gd
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
extends Spatial

export var show_text_input := true;
# if 'show_text_input' is enabled and this flag is set ture, then
# the text input box will aquire focus when then keyboard gains visibilty
export var focus_on_visible := true;

var _text_edit : TextEdit = null;
var _keyboard = null;

signal text_input_cancel;
signal text_input_enter;
signal text_input_cancel();
signal text_input_enter(text);


func _on_cancel():
Expand All @@ -32,3 +35,7 @@ func _ready():
_text_edit.grab_focus();
else:
$OQ_UI2DCanvas_TextInput.visible = false; # ?? maybe delte the node if not used

func _on_OQ_UI2DKeyboard_visibility_changed():
if visible and show_text_input and focus_on_visible:
_text_edit.grab_focus()
150 changes: 122 additions & 28 deletions game/BeepSaberMainMenu.gd
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,29 @@
# normal Beat Saber uses. So you can load here custom beat saber songs too
extends Panel

# emitted when a new map is selected
signal map_changed(map_info);
# emitted when a new map difficulty is selected
signal difficulty_changed(map_info,diff_name,diff_rank);
# emitted when the settings button is pressed
signal settings_requested()

# we need the main game class here to trigger game start/restart/continue
var _beepsaber = null;

onready var playlist_selector := $PlaylistSelector

enum PlaylistOptions {
AllSongs,
RecentlyAdded,
MostPlayed
}
const PLAYLIST_ITEMS = {
PlaylistOptions.AllSongs : "All Songs",
PlaylistOptions.RecentlyAdded : "Recently Added",
PlaylistOptions.MostPlayed : "Most Played"
}

func initialize(beepsaber_game):
_beepsaber = beepsaber_game;

Expand All @@ -28,6 +48,15 @@ export(NodePath) var keyboard;

var _playlists

# [{id:<song_dir_name>, source:<path_to_song?>},...]
var _all_songs = []
var _recently_added_songs = []# newest is first, oldest is last
var _most_played_songs = []# most played is first, least played is last

func refresh_playlist():
var id = playlist_selector.get_selected_id()
_on_PlaylistSelector_item_selected(id)

func _load_playlists():

_playlists = [];
Expand Down Expand Up @@ -56,20 +85,46 @@ func _load_playlists():
copy_file_name = copy.get_next();
file_name = dir.get_next();

_autogen_playlists(bspath+"Songs/", "BeepSaber/Songs/");
_all_songs = _discover_all_songs(bspath+"Songs/")
var songs_with_modify_times = []
var songs_with_play_count = []
for song in _all_songs:
var song_path = _song_path(song)
var song_info = _load_song_info(song_path)
var modified_time = file.get_modified_time(song_path)
var play_count = PlayCount.get_total_play_count(song_info)
songs_with_modify_times.append([modified_time,song])
songs_with_play_count.append([play_count,song])

if (!_playlists):
vr.log_error("No songs found in " + bspath);
$SongsMenu.clear()
return false;

if (_playlists.size() == 0):
_set_cur_playlist([])
else:
_set_cur_playlist(_playlists[0])
var tuple_compare = TupleCompare.new(0,false)
songs_with_modify_times.sort_custom(tuple_compare,"compare")
songs_with_play_count.sort_custom(tuple_compare,"compare")
_recently_added_songs = []
_most_played_songs = []
for tuple in songs_with_modify_times:
_recently_added_songs.append(tuple[1])
for tuple in songs_with_play_count:
_most_played_songs.append(tuple[1])

refresh_playlist()

# compare two tuples
# this is used to sort songs by most recently downloaded, most player, etc
class TupleCompare:
var idx = 0
var ascending = true

func _init(idx,ascending=true):
self.idx = idx
self.ascending = ascending

func compare(a,b):
if ascending:
return a[idx] < b[idx]
else:
return a[idx] > b[idx]

func _autogen_playlists(seek_path,name):
func _discover_all_songs(seek_path):
var songlist = [];
var dir = Directory.new();
var err = dir.open(seek_path);
Expand All @@ -87,26 +142,32 @@ func _autogen_playlists(seek_path,name):
else:
_autogen_playlists(new_dir,file_name);
file_name = dir.get_next();
if songlist:
_playlists.append({"Name":name,"Description":"Autogenerated","Songs":songlist});
return songlist

func _autogen_playlists(seek_path,name):
var all_songs = _discover_all_songs(seek_path)
_playlists.append({"Name":name,"Description":"Autogenerated","Songs":all_songs});

func _set_cur_playlist(pl):
func _set_cur_playlist(songs):
var current_id = $SongsMenu.get_selected_items()

$SongsMenu.clear()

if pl.has("Songs"):
for dat in pl["Songs"]:
_wire_song_dat(dat);
var song_count = songs.size()
for dat in songs:
_wire_song_dat(dat);

#whait a frame between every cover load to prevent frezzing
# wait a frame between every cover load to prevent freezing
yield(get_tree(),"idle_frame")
for b in range(0,$SongsMenu.get_item_count()):
$SongsMenu.set_item_icon(b,_load_cover(_song_path($SongsMenu.get_item_metadata(b)["id"]), $SongsMenu.get_item_metadata(b)["info"]._coverImageFilename))
yield(get_tree(),"idle_frame")

if current_id.size() > 0:
_select_song(current_id[0])
var selected_id = current_id[0]
if selected_id >= song_count:
selected_id = song_count - 1
_select_song(selected_id)

var default_song_icon = preload("res://game/data/beepsaber_logo.png")
func _wire_song_dat(dat):
Expand Down Expand Up @@ -175,9 +236,15 @@ func _select_song(id):
_map_path = _song_path(id);
$Delete_Button.disabled = false;
_map_info = _load_song_info(_map_path);

# notify listeners that map changed
emit_signal("map_changed",_map_info)

var play_count = PlayCount.get_total_play_count(_map_info)
$SongInfo_Label.text = """Song Author: %s
Song Title: %s
Beatmap Author: %s""" %[_map_info._songAuthorName, _map_info._songName, _map_info._levelAuthorName]
Beatmap Author: %s
Play Count: %d""" %[_map_info._songAuthorName, _map_info._songName, _map_info._levelAuthorName,play_count]

$cover.texture = _load_cover(_song_path(id), _map_info._coverImageFilename);

Expand Down Expand Up @@ -235,6 +302,14 @@ func _select_difficulty(id):
_map_difficulty = item_meta["id"]
_map_difficulty_name = item_meta["Name"]
$DifficultyMenu.select(id)

# notify listeners that difficulty has changed
var difficulty = _map_info._difficultyBeatmapSets[0]._difficultyBeatmaps[id]
emit_signal(
"difficulty_changed",
_map_info,
difficulty._difficulty,
difficulty._difficultyRank)


func _load_map_and_start():
Expand Down Expand Up @@ -269,6 +344,10 @@ func _on_Delete_Button_button_up():
_delete_map();

func _delete_map():
if _map_info:
Highscores.remove_map(_map_info)
PlayCount.remove_map(_map_info)

if _map_path:
var dir = Directory.new();
if dir.open(_map_path) == 0:
Expand All @@ -285,21 +364,26 @@ func _delete_map():
vr.log_info("Error removing song "+_map_path);
_on_LoadPlaylists_Button_pressed()


func _ready():
if OS.get_name() != "Android":
bspath = dlpath+"BeepSaber/";
vr.log_info("BeepSaber search path is " + bspath);

playlist_selector.clear()
for option in PLAYLIST_ITEMS.keys():
playlist_selector.add_item(PLAYLIST_ITEMS[option],option)

keyboard = get_node(keyboard);
keyboard.connect("text_input_enter",self,"_text_input_enter")
keyboard.connect("text_input_cancel",self,"_text_input_cancel")
if keyboard:
keyboard.connect("text_input_enter",self,"_text_input_enter")
keyboard.connect("text_input_cancel",self,"_text_input_cancel")

_load_playlists();

yield(get_tree(),"physics_frame")
keyboard._text_edit.connect("text_changed",self,"_text_input_changed")
keyboard._text_edit.connect("focus_exited",self,"_text_input_enter")
if keyboard:
keyboard._text_edit.connect("text_changed",self,"_text_input_changed")
keyboard._text_edit.connect("focus_exited",self,"_text_input_enter")


func _on_Play_Button_pressed():
Expand All @@ -321,6 +405,8 @@ func _on_Continue_Button_pressed():
func _on_Stop_Button_pressed():
set_mode_game_start();

func _on_Settings_Button_pressed():
emit_signal("settings_requested")

const READ_PERMISSION = "android.permission.READ_EXTERNAL_STORAGE"

Expand Down Expand Up @@ -387,7 +473,15 @@ func _text_input_changed():
func _clean_search():
$SongsMenu.sort_items_by_text()
$Search_Button/Label.text = ""




func _on_PlaylistSelector_item_selected(id):
match id:
PlaylistOptions.AllSongs:
_set_cur_playlist(_all_songs)
PlaylistOptions.MostPlayed:
_set_cur_playlist(_most_played_songs)
PlaylistOptions.RecentlyAdded:
_set_cur_playlist(_recently_added_songs)
_:
vr.log_warning("Unsupported playlist option %s" % id)
_set_cur_playlist(_all_songs)
Loading

0 comments on commit 52c7ed2

Please sign in to comment.