{"id":15722490,"url":"https://github.com/insality/defold-saver","last_synced_at":"2025-10-04T20:58:31.835Z","repository":{"id":251107213,"uuid":"836409149","full_name":"Insality/defold-saver","owner":"Insality","description":"Defold Save File Manager","archived":false,"fork":false,"pushed_at":"2025-04-26T12:19:48.000Z","size":885,"stargazers_count":32,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-27T12:24:37.075Z","etag":null,"topics":["defold","defold-extension","defold-library","defold-module","lua","save-manager"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Insality.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"insality","ko_fi":"insality","buy_me_a_coffee":"insality"}},"created_at":"2024-07-31T19:36:06.000Z","updated_at":"2025-04-26T12:19:52.000Z","dependencies_parsed_at":null,"dependency_job_id":"7c3cc768-5061-482e-8ec8-3a4fbf3b0673","html_url":"https://github.com/Insality/defold-saver","commit_stats":null,"previous_names":["insality/defold-saver"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Insality%2Fdefold-saver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Insality%2Fdefold-saver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Insality%2Fdefold-saver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Insality%2Fdefold-saver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Insality","download_url":"https://codeload.github.com/Insality/defold-saver/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252576835,"owners_count":21770720,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["defold","defold-extension","defold-library","defold-module","lua","save-manager"],"created_at":"2024-10-03T22:08:05.389Z","updated_at":"2025-10-04T20:58:31.816Z","avatar_url":"https://github.com/Insality.png","language":"Lua","funding_links":["https://github.com/sponsors/insality","https://ko-fi.com/insality","https://buymeacoffee.com/insality","https://www.buymeacoffee.com/insality"],"categories":[],"sub_categories":[],"readme":"![](media/logo.png)\n\n[![GitHub release (latest by date)](https://img.shields.io/github/v/tag/insality/defold-saver?style=for-the-badge\u0026label=Release)](https://github.com/Insality/defold-saver/tags)\n[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/insality/defold-saver/ci_workflow.yml?style=for-the-badge)](https://github.com/Insality/defold-saver/actions)\n[![codecov](https://img.shields.io/codecov/c/github/Insality/defold-saver?style=for-the-badge)](https://codecov.io/gh/Insality/defold-saver)\n\n[![Github-sponsors](https://img.shields.io/badge/sponsor-30363D?style=for-the-badge\u0026logo=GitHub-Sponsors\u0026logoColor=#EA4AAA)](https://github.com/sponsors/insality) [![Ko-Fi](https://img.shields.io/badge/Ko--fi-F16061?style=for-the-badge\u0026logo=ko-fi\u0026logoColor=white)](https://ko-fi.com/insality) [![BuyMeACoffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge\u0026logo=buy-me-a-coffee\u0026logoColor=black)](https://www.buymeacoffee.com/insality)\n\n# Saver\n\n**Saver** - is a library for saving and loading save data in **Defold** projects. It provides a simple API for saving and loading save data, as well as support for migrations and simple key-value storage. The library supports saving and loading data in JSON, Lua or binary format, and can save and load files to and from the file system.\n\n## Features\n\n- **Save and Load Game State**: Save and load Lua tables with a simple API.\n- **File Management**: Save and load data from filesystem or application data folder.\n- **Auto-Save**: Automatically save state at regular intervals.\n- **Storage**: Store key-value pairs in the game state.\n- **Format support**: Save and load Lua tables in \"json\", \"lua\" or \"serialized\" format.\n- **Binary Data**: Save and load the raw binary data (like images) with dedicated functions.\n- **Migrations**: Apply migrations to game state when the migration version changed.\n\n## Setup\n\n### [Dependency](https://www.defold.com/manuals/libraries/)\n\nOpen your `game.project` file and add the following line to the dependencies field under the project section:\n\n**[Saver](https://github.com/Insality/defold-saver/archive/refs/tags/5.zip)**\n\n```\nhttps://github.com/Insality/defold-saver/archive/refs/tags/5.zip\n```\n\nAfter that, select `Project ▸ Fetch Libraries` to update [library dependencies]((https://defold.com/manuals/libraries/#setting-up-library-dependencies)). This happens automatically whenever you open a project so you will only need to do this if the dependencies change without re-opening the project.\n\n### Library Size\n\n\u003e **Note:** The library size is calculated based on the build report per platform\n\n| Platform         | Library Size |\n| ---------------- | ------------ |\n| HTML5            | **5.23 KB**  |\n| Desktop / Mobile | **8.68 KB**  |\n\n\n### Configuration [optional]\n\nYou can configure the module in the `game.project` file:\n\n```ini\n[saver]\nsave_name = game\nsave_folder = Defold Saver\nautosave_timer = 3\nsaver_key = saver\nlua_require_as_string = 0\n```\n\nAll of these settings you can also set in the `saver.init` function.\n\n```lua\nsaver.init({\n\tsave_name = \"game\",\n\tsave_folder = \"Defold Saver\",\n\tautosave_timer = 3,\n\tsaver_key = \"saver\",\n\tlua_require_as_string = 0,\n})\n```\nThis configuration section for `game.project` defines various settings:\n\n- **save_name**: The name of the save file. Default is `game`. The file will be stored in the `save_folder` folder. Can have an extension like `.json`, `.lua` (but will not keep the userdata types like `vmath.vector3`, `hash` etc).\n- **save_folder**: The folder name where the save file will be stored. Default is your `project.title` name (with only alphanumeric, underscores or spaces characters).\n- **autosave_timer**: The time interval in seconds between auto-saves. Default is `3`.\n- **saver_key**: The key in the save data table that contains the Saver state. Default is `saver`.\n- **lua_require_as_string**: If set to `1`, the `require()` function will load Lua files as strings instead of Lua tables. This is useful for loading external files and processing their paths. The default value is `0`. This setting only affects the Lua format and works for load function. Very special case!\n\n### Core Concepts\n\nDefold Saver uses the following core concepts:\n- **Auto-Save**: Automatically save data at regular intervals. It used as a default save method. This allows you to specify the data you want to keep in the save file and the library will handle the rest.\n- **Save State**: A Save state contains a set of table references in the save file. You can bind multiple save states. Bindings is done by the `saver.bind_save_state(id, table_reference)` function. When you bind the table to save state and previous data was saved, the save data will override values in your reference table. So usually you should bind the default table from module or your game data on game loader step.\n- **Migration**: Migrations are used to update the save data if required. Migration is a just list of functions that will be applied to the save data if the migration version in save is less than the migrations count. You can set migrations by `saver.set_migrations` function before `saver.init` and apply them by `saver.apply_migrations` function after.\n- **Storage**: Storage is a simple key-value storage that can be utilized in many ways and you don't want to make a separate save state for it. You can set and get values by `saver.set_value` and `saver.get_value` functions.\n- **Saving Userdata**: Take a note, if your data contains Defold userdata, like `vmath.vector3`, `hash` etc, you should don't use the `json` file format, due the userdata will be lost. Use `lua` or `serialized` format instead. Read more in Use Cases section.\n- **Binary Data Handling**: The library provides dedicated functions for handling binary data (like images or other non-Lua tables). Use `saver.save_binary_by_name`/`saver.load_binary_by_name` and `saver.save_binary_by_path`/`saver.load_binary_by_path` for raw binary data.\n- **HTML5 Support**: The library supports HTML5 platform and uses `sys.serialize` with `base64` encoding for saving all data instead all other formats.\n\n\n## Basic Usage\n\nBind your lua table to make it persistent:\n\n```lua\nlocal saver = require(\"saver.saver\")\n\nlocal game_data = {\n\tscore = 0,\n\tlevel = 1,\n}\n\nfunction init(self)\n\tsaver.init()\n\tsaver.bind_save_state(\"game\", game_data)\n\n\t-- Now we can change game_data content and it will be saved automatically via autosave\n\tgame_data.score = game_data.score + 1\n\n\t-- Or you can save it manually by saver.save_game_state() if you want to save it immediately\n\tsaver.save_game_state()\nend\n```\n\nUsing the simple storage API:\n\n```lua\nlocal saver = require(\"saver.saver\")\n\nfunction init(self)\n\tlocal run_count = saver.get_value(\"run_count\", 0)\n\trun_count = run_count + 1\n\tsaver.set_value(\"run_count\", run_count)\nend\n```\n\n\n## API Reference\n\n### Quick API Reference\n\n```lua\nlocal saver = require(\"saver.saver\")\n\n-- Main functions\nsaver.init()\nsaver.bind_save_state(table_key_id, table_reference)\nsaver.save_game_state([save_name])\nsaver.load_game_state([save_name])\nsaver.set_game_state(game_state)\nsaver.get_game_state()\nsaver.delete_game_state([save_name])\n\n-- File Handling by absolute path\nsaver.save_file_by_path(data, absolute_file_path, [format])\nsaver.load_file_by_path(absolute_file_path, [format])\nsaver.save_binary_by_path(data, absolute_file_path)\nsaver.load_binary_by_path(absolute_file_path)\nsaver.delete_file_by_path(absolute_file_path)\nsaver.is_file_exists_by_path(absolute_file_path)\n\n-- File Handling by relative path in application data folder (from sys.get_save_path())\n-- Subfolders are supported\nsaver.save_file_by_name(data, file_name, [format])\nsaver.load_file_by_name(file_name, [format])\nsaver.save_binary_by_name(data, file_name)\nsaver.load_binary_by_name(file_name)\nsaver.delete_file_by_name(file_name)\nsaver.is_file_exists_by_name(file_name)\n\n-- File format constants\nsaver.FORMAT.SERIALIZED -- \"serialized\", save and load as Lua serialized table. Default format.\nsaver.FORMAT.JSON -- \"json\", save and load as JSON. Autoselect if path ends with .json\nsaver.FORMAT.LUA -- \"lua\", save and load as Lua. Autoselect if path ends with .lua\n\n-- Storage\nsaver.set_value(key_id, value)\nsaver.get_value(key_id, [default_value])\nsaver.is_value_exists(key_id)\n\n-- Migrations\nsaver.set_migrations(migration_list)\nsaver.apply_migrations()\n\n-- Other\nsaver.set_autosave_timer(seconds)\nsaver.get_save_path(file_name)\nsaver.get_save_version()\nsaver.set_logger(logger)\nsaver.get_current_game_project_folder()\nsaver.before_save_callback = function() \"Called before saver saves data\" end\n\n---@deprecated Use `saver.set_value` and `saver.get_value` instead\nlocal storage = require(\"saver.storage\")\nstorage.set(id, value)\nstorage.get(id, [default_value])\nstorage.get_number(id, [default_value])\nstorage.get_string(id, [default_value])\nstorage.get_boolean(id, [default_value])\n```\n\n### API Reference\n\n- Saver API: [saver_api.md](api/saver_api.md)\n- Storage API: [storage_api.md](api/storage_api.md) (deprecated, use `saver.set_value` and `saver.get_value` instead)\n\n\n## Use Cases\n\nRead the [Use Cases](USE_CASES.md) file to see several examples of how to use the this module in your Defold game development projects.\n\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n\n## Issues and Suggestions\n\nFor any issues, questions, or suggestions, please [create an issue](https://github.com/Insality/defold-saver/issues).\n\n\n## 👏 Contributors\n\n\u003ca href=\"https://github.com/Insality/defold-saver/graphs/contributors\"\u003e\n  \u003cimg src=\"https://contributors-img.web.app/image?repo=insality/defold-saver\"/\u003e\n\u003c/a\u003e\n\n## Changelog\n\n\u003cdetails\u003e\n\n### **V1**\n- Initial release\n\n### **V2**\n- Update docs, missing API for saver.delete_* functions\n- Fix error with `get_current_game_project_folder` while using in HTML5 builds\n- Add `saver.before_save_callback` callback for custom save logic. Can be used to prepare/update data before saving, like transfing from real-time data to save data\n\n### **V3**\n- **BREAKING**: HTML5 data now using `sys.serialize` instead `json.encode` due the issue with `json.encode` (sparse arrays, number keys)\n\t- I'm not expecting any game in production to use this feature, but if you are using it, please implement migration for your save data\n- **BREAKING**: Change the way to get the project file name. Now it's removing the spaces and special characters from the project title.\n\t- To get the previous behavior, you should set the `save_folder` in the `game.project` file.\n\n- Add `saver.save_folder` configuration option to README.md.\n- Fix `saver.delete_file_by_path` for HTML5.\n\n### **V4**\n- Add binary data handling with explicit API for different file formats\n  - Previously, this library was designed to save and load a Lua table to persistent storage. But sometimes you want to operate with binary data, like images, audio, etc. Now you can use `saver.save_binary_by_name`/`saver.load_binary_by_name` and `saver.save_binary_by_path`/`saver.load_binary_by_path` for raw binary data.\n- Better file format detection and improved internal implementation\n- More consistent API for saving and loading files\n- Deprecated `saver.storage` module\n  - Now you should use `saver.set_value` and `saver.get_value` for key-value storage\n\n### **V5**\n- #10 Add Configuration options via api to `saver.init(config)` to cover all `game.project` settings\n\n\u003c/details\u003e\n\n\n## ❤️ Support project ❤️\n\nYour donation helps me stay engaged in creating valuable projects for **Defold**. If you appreciate what I'm doing, please consider supporting me!\n\n[![Github-sponsors](https://img.shields.io/badge/sponsor-30363D?style=for-the-badge\u0026logo=GitHub-Sponsors\u0026logoColor=#EA4AAA)](https://github.com/sponsors/insality) [![Ko-Fi](https://img.shields.io/badge/Ko--fi-F16061?style=for-the-badge\u0026logo=ko-fi\u0026logoColor=white)](https://ko-fi.com/insality) [![BuyMeACoffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge\u0026logo=buy-me-a-coffee\u0026logoColor=black)](https://www.buymeacoffee.com/insality)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finsality%2Fdefold-saver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finsality%2Fdefold-saver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finsality%2Fdefold-saver/lists"}