From 42bcbaf2b0fddb6343d5f5c31800958d5d2aa764 Mon Sep 17 00:00:00 2001 From: Insality Date: Sat, 17 May 2025 13:33:36 +0300 Subject: [PATCH 01/14] Add saber debug panel --- .../properties_panel/property_saver_slots.gui | 313 ++++++++++++++++++ .../properties_panel/property_saver_slots.lua | 66 ++++ saver/saver.lua | 14 + saver/saver_debug_page.lua | 117 +++++++ 4 files changed, 510 insertions(+) create mode 100644 saver/properties_panel/property_saver_slots.gui create mode 100644 saver/properties_panel/property_saver_slots.lua create mode 100644 saver/saver_debug_page.lua diff --git a/saver/properties_panel/property_saver_slots.gui b/saver/properties_panel/property_saver_slots.gui new file mode 100644 index 0000000..f8316dc --- /dev/null +++ b/saver/properties_panel/property_saver_slots.gui @@ -0,0 +1,313 @@ +fonts { + name: "druid_text_bold" + font: "/druid/fonts/druid_text_bold.font" +} +textures { + name: "druid" + texture: "/druid/druid.atlas" +} +nodes { + size { + x: 400.0 + y: 40.0 + } + type: TYPE_BOX + texture: "druid/empty" + id: "root" + adjust_mode: ADJUST_MODE_STRETCH + inherit_alpha: true + visible: false +} +nodes { + position { + x: -200.0 + } + scale { + x: 0.5 + y: 0.5 + } + size { + x: 350.0 + y: 40.0 + } + color { + x: 0.463 + y: 0.475 + z: 0.49 + } + type: TYPE_TEXT + text: "Slots" + font: "druid_text_bold" + id: "text_name" + pivot: PIVOT_W + outline { + x: 1.0 + y: 1.0 + z: 1.0 + } + shadow { + x: 1.0 + y: 1.0 + z: 1.0 + } + adjust_mode: ADJUST_MODE_STRETCH + parent: "root" + inherit_alpha: true + outline_alpha: 0.0 + shadow_alpha: 0.0 +} +nodes { + position { + x: 200.0 + } + size { + x: 200.0 + y: 40.0 + } + type: TYPE_BOX + id: "E_Anchor" + pivot: PIVOT_E + parent: "root" + inherit_alpha: true + size_mode: SIZE_MODE_AUTO + visible: false +} +nodes { + position { + x: -170.0 + } + size { + x: 60.0 + y: 40.0 + } + color { + x: 0.463 + y: 0.475 + z: 0.49 + } + type: TYPE_BOX + texture: "druid/rect_round2_width2" + id: "button_1" + parent: "E_Anchor" + inherit_alpha: true + slice9 { + x: 5.0 + y: 5.0 + z: 5.0 + w: 5.0 + } +} +nodes { + position { + y: -20.0 + } + size { + x: 60.0 + y: 4.0 + } + color { + x: 0.894 + y: 0.506 + z: 0.333 + } + type: TYPE_BOX + texture: "druid/pixel" + id: "selected_1" + pivot: PIVOT_S + adjust_mode: ADJUST_MODE_STRETCH + parent: "button_1" + inherit_alpha: true +} +nodes { + scale { + x: 0.5 + y: 0.5 + } + size { + x: 90.0 + y: 50.0 + } + color { + x: 0.722 + y: 0.741 + z: 0.761 + } + type: TYPE_TEXT + text: "1" + font: "druid_text_bold" + id: "text_button_1" + outline { + x: 1.0 + y: 1.0 + z: 1.0 + } + shadow { + x: 1.0 + y: 1.0 + z: 1.0 + } + parent: "button_1" + inherit_alpha: true + outline_alpha: 0.0 + shadow_alpha: 0.0 +} +nodes { + position { + x: -100.0 + } + size { + x: 60.0 + y: 40.0 + } + color { + x: 0.463 + y: 0.475 + z: 0.49 + } + type: TYPE_BOX + texture: "druid/rect_round2_width2" + id: "button_2" + parent: "E_Anchor" + inherit_alpha: true + slice9 { + x: 5.0 + y: 5.0 + z: 5.0 + w: 5.0 + } +} +nodes { + position { + y: -20.0 + } + size { + x: 60.0 + y: 4.0 + } + color { + x: 0.894 + y: 0.506 + z: 0.333 + } + type: TYPE_BOX + texture: "druid/pixel" + id: "selected_2" + pivot: PIVOT_S + adjust_mode: ADJUST_MODE_STRETCH + parent: "button_2" + inherit_alpha: true +} +nodes { + scale { + x: 0.5 + y: 0.5 + } + size { + x: 90.0 + y: 50.0 + } + color { + x: 0.722 + y: 0.741 + z: 0.761 + } + type: TYPE_TEXT + text: "2" + font: "druid_text_bold" + id: "text_button_2" + outline { + x: 1.0 + y: 1.0 + z: 1.0 + } + shadow { + x: 1.0 + y: 1.0 + z: 1.0 + } + parent: "button_2" + inherit_alpha: true + outline_alpha: 0.0 + shadow_alpha: 0.0 +} +nodes { + position { + x: -30.0 + } + size { + x: 60.0 + y: 40.0 + } + color { + x: 0.463 + y: 0.475 + z: 0.49 + } + type: TYPE_BOX + texture: "druid/rect_round2_width2" + id: "button_3" + parent: "E_Anchor" + inherit_alpha: true + slice9 { + x: 5.0 + y: 5.0 + z: 5.0 + w: 5.0 + } +} +nodes { + position { + y: -20.0 + } + size { + x: 60.0 + y: 4.0 + } + color { + x: 0.894 + y: 0.506 + z: 0.333 + } + type: TYPE_BOX + texture: "druid/pixel" + id: "selected_3" + pivot: PIVOT_S + adjust_mode: ADJUST_MODE_STRETCH + parent: "button_3" + inherit_alpha: true +} +nodes { + scale { + x: 0.5 + y: 0.5 + } + size { + x: 90.0 + y: 50.0 + } + color { + x: 0.722 + y: 0.741 + z: 0.761 + } + type: TYPE_TEXT + text: "3" + font: "druid_text_bold" + id: "text_button_3" + outline { + x: 1.0 + y: 1.0 + z: 1.0 + } + shadow { + x: 1.0 + y: 1.0 + z: 1.0 + } + parent: "button_3" + inherit_alpha: true + outline_alpha: 0.0 + shadow_alpha: 0.0 +} +material: "/builtins/materials/gui.material" +adjust_reference: ADJUST_REFERENCE_PARENT diff --git a/saver/properties_panel/property_saver_slots.lua b/saver/properties_panel/property_saver_slots.lua new file mode 100644 index 0000000..ad59d73 --- /dev/null +++ b/saver/properties_panel/property_saver_slots.lua @@ -0,0 +1,66 @@ +local color = require("druid.color") + +---@class druid.widget.property_three_buttons: druid.widget +---@field root node +---@field container druid.container +---@field text_name druid.text +---@field button_1 druid.button +---@field text_button_1 druid.text +---@field button_2 druid.button +---@field text_button_2 druid.text +---@field button_3 druid.button +---@field text_button_3 druid.text +local M = {} + + +function M:init() + self.root = self:get_node("root") + self.text_name = self.druid:new_text("text_name") + :set_text_adjust("scale_then_trim", 0.3) + + self.selected_nodes = { + self:get_node("selected_1"), + self:get_node("selected_2"), + self:get_node("selected_3"), + } + gui.set_alpha(self.selected_nodes[1], 0) + gui.set_alpha(self.selected_nodes[2], 0) + gui.set_alpha(self.selected_nodes[3], 0) + + self.button_1 = self.druid:new_button("button_1", self.on_click, 1) + self.text_button_1 = self.druid:new_text("text_button_1") + + self.button_2 = self.druid:new_button("button_2", self.on_click, 2) + self.text_button_2 = self.druid:new_text("text_button_2") + + self.button_3 = self.druid:new_button("button_3", self.on_click, 3) + self.text_button_3 = self.druid:new_text("text_button_3") + + self.container = self.druid:new_container(self.root) + self.container:add_container("text_name", nil, function(_, size) + self.text_name:set_size(size) + end) + self.container:add_container("E_Anchor") +end + + +function M:on_click(index) + gui.set_alpha(self.selected_nodes[index], 1) + gui.animate(self.selected_nodes[index], "color.w", 0, gui.EASING_INSINE, 0.16) +end + + +---@param text string +---@return druid.widget.property_three_buttons +function M:set_text_property(text) + self.text_name:set_text(text) + return self +end + + +function M:set_color(color_value) + color.set_color(self:get_node("button"), color_value) +end + + +return M diff --git a/saver/saver.lua b/saver/saver.lua index b1694ad..2976313 100644 --- a/saver/saver.lua +++ b/saver/saver.lua @@ -9,6 +9,7 @@ local storage = require("saver.storage") local migrations = require("saver.migrations") local saver_internal = require("saver.saver_internal") +local saver_debug_page = require("saver.saver_debug_page") --- Take a default folder name as a project name without special characters local PROJECT_NAME = sys.get_config_string("project.title"):gsub("[^%w_ ]", "") @@ -463,6 +464,13 @@ function M.set_autosave_timer(timer) end +---Returns the current autosave timer. +---@return number timer The current autosave timer. +function M.get_autosave_timer() + return AUTOSAVE_TIMER +end + + ---@private ---Autosave timer callback function M.on_autosave_timer() @@ -629,6 +637,12 @@ function M.is_value_exists(key_id) end +---@param druid druid.instance +---@param properties_panel druid.widget.properties_panel +function M.render_properties_panel(druid, properties_panel) + saver_debug_page.render_properties_panel(M, druid, properties_panel) +end + ---A callback that is called before the saver saves the game state. ---You can use it to perform additional actions before saving the game state. ---For example to update your save data with values from the game. diff --git a/saver/saver_debug_page.lua b/saver/saver_debug_page.lua new file mode 100644 index 0000000..12d191b --- /dev/null +++ b/saver/saver_debug_page.lua @@ -0,0 +1,117 @@ +local properties_saver_slots = require("saver.properties_panel.property_saver_slots") + +local M = {} + + +---@param saver saver +---@param druid druid.instance +---@param properties_panel druid.widget.properties_panel +function M.render_properties_panel(saver, druid, properties_panel) + properties_panel:next_scene() + properties_panel:set_header("Saver Panel") + + properties_panel:add_button(function(button) + button:set_text_property("Game State") + button:set_text_button("Save") + saver.save_game_state() + end) + + properties_panel:add_button(function(button) + button:set_text_property("Game State") + button:set_text_button("Inspect") + button.button.on_click:subscribe(function() + properties_panel:next_scene() + properties_panel:set_header("Game State") + properties_panel:render_lua_table(saver.get_game_state()) + end) + end) + + properties_panel:add_widget(function() + local three_buttons = druid:new_widget(properties_saver_slots, "property_saver_slots", "root") + three_buttons:set_text_property("Save Slot") + + three_buttons.button_1.on_click:subscribe(function() + saver.save_game_state("saver_slot_1") + end) + three_buttons.button_2.on_click:subscribe(function() + saver.save_game_state("saver_slot_2") + end) + three_buttons.button_3.on_click:subscribe(function() + saver.save_game_state("saver_slot_3") + end) + + return three_buttons + end) + + properties_panel:add_widget(function() + local three_buttons = druid:new_widget(properties_saver_slots, "property_saver_slots", "root") + three_buttons:set_text_property("Load Slot") + + three_buttons.button_1.on_click:subscribe(function() + saver.load_game_state("saver_slot_1") + sys.reboot() + end) + three_buttons.button_2.on_click:subscribe(function() + saver.load_game_state("saver_slot_2") + sys.reboot() + end) + three_buttons.button_3.on_click:subscribe(function() + saver.load_game_state("saver_slot_3") + sys.reboot() + end) + + return three_buttons + end) + + properties_panel:add_widget(function() + local three_buttons = druid:new_widget(properties_saver_slots, "property_saver_slots", "root") + three_buttons:set_text_property("Delete Slot") + + three_buttons.button_1.on_click:subscribe(function() + print("Hold button to delete slot 1") + end) + three_buttons.button_1.on_long_click:subscribe(function() + saver.delete_game_state("saver_slot_1") + sys.reboot() + end) + + three_buttons.button_2.on_click:subscribe(function() + print("Hold button to delete slot 2") + end) + three_buttons.button_2.on_long_click:subscribe(function() + saver.delete_game_state("saver_slot_2") + sys.reboot() + end) + + three_buttons.button_3.on_click:subscribe(function() + print("Hold button to delete slot 3") + end) + three_buttons.button_3.on_long_click:subscribe(function() + saver.delete_game_state("saver_slot_3") + sys.reboot() + end) + + return three_buttons + end) + + properties_panel:add_button(function(button) + button:set_text_property("Game State") + button:set_text_button("pprint") + button.button.on_click:subscribe(function() + pprint(saver.get_game_state()) + end) + end) + + properties_panel:add_input(function(input) + input:set_text_property("Autosave") + input.on_change_value:subscribe(function(value) + value = tonumber(value) or 0 + print("Autosave timer: " .. value) + saver.set_autosave_timer(value) + end) + input:set_text_value(saver.get_autosave_timer()) + end) +end + + +return M From fb775d536909965ff7441f718e2dae0c13c3477e Mon Sep 17 00:00:00 2001 From: Insality Date: Sat, 17 May 2025 19:57:01 +0300 Subject: [PATCH 02/14] Update --- saver/saver_debug_page.lua | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/saver/saver_debug_page.lua b/saver/saver_debug_page.lua index 12d191b..782f326 100644 --- a/saver/saver_debug_page.lua +++ b/saver/saver_debug_page.lua @@ -13,7 +13,9 @@ function M.render_properties_panel(saver, druid, properties_panel) properties_panel:add_button(function(button) button:set_text_property("Game State") button:set_text_button("Save") - saver.save_game_state() + button.button.on_click:subscribe(function() + saver.save_game_state() + end) end) properties_panel:add_button(function(button) @@ -111,6 +113,11 @@ function M.render_properties_panel(saver, druid, properties_panel) end) input:set_text_value(saver.get_autosave_timer()) end) + + properties_panel:add_text(function(text) + text:set_text_property("Version") + text:set_text_value(tostring(saver.get_save_version())) + end) end From 1eac359949849fa4b7049adf2f098282df1deca3 Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 20 May 2025 20:58:00 +0300 Subject: [PATCH 03/14] Fix for lua require as string --- saver/saver_internal.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/saver/saver_internal.lua b/saver/saver_internal.lua index bccfb88..c427c7f 100644 --- a/saver/saver_internal.lua +++ b/saver/saver_internal.lua @@ -188,7 +188,7 @@ function M.load_lua(filepath) return nil end - if LUA_REQUIRE_AS_STRING then + if M.LUA_REQUIRE_AS_STRING then -- Replace all require("some.path") to "/some/path.lua" file_data = file_data:gsub('require%("([^"]+)"%)', function(path) return string.format('"/%s"', path:gsub("%.", "/") .. ".lua") @@ -446,7 +446,7 @@ function M.table_to_lua_string(tbl, indent, is_array) local v_is_array = #v > 0 result = result .. M.table_to_lua_string(v, indent .. " ", v_is_array) elseif type(v) == "string" then - local is_require = LUA_REQUIRE_AS_STRING and v:sub(-1) == ')' and v:sub(1, 8) == 'require(' + local is_require = M.LUA_REQUIRE_AS_STRING and v:sub(-1) == ')' and v:sub(1, 8) == 'require(' if is_require then result = result .. v else From 6b6d224e605ba755a460f5f1e023cbe3249eaa12 Mon Sep 17 00:00:00 2001 From: Insality Date: Thu, 22 May 2025 22:13:38 +0300 Subject: [PATCH 04/14] Remove druid color from debug panels --- saver/properties_panel/property_saver_slots.lua | 7 ------- 1 file changed, 7 deletions(-) diff --git a/saver/properties_panel/property_saver_slots.lua b/saver/properties_panel/property_saver_slots.lua index ad59d73..92783a8 100644 --- a/saver/properties_panel/property_saver_slots.lua +++ b/saver/properties_panel/property_saver_slots.lua @@ -1,5 +1,3 @@ -local color = require("druid.color") - ---@class druid.widget.property_three_buttons: druid.widget ---@field root node ---@field container druid.container @@ -58,9 +56,4 @@ function M:set_text_property(text) end -function M:set_color(color_value) - color.set_color(self:get_node("button"), color_value) -end - - return M From 38a1c6cc0cdeea189d6ddfe6456495c70c2052a2 Mon Sep 17 00:00:00 2001 From: Insality Date: Sat, 24 May 2025 19:29:33 +0300 Subject: [PATCH 05/14] Update subfolders for windows paths --- saver/saver.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/saver/saver.lua b/saver/saver.lua index 2976313..0039a82 100644 --- a/saver/saver.lua +++ b/saver/saver.lua @@ -434,6 +434,9 @@ function M.get_save_path(filename) -- If filename contains "/" extract subfolder to the dir_name local directory_path = DIRECTORY_PATH + -- For windows we can't make subfolders, but we can use _ instead of \ + filename = filename:gsub("\\", "_") + if filename:find("/") then local splitted = saver_internal.split(filename, "/") filename = splitted[#splitted] From f88417d203719149dcf04f50e2837f1bf6cc7ff9 Mon Sep 17 00:00:00 2001 From: Insality Date: Sat, 24 May 2025 22:48:56 +0300 Subject: [PATCH 06/14] Fix for windows \r lines --- saver/saver_internal.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/saver/saver_internal.lua b/saver/saver_internal.lua index c427c7f..2d45727 100644 --- a/saver/saver_internal.lua +++ b/saver/saver_internal.lua @@ -112,7 +112,7 @@ end ---@param filepath string The file path ---@return boolean success Whether the save was successful function M.save_json(data, filepath) - local file = io.open(filepath, "w+") + local file = io.open(filepath, "wb") if not file then M.logger:error("Can't open file for writing", filepath) return false @@ -157,7 +157,7 @@ end ---@param filepath string The file path ---@return boolean success Whether the save was successful function M.save_lua(data, filepath) - local file = io.open(filepath, "w+") + local file = io.open(filepath, "wb") if not file then M.logger:error("Can't open file for writing", filepath) return false From ecc51bd5a716033eadca3b1039d323045b646993 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 25 May 2025 16:56:08 +0300 Subject: [PATCH 07/14] Fix for window paths again --- saver/saver.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/saver/saver.lua b/saver/saver.lua index 0039a82..6eb7712 100644 --- a/saver/saver.lua +++ b/saver/saver.lua @@ -18,6 +18,7 @@ local SAVE_NAME = sys.get_config_string("saver.save_name", "game") local SAVER_KEY = sys.get_config_string("saver.saver_key", "saver") local DEFAULT_AUTOSAVE_TIMER = sys.get_config_int("saver.autosave_timer", 3) local STORAGE_KEY = sys.get_config_string("saver.storage_key", "storage") -- deprecated +local IS_WINDOWS = sys.get_sys_info().system_name == "Windows" -- If several instances of the game are running, then we using instance index to avoid conflicts local INSTANCE_INDEX = sys.get_config_int("project.instance_index", 0) @@ -434,6 +435,7 @@ function M.get_save_path(filename) -- If filename contains "/" extract subfolder to the dir_name local directory_path = DIRECTORY_PATH + -- For windows we can't make subfolders, but we can use _ instead of \ filename = filename:gsub("\\", "_") @@ -443,6 +445,11 @@ function M.get_save_path(filename) directory_path = directory_path .. "/" .. table.concat(splitted, "/", 1, #splitted - 1) end + -- If we on windows, replace all subfolders with _ + if IS_WINDOWS then + directory_path = directory_path:gsub("/", "_") + end + return sys.get_save_file(directory_path, filename) end From 188eae4070d291b90b4d2bbdfbd24393ad4997b0 Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 27 May 2025 23:07:15 +0300 Subject: [PATCH 08/14] The get_save_path() without arguments now returns a app folder --- saver/saver.lua | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/saver/saver.lua b/saver/saver.lua index 6eb7712..1b76811 100644 --- a/saver/saver.lua +++ b/saver/saver.lua @@ -423,15 +423,28 @@ end ---Returns the absolute path to the game save folder. If a file name is provided, the path to the file in the game save folder is returned. Filename supports subfolders. +--- local folder_path = saver.get_save_path() +--- print(folder_path) -- "/Users/user/Library/Application Support/Defold Saver/" +--- --- local file_path = saver.get_save_path("data.json") --- print(file_path) -- "/Users/user/Library/Application Support/Defold Saver/data.json" --- --- local file_path_2 = saver.get_save_path("profiles/profile1.json") --- print(file_path_2) -- "/Users/user/Library/Application Support/Defold Saver/profiles/profile1.json" ----@param filename string The name of the file to get the path for. Can contain subfolders. +---@param filename string|nil The name of the file to get the path for. Can contain subfolders. If nil, returns the folder path. ---@return string path The absolute path to the game save folder, or the path to the file in the game save folder if a file name is provided. function M.get_save_path(filename) - assert(filename, "Can't get save path without filename") + -- If no filename provided, return just the folder path + if not filename then + local directory_path = DIRECTORY_PATH + -- If we on windows, replace all subfolders with _ + if IS_WINDOWS then + directory_path = directory_path:gsub("/", "_") + end + local folder_path = sys.get_save_file(directory_path, "") + --folder_path = folder_path:gsub("[^/\\]*$", "") -- + return folder_path + end -- If filename contains "/" extract subfolder to the dir_name local directory_path = DIRECTORY_PATH From ba3b352a640327c90f5bbd450cd3cf488db30c7b Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 27 May 2025 23:07:27 +0300 Subject: [PATCH 09/14] Update saver debug panel --- saver/saver_debug_page.lua | 45 +++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/saver/saver_debug_page.lua b/saver/saver_debug_page.lua index 782f326..05be191 100644 --- a/saver/saver_debug_page.lua +++ b/saver/saver_debug_page.lua @@ -11,7 +11,7 @@ function M.render_properties_panel(saver, druid, properties_panel) properties_panel:set_header("Saver Panel") properties_panel:add_button(function(button) - button:set_text_property("Game State") + button:set_text_property("Save Game") button:set_text_button("Save") button.button.on_click:subscribe(function() saver.save_game_state() @@ -19,7 +19,16 @@ function M.render_properties_panel(saver, druid, properties_panel) end) properties_panel:add_button(function(button) - button:set_text_property("Game State") + button:set_text_property("Save Folder") + button:set_text_button("Open") + button:set_color("#7D6034") + button.button.on_click:subscribe(function() + M.open_at_desktop(saver.get_save_path()) + end) + end) + + properties_panel:add_button(function(button) + button:set_text_property("Inspect State") button:set_text_button("Inspect") button.button.on_click:subscribe(function() properties_panel:next_scene() @@ -70,35 +79,32 @@ function M.render_properties_panel(saver, druid, properties_panel) three_buttons:set_text_property("Delete Slot") three_buttons.button_1.on_click:subscribe(function() - print("Hold button to delete slot 1") + print("You pressed delete button. Hold to confirm.") end) three_buttons.button_1.on_long_click:subscribe(function() saver.delete_game_state("saver_slot_1") - sys.reboot() end) three_buttons.button_2.on_click:subscribe(function() - print("Hold button to delete slot 2") + print("You pressed delete button. Hold to confirm.") end) three_buttons.button_2.on_long_click:subscribe(function() saver.delete_game_state("saver_slot_2") - sys.reboot() end) three_buttons.button_3.on_click:subscribe(function() - print("Hold button to delete slot 3") + print("You pressed delete button. Hold to confirm.") end) three_buttons.button_3.on_long_click:subscribe(function() saver.delete_game_state("saver_slot_3") - sys.reboot() end) return three_buttons end) properties_panel:add_button(function(button) - button:set_text_property("Game State") - button:set_text_button("pprint") + button:set_text_property("pprint") + button:set_text_button("Game State") button.button.on_click:subscribe(function() pprint(saver.get_game_state()) end) @@ -121,4 +127,23 @@ function M.render_properties_panel(saver, druid, properties_panel) end +---@param path string +---@return boolean +function M.open_at_desktop(path) + local system = sys.get_sys_info().system_name + if system == "Windows" then + os.execute(string.format('explorer /select,"%s"', path)) + return true + elseif system == "Linux" then + os.execute(string.format("xdg-open %q", path)) + return true + elseif system == "Darwin" then + os.execute(string.format("open -R %q", path)) + return true + end + + return false +end + + return M From f5856cc9fe7afbd9056951d7018d174936b7d63b Mon Sep 17 00:00:00 2001 From: Insality Date: Wed, 28 May 2025 23:31:32 +0300 Subject: [PATCH 10/14] Update log --- saver/saver.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/saver/saver.lua b/saver/saver.lua index 1b76811..8da54bb 100644 --- a/saver/saver.lua +++ b/saver/saver.lua @@ -102,7 +102,7 @@ function M.init(config) M.check_game_version() M.set_autosave_timer(DEFAULT_AUTOSAVE_TIMER) - saver_internal.logger:info("Save loaded", M.get_game_state()[SAVER_KEY]) + saver_internal.logger:debug("Saver initialized") end From 7d9f2d4eea3dfdaa29327533d6a88acc853ff179 Mon Sep 17 00:00:00 2001 From: Insality Date: Thu, 19 Jun 2025 20:32:50 +0300 Subject: [PATCH 11/14] Fix reboot --- saver/saver_debug_page.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/saver/saver_debug_page.lua b/saver/saver_debug_page.lua index 05be191..0ef867a 100644 --- a/saver/saver_debug_page.lua +++ b/saver/saver_debug_page.lua @@ -60,15 +60,15 @@ function M.render_properties_panel(saver, druid, properties_panel) three_buttons.button_1.on_click:subscribe(function() saver.load_game_state("saver_slot_1") - sys.reboot() + sys.reboot("--config=saver.save_name=saver_slot_1", "--config=saver.autosave_timer=0") end) three_buttons.button_2.on_click:subscribe(function() saver.load_game_state("saver_slot_2") - sys.reboot() + sys.reboot("--config=saver.save_name=saver_slot_2", "--config=saver.autosave_timer=0") end) three_buttons.button_3.on_click:subscribe(function() saver.load_game_state("saver_slot_3") - sys.reboot() + sys.reboot("--config=saver.save_name=saver_slot_3", "--config=saver.autosave_timer=0") end) return three_buttons From 575999f2bff21153ef34e072d2d5f1f5a4d574d5 Mon Sep 17 00:00:00 2001 From: Insality Date: Fri, 11 Jul 2025 23:53:00 +0300 Subject: [PATCH 12/14] Update subfolders --- saver/saver.lua | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/saver/saver.lua b/saver/saver.lua index 8da54bb..90b3221 100644 --- a/saver/saver.lua +++ b/saver/saver.lua @@ -18,7 +18,9 @@ local SAVE_NAME = sys.get_config_string("saver.save_name", "game") local SAVER_KEY = sys.get_config_string("saver.saver_key", "saver") local DEFAULT_AUTOSAVE_TIMER = sys.get_config_int("saver.autosave_timer", 3) local STORAGE_KEY = sys.get_config_string("saver.storage_key", "storage") -- deprecated -local IS_WINDOWS = sys.get_sys_info().system_name == "Windows" +local SYSTEM_NAME = sys.get_sys_info().system_name +local IS_WINDOWS = SYSTEM_NAME == "Windows" +local IS_LINUX = SYSTEM_NAME == "Linux" -- If several instances of the game are running, then we using instance index to avoid conflicts local INSTANCE_INDEX = sys.get_config_int("project.instance_index", 0) @@ -371,7 +373,8 @@ function M.save_file_by_name(data, filename, format) return false end - return M.save_file_by_path(data, M.get_save_path(filename), format) + local path = M.get_save_path(filename) + return M.save_file_by_path(data, path, format) end @@ -437,33 +440,16 @@ function M.get_save_path(filename) -- If no filename provided, return just the folder path if not filename then local directory_path = DIRECTORY_PATH - -- If we on windows, replace all subfolders with _ - if IS_WINDOWS then - directory_path = directory_path:gsub("/", "_") - end - local folder_path = sys.get_save_file(directory_path, "") - --folder_path = folder_path:gsub("[^/\\]*$", "") -- - return folder_path - end - - -- If filename contains "/" extract subfolder to the dir_name - local directory_path = DIRECTORY_PATH - - -- For windows we can't make subfolders, but we can use _ instead of \ - filename = filename:gsub("\\", "_") - - if filename:find("/") then - local splitted = saver_internal.split(filename, "/") - filename = splitted[#splitted] - directory_path = directory_path .. "/" .. table.concat(splitted, "/", 1, #splitted - 1) + return sys.get_save_file(directory_path, "") end - -- If we on windows, replace all subfolders with _ - if IS_WINDOWS then - directory_path = directory_path:gsub("/", "_") + -- Only this OS can't make subfolders, so we need to replace all "/" with "_". Should be fixed? + -- MacOS is okay with that + if IS_WINDOWS or IS_LINUX then + filename = filename:gsub("/", "_") end - return sys.get_save_file(directory_path, filename) + return sys.get_save_file(DIRECTORY_PATH, filename) end From c78c6f828b622e6a266a65565f41927061542c8a Mon Sep 17 00:00:00 2001 From: Insality Date: Wed, 16 Jul 2025 21:26:30 +0300 Subject: [PATCH 13/14] Remove subfolder support due it not working well currently --- saver/saver.lua | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/saver/saver.lua b/saver/saver.lua index 90b3221..3bd6b9e 100644 --- a/saver/saver.lua +++ b/saver/saver.lua @@ -18,9 +18,6 @@ local SAVE_NAME = sys.get_config_string("saver.save_name", "game") local SAVER_KEY = sys.get_config_string("saver.saver_key", "saver") local DEFAULT_AUTOSAVE_TIMER = sys.get_config_int("saver.autosave_timer", 3) local STORAGE_KEY = sys.get_config_string("saver.storage_key", "storage") -- deprecated -local SYSTEM_NAME = sys.get_sys_info().system_name -local IS_WINDOWS = SYSTEM_NAME == "Windows" -local IS_LINUX = SYSTEM_NAME == "Linux" -- If several instances of the game are running, then we using instance index to avoid conflicts local INSTANCE_INDEX = sys.get_config_int("project.instance_index", 0) @@ -443,11 +440,7 @@ function M.get_save_path(filename) return sys.get_save_file(directory_path, "") end - -- Only this OS can't make subfolders, so we need to replace all "/" with "_". Should be fixed? - -- MacOS is okay with that - if IS_WINDOWS or IS_LINUX then - filename = filename:gsub("/", "_") - end + filename = filename:gsub("/", "_") return sys.get_save_file(DIRECTORY_PATH, filename) end From 13fc2476caa927808adc9fb19ea6723c81d513c0 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 26 Oct 2025 19:42:09 +0200 Subject: [PATCH 14/14] Update properties panel --- saver/saver.lua | 7 ------- saver/saver_debug_page.lua | 6 +++--- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/saver/saver.lua b/saver/saver.lua index 3bd6b9e..9a50b89 100644 --- a/saver/saver.lua +++ b/saver/saver.lua @@ -9,7 +9,6 @@ local storage = require("saver.storage") local migrations = require("saver.migrations") local saver_internal = require("saver.saver_internal") -local saver_debug_page = require("saver.saver_debug_page") --- Take a default folder name as a project name without special characters local PROJECT_NAME = sys.get_config_string("project.title"):gsub("[^%w_ ]", "") @@ -639,12 +638,6 @@ function M.is_value_exists(key_id) end ----@param druid druid.instance ----@param properties_panel druid.widget.properties_panel -function M.render_properties_panel(druid, properties_panel) - saver_debug_page.render_properties_panel(M, druid, properties_panel) -end - ---A callback that is called before the saver saves the game state. ---You can use it to perform additional actions before saving the game state. ---For example to update your save data with values from the game. diff --git a/saver/saver_debug_page.lua b/saver/saver_debug_page.lua index 0ef867a..72c8c3e 100644 --- a/saver/saver_debug_page.lua +++ b/saver/saver_debug_page.lua @@ -1,12 +1,12 @@ +local saver = require("saver.saver") local properties_saver_slots = require("saver.properties_panel.property_saver_slots") local M = {} ----@param saver saver ---@param druid druid.instance ---@param properties_panel druid.widget.properties_panel -function M.render_properties_panel(saver, druid, properties_panel) +function M.render_properties_panel(druid, properties_panel) properties_panel:next_scene() properties_panel:set_header("Saver Panel") @@ -21,7 +21,7 @@ function M.render_properties_panel(saver, druid, properties_panel) properties_panel:add_button(function(button) button:set_text_property("Save Folder") button:set_text_button("Open") - button:set_color("#7D6034") + button:set_color("#6FA4DC") button.button.on_click:subscribe(function() M.open_at_desktop(saver.get_save_path()) end)