From f84f15b8ae0710f94cc835368e8a7af507ec7ed9 Mon Sep 17 00:00:00 2001 From: Emmanouil Papadeas <35376950+OverloadedOrama@users.noreply.github.com> Date: Mon, 22 Jul 2024 03:11:29 +0300 Subject: [PATCH] Experiment with Steam achievements, using a new SteamManager class This has no effect on non-Steam builds. Steam achievements are mostly for fun, but can also be educational because they can let users know of certain features and functionalities. It's using the GodotSteam GDExtension, but because I do not want to bloat the GitHub repository with things that are not needed for most builds, I decided not to include the GDExtension files, and instead check if the `Steam` class exists in `ClassDB`. The new SteamManager class pretty much does nothing on non-Steam builds, so do not worry about bloat. In the future we could even take advantage of more of Steam's features, such as Cloud storage for pxo files. --- .gitignore | 2 + src/Autoload/OpenSave.gd | 7 ++-- src/Classes/Drawers.gd | 1 + src/Classes/SteamManager.gd | 45 +++++++++++++++++++++ src/Main.tscn | 8 +++- src/Preferences/PreferencesDialog.gd | 1 + src/Tools/DesignTools/Eraser.gd | 1 + src/UI/TopMenuContainer/TopMenuContainer.gd | 2 + 8 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 src/Classes/SteamManager.gd diff --git a/.gitignore b/.gitignore index cf3bef523..c780db20f 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,5 @@ mono_crash.*.json # Android ignores android/ + +addons/godotsteam diff --git a/src/Autoload/OpenSave.gd b/src/Autoload/OpenSave.gd index 112038558..037fe503c 100644 --- a/src/Autoload/OpenSave.gd +++ b/src/Autoload/OpenSave.gd @@ -354,14 +354,14 @@ func open_v0_pxo_file(path: String, empty_project: bool) -> Project: func save_pxo_file( path: String, autosave: bool, include_blended := false, project := Global.current_project ) -> bool: - if !autosave: + if not autosave: project.name = path.get_file().trim_suffix(".pxo") var serialized_data := project.serialize() - if !serialized_data: + if not serialized_data: Global.popup_error(tr("File failed to save. Converting project data to dictionary failed.")) return false var to_save := JSON.stringify(serialized_data) - if !to_save: + if not to_save: Global.popup_error(tr("File failed to save. Converting dictionary to JSON failed.")) return false @@ -450,6 +450,7 @@ func save_pxo_file( Global.FileMenu.SAVE, tr("Save") + " %s" % path.get_file() ) project_saved.emit() + SteamManager.set_achievement("ACH_SAVE") save_project_to_recent_list(path) return true diff --git a/src/Classes/Drawers.gd b/src/Classes/Drawers.gd index 1989572e2..669ab0bd7 100644 --- a/src/Classes/Drawers.gd +++ b/src/Classes/Drawers.gd @@ -77,3 +77,4 @@ func set_pixel(image: Image, position: Vector2i, color: Color, ignore_mirroring var mirror_pos := mirrored_positions[i] if project.can_pixel_get_drawn(mirror_pos) && not Tools.check_alpha_lock(image, mirror_pos): drawers[i + 1].set_pixel(image, mirror_pos, color, color_op) + SteamManager.set_achievement("ACH_FIRST_PIXEL") diff --git a/src/Classes/SteamManager.gd b/src/Classes/SteamManager.gd new file mode 100644 index 000000000..5771897eb --- /dev/null +++ b/src/Classes/SteamManager.gd @@ -0,0 +1,45 @@ +class_name SteamManager +extends Node + +## A class that manages Steam-specific functionalities. Currently only unlocks achievements. +## On non-Steam builds, this node gets automatically freed. + +## The Steam app id of Pixelorama. +const APP_ID := 2779170 +## We are using a variable instead of the `Steam` singleton directly, +## because it is not available in non-Steam builds. +static var steam_class + + +func _init() -> void: + if not ClassDB.class_exists(&"Steam"): + queue_free() + return + steam_class = ClassDB.instantiate(&"Steam") + OS.set_environment("SteamAppID", str(APP_ID)) + OS.set_environment("SteamGameID", str(APP_ID)) + + +func _ready() -> void: + if not is_instance_valid(steam_class): + return + var response: Dictionary = steam_class.steamInitEx(true, APP_ID) + print(response) + if not steam_class.isSteamRunning(): + print("Steam is not running!") + return + #var id: int = steam_class.getSteamID() + #var username: String = steam_class.getFriendPersonaName(id) + + +## Unlocks an achievement on Steam based on its [param achievement_name]. +static func set_achievement(achievement_name: String) -> void: + if not is_instance_valid(steam_class): + return + if not steam_class.isSteamRunning(): + return + var status: Dictionary = steam_class.getAchievement(achievement_name) + if status["achieved"]: + return + steam_class.setAchievement(achievement_name) + steam_class.storeStats() diff --git a/src/Main.tscn b/src/Main.tscn index 41fbeca46..0ab12774d 100644 --- a/src/Main.tscn +++ b/src/Main.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=17 format=3 uid="uid://dbylw5k04ulp8"] +[gd_scene load_steps=18 format=3 uid="uid://dbylw5k04ulp8"] [ext_resource type="Theme" uid="uid://bkb4syj8110el" path="res://assets/themes/dark/theme.tres" id="1"] [ext_resource type="Script" path="res://src/Main.gd" id="2"] @@ -14,6 +14,7 @@ [ext_resource type="PackedScene" uid="uid://c0nuukjakmai2" path="res://src/UI/Dialogs/TileModeOffsetsDialog.tscn" id="14"] [ext_resource type="PackedScene" uid="uid://c6fyrnyt3663o" path="res://src/UI/Timeline/TagProperties.tscn" id="14_fw6cf"] [ext_resource type="Script" path="res://src/HandleExtensions.gd" id="15_v0k2h"] +[ext_resource type="Script" path="res://src/Classes/SteamManager.gd" id="17_k1xhp"] [ext_resource type="PackedScene" uid="uid://clbjfkdupw52l" path="res://src/UI/Timeline/CelProperties.tscn" id="17_ucs64"] [ext_resource type="PackedScene" uid="uid://clgu8wb5o6oup" path="res://src/UI/Dialogs/ExportDialog.tscn" id="39"] @@ -110,11 +111,14 @@ visible = false [node name="ImageRequest" type="HTTPRequest" parent="."] +[node name="SteamManager" type="Node" parent="."] +script = ExtResource("17_k1xhp") + [connection signal="files_selected" from="Dialogs/OpenSprite" to="." method="_on_OpenSprite_files_selected"] [connection signal="visibility_changed" from="Dialogs/OpenSprite" to="." method="_on_open_sprite_visibility_changed"] [connection signal="file_selected" from="Dialogs/SaveSprite" to="." method="_on_SaveSprite_file_selected"] -[connection signal="visibility_changed" from="Dialogs/SaveSprite" to="." method="_on_save_sprite_visibility_changed"] [connection signal="visibility_changed" from="Dialogs/SaveSprite" to="." method="_can_draw_true"] +[connection signal="visibility_changed" from="Dialogs/SaveSprite" to="." method="_on_save_sprite_visibility_changed"] [connection signal="confirmed" from="Dialogs/SaveSpriteHTML5" to="." method="save_project" binds= [""]] [connection signal="visibility_changed" from="Dialogs/SaveSpriteHTML5" to="." method="_can_draw_true"] [connection signal="visibility_changed" from="Dialogs/ExportDialog" to="." method="_can_draw_true"] diff --git a/src/Preferences/PreferencesDialog.gd b/src/Preferences/PreferencesDialog.gd index a2458d75c..827243408 100644 --- a/src/Preferences/PreferencesDialog.gd +++ b/src/Preferences/PreferencesDialog.gd @@ -328,6 +328,7 @@ func _ready() -> void: if typeof(value) == TYPE_VECTOR2 or typeof(value) == TYPE_COLOR: is_default = value.is_equal_approx(pref.default_value) disable_restore_default_button(restore_default_button, is_default) + SteamManager.set_achievement("ACH_PREFERENCES") func _on_Preference_value_changed(value, pref: Preference, button: RestoreDefaultButton) -> void: diff --git a/src/Tools/DesignTools/Eraser.gd b/src/Tools/DesignTools/Eraser.gd index e5870e8ab..754b1200a 100644 --- a/src/Tools/DesignTools/Eraser.gd +++ b/src/Tools/DesignTools/Eraser.gd @@ -106,6 +106,7 @@ func draw_end(pos: Vector2i) -> void: _draw_line = false commit_undo() + SteamManager.set_achievement("ACH_ERASE_PIXEL") cursor_text = "" update_random_image() diff --git a/src/UI/TopMenuContainer/TopMenuContainer.gd b/src/UI/TopMenuContainer/TopMenuContainer.gd index a45630c5d..bbfeae307 100644 --- a/src/UI/TopMenuContainer/TopMenuContainer.gd +++ b/src/UI/TopMenuContainer/TopMenuContainer.gd @@ -834,6 +834,7 @@ func help_menu_id_pressed(id: int) -> void: _popup_dialog(Global.control.splash_dialog) Global.HelpMenu.ONLINE_DOCS: OS.shell_open(DOCS_URL) + SteamManager.set_achievement("ACH_ONLINE_DOCS") Global.HelpMenu.ISSUE_TRACKER: OS.shell_open(ISSUES_URL) Global.HelpMenu.OPEN_EDITOR_DATA_FOLDER: @@ -844,5 +845,6 @@ func help_menu_id_pressed(id: int) -> void: about_dialog.popup() Global.HelpMenu.SUPPORT_PIXELORAMA: OS.shell_open(SUPPORT_URL) + SteamManager.set_achievement("ACH_SUPPORT_DEVELOPMENT") _: _handle_metadata(id, help_menu)