aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-09-15 23:46:37 +0200
committermetamuffin <metamuffin@disroot.org>2025-09-15 23:46:37 +0200
commitebb5c295c03cb1689c081006ad2ee167bd355d0a (patch)
tree1d62a388a97bfb09e5a01b565b2bae53acd966ce
parent0b780e2271e63f10a2580afe9507d18d735527f8 (diff)
downloadhurrycurry-ebb5c295c03cb1689c081006ad2ee167bd355d0a.tar
hurrycurry-ebb5c295c03cb1689c081006ad2ee167bd355d0a.tar.bz2
hurrycurry-ebb5c295c03cb1689c081006ad2ee167bd355d0a.tar.zst
move profile related functions to static Profile members
-rw-r--r--client/game.gd10
-rw-r--r--client/global.gd88
-rw-r--r--client/gui/components/message/item/item_message.gd2
-rw-r--r--client/gui/menus/character.gd14
-rw-r--r--client/gui/menus/main/play.gd12
-rw-r--r--client/gui/menus/setup/setup.gd8
-rw-r--r--client/gui/overlays/popup_message/popup_message.gd34
-rw-r--r--client/profile.gd91
-rw-r--r--client/profile.gd.uid1
-rw-r--r--client/settings.gd9
10 files changed, 140 insertions, 129 deletions
diff --git a/client/game.gd b/client/game.gd
index 76308349..a8f905fb 100644
--- a/client/game.gd
+++ b/client/game.gd
@@ -234,7 +234,7 @@ func handle_packet(p):
if (player.is_customer
and not Settings.read("gameplay.tutorial_disabled")
and join_state == JoinState.JOINED):
- var completed_ingredients: Array = Global.get_profile("tutorial_ingredients_played")
+ var completed_ingredients: Array = Profile.read("tutorial_ingredients_played")
var completed := Global.array_has_all(completed_ingredients, ingredients)
if not completed:
@@ -301,11 +301,11 @@ func handle_packet(p):
if p.success:
var completed_item := ItemFactory.ParsedItem.new(item_names[p.item])
- var played: Array = Global.get_profile("tutorial_ingredients_played")
+ var played: Array = Profile.read("tutorial_ingredients_played")
played.append(completed_item.name)
played.append_array(completed_item.contents)
- Global.set_profile("tutorial_ingredients_played", played)
- Global.save_profile()
+ Profile.write("tutorial_ingredients_played", played)
+ Profile.save()
while item_names[p.item] in tutorial_queue:
tutorial_queue.erase(item_names[p.item])
@@ -372,7 +372,7 @@ func toggle_join():
match join_state:
JoinState.SPECTATING:
set_join_state(JoinState.WAITING)
- mp.send_join(Global.get_profile("username"), Global.get_profile("character_style"))
+ mp.send_join(Profile.read("username"), Profile.read("character_style"))
JoinState.WAITING:
push_error("Join/Leave action already toggled.")
JoinState.JOINED:
diff --git a/client/global.gd b/client/global.gd
index c7ee555e..d9d714aa 100644
--- a/client/global.gd
+++ b/client/global.gd
@@ -24,37 +24,9 @@ signal using_touch_change(using: bool)
@warning_ignore("UNUSED_SIGNAL")
signal hand_count_change(count: bool)
-var default_profile := {
- "username": "",
- "character_style": {
- "color": 0,
- "headwear": 0,
- "hairstyle": 0
- },
- "last_server_url": "",
- "tutorial_ingredients_played": [],
- "registry_asked": false,
- "hints": {
- "has_moved": false,
- "has_boosted": false,
- "has_interacted": false,
- "has_rotated": false,
- "has_reset": false,
- "has_zoomed": false,
- "has_seen_performance": false,
- "has_seen_join_while_running": false
- }
-}
-
var using_joypad := false
var using_touch := false
-# profile and settings are stored in a Dictionary[String, Any]
-var profile: Dictionary
-var settings: Dictionary
-
-var settings_tree: GameSetting
-
var game_paused := false
var hand_count := 0
@@ -68,7 +40,7 @@ var focused_node: Control
var focused_menu: Menu # only use this as a last resort, currently exists to open setup menu from settings
func _ready():
- profile = load_dict("user://profile", default_profile)
+ Profile.load("user://profile")
Settings.load("user://settings.json")
get_viewport().gui_focus_changed.connect(Sound.play_hover_maybe)
get_viewport().gui_focus_changed.connect(func(node): focused_node = node)
@@ -105,27 +77,6 @@ func _input(event):
using_touch = false
using_touch_change.emit(using_touch)
-func save_profile():
- save_dict("user://profile", profile)
-
-func save_dict(path: String, dict: Dictionary):
- var f = FileAccess.open(path, FileAccess.WRITE)
- var to_save = dict.duplicate(true)
- f.store_var(to_save, true)
-
-func load_dict(path: String, default: Dictionary) -> Dictionary:
- # TOCTOU here. Godot docs says its fine.
- if not FileAccess.file_exists(path):
- print("Skip profile load")
- return default
- var f = FileAccess.open(path, FileAccess.READ)
- var saved_dict = f.get_var(true)
-
- if saved_dict != null and saved_dict is Dictionary:
- add_missing_keys(saved_dict, default)
-
- return saved_dict
-
func on_mobile() -> bool:
var os_name := OS.get_name()
return os_name == "Android" or os_name == "iOS"
@@ -138,37 +89,6 @@ func on_high_end() -> bool:
func on_vulkan() -> bool:
return ProjectSettings.get_setting("rendering/rendering_device/driver") == "vulkan"
-func get_profile(key: String):
- if profile.has(key):
- return profile[key]
- else:
- push_error("Tried to access profile setting \"%s\", which does not exist (missing key)" % key)
- return null
-
-func set_profile(key: String, value):
- if !profile.has(key):
- push_error("Tried to set profile setting \"%s\", which does not yet exist (missing key)" % key)
- return
- if profile[key] != value:
- profile[key] = value
-
-func set_hint(key: String, value: bool):
- if !profile["hints"].has(key):
- push_error("Tried to set hint \"%s\", which does not yet exist (missing key)" % key)
- if profile["hints"][key] != value:
- if value:
- Settings.write("gameplay.hints_started", true)
- Settings.save()
- profile["hints"][key] = value
- save_profile() # TODO avoid this call when bulk-unsetting hints
-
-func get_hint(key: String):
- if profile["hints"].has(key):
- return profile["hints"][key]
- else:
- push_error("Tried to access hint \"%s\", which does not exist (missing key)" % key)
- return null
-
static func interpolate(current, target, dt):
return target + (current - target) * exp(-dt)
@@ -206,7 +126,7 @@ func language_list():
func array_eq(a, b):
return a.all(func(e): return a.count(e) == b.count(e))
-func add_missing_keys(dict: Dictionary, reference: Dictionary):
+static func add_missing_keys(dict: Dictionary, reference: Dictionary):
for k in reference.keys():
if !dict.has(k) or typeof(dict[k]) != typeof(reference[k]):
dict[k] = reference[k]
@@ -220,8 +140,8 @@ func array_has_all(parent: Array, children: Array) -> bool:
return false
return true
-func configure_viewport_aa(vp: Viewport, aa: String) -> void:
- match aa:
+func configure_viewport_aa(vp: Viewport) -> void:
+ match Settings.read("graphics.aa"):
"disabled":
vp.msaa_3d = Viewport.MSAA_DISABLED
vp.screen_space_aa = Viewport.SCREEN_SPACE_AA_DISABLED
diff --git a/client/gui/components/message/item/item_message.gd b/client/gui/components/message/item/item_message.gd
index 4079e363..f5a97723 100644
--- a/client/gui/components/message/item/item_message.gd
+++ b/client/gui/components/message/item/item_message.gd
@@ -31,7 +31,7 @@ var timeout_initial := 0.
@onready var v_box_container: VBoxContainer = $VBoxContainer
func _ready() -> void:
- Global.configure_viewport_aa(sub_viewport, Settings.read("graphics.aa"))
+ Global.configure_viewport_aa(sub_viewport)
if enable_grayscale:
sub_viewport_container.material = PRINTED_MAT
diff --git a/client/gui/menus/character.gd b/client/gui/menus/character.gd
index 3c1230ae..715a7b1f 100644
--- a/client/gui/menus/character.gd
+++ b/client/gui/menus/character.gd
@@ -22,8 +22,8 @@ extends Menu
func _ready():
super()
- $VBoxContainer/top_panel/a/username.text = Global.get_profile("username")
- character.set_style(Global.get_profile("character_style"), "chef")
+ $VBoxContainer/top_panel/a/username.text = Profile.read("username")
+ character.set_style(Profile.read("character_style"), "chef")
init_map()
func init_map():
@@ -61,8 +61,8 @@ func exit():
popup_data.buttons = [accept_button]
await submenu("res://gui/menus/popup.tscn", popup_data)
return
- Global.set_profile("username", username_edit.text)
- Global.save_profile()
+ Profile.write("username", username_edit.text)
+ Profile.save()
super()
func _on_character_back_pressed():
@@ -90,7 +90,7 @@ func _on_hairstyle_forward_pressed() -> void:
current_style.hairstyle = G.rem_euclid(current_style.hairstyle + 1, character.hairstyles.size()))
func modify_style(modifier: Callable):
- var current_style: Dictionary = Global.get_profile("character_style")
+ var current_style: Dictionary = Profile.read("character_style")
modifier.call(current_style)
- Global.set_profile("character_style", current_style)
- character.set_style(Global.get_profile("character_style"), "chef")
+ Profile.write("character_style", current_style)
+ character.set_style(Profile.read("character_style"), "chef")
diff --git a/client/gui/menus/main/play.gd b/client/gui/menus/main/play.gd
index 87b0b5bf..1e64a02f 100644
--- a/client/gui/menus/main/play.gd
+++ b/client/gui/menus/main/play.gd
@@ -34,7 +34,7 @@ func _ready():
url_regex.compile("^(?:(ws|wss)://)?([^:]+)(?::([0-9]+))?$")
if OS.has_feature("web"):
server.hide()
- connect_uri.text = Global.get_profile("last_server_url")
+ connect_uri.text = Profile.read("last_server_url")
Sound.play_music("MainMenu")
ServerList.update_server_list.connect(update_server_list)
@@ -43,7 +43,7 @@ func _ready():
update_server_list_loading(ServerList.loading)
super()
- if not Global.get_profile("registry_asked"):
+ if not Profile.read("registry_asked"):
var popup_data := MenuPopup.Data.new()
popup_data.text = tr("c.menu.play.allow_query_registry").format([Settings.read("online.registry_url")])
var allow_button := Button.new()
@@ -54,8 +54,8 @@ func _ready():
deny_button.pressed.connect(func(): Settings.write("online.use_registry", false))
popup_data.buttons = [allow_button, deny_button]
await submenu("res://gui/menus/popup.tscn", popup_data)
- Global.set_profile("registry_asked", true)
- Global.save_profile()
+ Profile.write("registry_asked", true)
+ Profile.save()
Settings.save()
ServerList.start()
@@ -110,8 +110,8 @@ func _on_connect_pressed():
if result.get_string(3) == "" and result.get_string(1) != "wss":
url = url + ":27032"
connect_uri.text = url
- Global.set_profile("last_server_url", url)
- Global.save_profile()
+ Profile.write("last_server_url", url)
+ Profile.save()
connect_to(url)
func _on_quick_connect_pressed():
diff --git a/client/gui/menus/setup/setup.gd b/client/gui/menus/setup/setup.gd
index e4103603..878331ff 100644
--- a/client/gui/menus/setup/setup.gd
+++ b/client/gui/menus/setup/setup.gd
@@ -92,12 +92,12 @@ func _on_sign_pressed():
anim.play_backwards("paper_slide")
await anim.animation_finished
- Global.set_profile("username", username.text)
- Global.set_profile("character_style", character_style)
+ Profile.write("username", username.text)
+ Profile.write("character_style", character_style)
if skip_tutorial.button_pressed:
for k in Global.profile["hints"].keys():
- Global.set_hint(k, true)
- Global.save_profile()
+ Profile.set_hint(k, true)
+ Profile.save()
Settings.write("gameplay.hints_started", skip_tutorial.button_pressed)
Settings.write("gameplay.tutorial_disabled", skip_tutorial.button_pressed)
diff --git a/client/gui/overlays/popup_message/popup_message.gd b/client/gui/overlays/popup_message/popup_message.gd
index d577465b..6a3d8273 100644
--- a/client/gui/overlays/popup_message/popup_message.gd
+++ b/client/gui/overlays/popup_message/popup_message.gd
@@ -131,26 +131,26 @@ func stop_game_hints():
func _input(_event):
if Input.is_action_just_pressed("boost"):
- Global.set_hint("has_boosted", true)
+ Profile.set_hint("has_boosted", true)
if any_action_just_pressed(["forwards", "backwards", "left", "right"]):
- Global.set_hint("has_moved", true)
+ Profile.set_hint("has_moved", true)
if any_action_just_pressed(["rotate_left", "rotate_right", "rotate_up", "rotate_down"]):
- if not Global.get_hint("has_reset"):
+ if not Profile.get_hint("has_reset"):
reset_timer.start()
- Global.set_hint("has_rotated", true)
+ Profile.set_hint("has_rotated", true)
if any_action_just_pressed(["zoom_in", "zoom_out"]):
- Global.set_hint("has_zoomed", true)
+ Profile.set_hint("has_zoomed", true)
if Input.is_action_just_pressed("interact_left") or Input.is_action_just_pressed("interact_right"):
- Global.set_hint("has_interacted", true)
+ Profile.set_hint("has_interacted", true)
if Input.is_action_just_pressed("reset"):
- Global.set_hint("has_reset", true)
+ Profile.set_hint("has_reset", true)
func _on_boost_timeout():
- if not Global.get_hint("has_boosted") and not Global.using_touch:
+ if not Profile.get_hint("has_boosted") and not Global.using_touch:
display_hint_msg(tr("c.hint.boost").format([display_keybind("boost")]))
func _on_move_timeout():
- if not Global.get_hint("has_moved") and not Global.using_touch:
+ if not Profile.get_hint("has_moved") and not Global.using_touch:
display_hint_msg(tr("c.hint.movement").format([", ".join(
[
display_keybind("forwards"),
@@ -161,15 +161,15 @@ func _on_move_timeout():
)]))
func _on_interact_timeout():
- if not Global.get_hint("has_interacted") and not Global.using_touch:
+ if not Profile.get_hint("has_interacted") and not Global.using_touch:
display_hint_msg(tr("c.hint.interact").format([display_keybind("interact")]))
func _on_reset_timeout():
- if not Global.get_hint("has_reset") and not Global.using_touch:
+ if not Profile.get_hint("has_reset") and not Global.using_touch:
display_hint_msg(tr("c.hint.reset_camera").format([display_keybind("reset")]))
func _on_zoom_timeout():
- if not Global.get_hint("has_zoomed") and not Global.using_touch:
+ if not Profile.get_hint("has_zoomed") and not Global.using_touch:
display_hint_msg(tr("c.hint.zoom_camera").format([", ".join(
[
display_keybind("zoom_in"),
@@ -203,7 +203,7 @@ func any_action_just_pressed(actions: Array) -> bool:
return false
func _on_rotate_camera_timeout():
- if not Global.get_hint("has_rotated") and not Global.using_touch:
+ if not Profile.get_hint("has_rotated") and not Global.using_touch:
display_hint_msg(tr("c.hint.rotate").format([", ".join(
[
display_keybind("rotate_up"),
@@ -214,13 +214,13 @@ func _on_rotate_camera_timeout():
)]))
func _on_join_while_running_timeout():
- if not game.join_state == Game.JoinState.JOINED and not Global.get_hint("has_seen_join_while_running"):
- Global.set_hint("has_seen_join_while_running", true)
+ if not game.join_state == Game.JoinState.JOINED and not Profile.get_hint("has_seen_join_while_running"):
+ Profile.set_hint("has_seen_join_while_running", true)
display_hint_msg(tr("c.hint.join_while_running").format([display_keybind("menu")]))
func _on_performance_timeout() -> void:
- if not Global.get_hint("has_seen_performance") and Engine.get_frames_per_second() < DisplayServer.screen_get_refresh_rate() * 0.75:
- Global.set_hint("has_seen_performance", true)
+ if not Profile.get_hint("has_seen_performance") and Engine.get_frames_per_second() < DisplayServer.screen_get_refresh_rate() * 0.75:
+ Profile.set_hint("has_seen_performance", true)
display_hint_msg(tr("c.hint.framerate_low"))
class PositionalMessage:
diff --git a/client/profile.gd b/client/profile.gd
new file mode 100644
index 00000000..438e8e66
--- /dev/null
+++ b/client/profile.gd
@@ -0,0 +1,91 @@
+# Hurry Curry! - a game about cooking
+# Copyright (C) 2025 Hurry Curry! contributors
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, version 3 of the License only.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+extends Node
+class_name Profile
+
+static var default_profile := {
+ "username": "",
+ "character_style": {
+ "color": 0,
+ "headwear": 0,
+ "hairstyle": 0
+ },
+ "last_server_url": "",
+ "tutorial_ingredients_played": [],
+ "registry_asked": false,
+ "hints": {
+ "has_moved": false,
+ "has_boosted": false,
+ "has_interacted": false,
+ "has_rotated": false,
+ "has_reset": false,
+ "has_zoomed": false,
+ "has_seen_performance": false,
+ "has_seen_join_while_running": false
+ }
+}
+
+# profile is stored in a Dictionary[String, Any]
+static var values: Dictionary
+static var loaded_path: String
+
+static func load(path: String):
+ # TOCTOU here. Godot docs says its fine.
+ if not FileAccess.file_exists(path):
+ print("Skip profile load")
+ return default_profile
+ var f = FileAccess.open(path, FileAccess.READ)
+
+ values = f.get_var(true)
+ if values != null and values is Dictionary:
+ G.add_missing_keys(values, default_profile)
+ loaded_path = path
+
+static func save():
+ var f = FileAccess.open(loaded_path, FileAccess.WRITE)
+ var to_save = values.duplicate(true)
+ f.store_var(to_save, true)
+
+static func read(key: String):
+ if values.has(key):
+ return values[key]
+ else:
+ push_error("Tried to access profile setting \"%s\", which does not exist (missing key)" % key)
+ return null
+
+static func write(key: String, value):
+ if !values.has(key):
+ push_error("Tried to set profile setting \"%s\", which does not yet exist (missing key)" % key)
+ return
+ if values[key] != value:
+ values[key] = value
+
+static func set_hint(key: String, value: bool):
+ if !values["hints"].has(key):
+ push_error("Tried to set hint \"%s\", which does not yet exist (missing key)" % key)
+ if values["hints"][key] != value:
+ if value:
+ Settings.write("gameplay.hints_started", true)
+ Settings.save()
+ values["hints"][key] = value
+ save() # TODO avoid this call when bulk-unsetting hints
+
+static func get_hint(key: String):
+ if values["hints"].has(key):
+ return values["hints"][key]
+ else:
+ push_error("Tried to access hint \"%s\", which does not exist (missing key)" % key)
+ return null
diff --git a/client/profile.gd.uid b/client/profile.gd.uid
new file mode 100644
index 00000000..5cd63b28
--- /dev/null
+++ b/client/profile.gd.uid
@@ -0,0 +1 @@
+uid://1hlvx8wuxl2d
diff --git a/client/settings.gd b/client/settings.gd
index 8381ddc2..55a2b90e 100644
--- a/client/settings.gd
+++ b/client/settings.gd
@@ -134,7 +134,7 @@ static func hook_changed_init(key: String, display: bool, callable: Callable):
static func get_category_dict(prefix: String):
var map = {}
- for k in Global.settings.keys():
+ for k in values.keys():
var kn = k.trim_prefix(prefix + ".")
if kn == k: continue
map[kn] = read(k)
@@ -158,9 +158,8 @@ static var change_hooks_apply = {
"audio.sfx_volume": h_volume_sfx,
}
-static func h_aa(mode):
- var vp = Global.get_viewport()
- Global.configure_viewport_aa(vp, mode)
+static func h_aa(_mode):
+ Global.configure_viewport_aa(Global.get_viewport())
static func h_taa(enabled):
Global.get_viewport().use_taa = enabled
@@ -198,4 +197,4 @@ static func h_input():
static func h_hints_started(started: bool):
if not started:
for k in Global.profile["hints"].keys():
- Global.set_hint(k, false)
+ Profile.set_hint(k, false)