{"id":19125634,"url":"https://github.com/dmitmel/crosscode-readable-saves","last_synced_at":"2025-02-22T14:47:43.211Z","repository":{"id":95463685,"uuid":"258267423","full_name":"dmitmel/crosscode-readable-saves","owner":"dmitmel","description":"A mod for CrossCode which unencrypts the save file and adds an additional save format suitable for editing by hand","archived":false,"fork":false,"pushed_at":"2024-02-19T16:34:11.000Z","size":161,"stargazers_count":1,"open_issues_count":4,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-03T09:46:04.303Z","etag":null,"topics":["ccmod","ccmodding-typescript","crosscode","mod"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/dmitmel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"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}},"created_at":"2020-04-23T16:38:46.000Z","updated_at":"2022-11-13T09:58:49.000Z","dependencies_parsed_at":"2023-03-22T04:50:37.015Z","dependency_job_id":null,"html_url":"https://github.com/dmitmel/crosscode-readable-saves","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmitmel%2Fcrosscode-readable-saves","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmitmel%2Fcrosscode-readable-saves/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmitmel%2Fcrosscode-readable-saves/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmitmel%2Fcrosscode-readable-saves/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dmitmel","download_url":"https://codeload.github.com/dmitmel/crosscode-readable-saves/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240190907,"owners_count":19762591,"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":["ccmod","ccmodding-typescript","crosscode","mod"],"created_at":"2024-11-09T05:36:14.855Z","updated_at":"2025-02-22T14:47:43.189Z","avatar_url":"https://github.com/dmitmel.png","language":"TypeScript","readme":"# crosscode-readable-saves\n\n[![go to the releases page](https://raw.githubusercontent.com/CCDirectLink/organization/master/assets/badges/releases@2x.png)](https://github.com/dmitmel/crosscode-readable-saves/releases)\n\nA mod which improves the [savegame format](https://crosscode.gamepedia.com/Savegame) of CrossCode\nby:\n\n1. Disabling encryption (decryption is still in place, so your old save file will be imported\n   without any problems)\n2. Writing the slots and the game options in separate JSON files (which are easily editable) into\n   the `cc-readable-save` directory alongside your regular save file\n\n## Overview of the default save format\n\nFirst of all, here's some information about the regular save file. It is located in:\n\n| System     | Path                                                      |\n| ---------- | --------------------------------------------------------- |\n| MS Windows | `%LOCALAPPDATA%\\CrossCode\\cc.save`                        |\n| macOS      | `~/Library/Application Support/CrossCode/Default/cc.save` |\n| GNU/Linux  | `~/.config/CrossCode/Default/cc.save`                     |\n\nIt's default format is\n([taken from the CrossCode wiki](https://crosscode.gamepedia.com/Savegame#Savefile_and_Localstorage_format),\nsee that page for more info):\n\n\u003c!-- prettier-ignore --\u003e\n```json5\n{\n  \"slots\": [\n    \"{encrypted slot 1}\",\n    \"{encrypted slot 2}\",\n    \"{encrypted slot 3}\",\n    // ...\n    \"{encrypted slot N}\",\n  ],\n  \"autoSlot\": \"{encrypted}\",\n  \"globals\": \"{encrypted}\",   // game options and trophies/achievements\n  \"lastSlot\": -1              // last loaded slot, slot index or -1 if that was the auto slot\n}\n```\n\nEncrypted strings always start with `[-!_0_!-]`, the rest is JSON data encrypted with\n[AES-256](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) (in\n[CBC mode](\u003chttps://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_block_chaining_(CBC)\u003e))\nand then encoded with [Base64](https://en.wikipedia.org/wiki/Base64). The password used for AES\nencryption is already known since May 2016:\n\n\u003cdetails\u003e\u003csummary\u003eClick to reveal the password (unless you want the challenge of figuring it out by reverse-engineering the game)\u003c/summary\u003e\u003cp\u003e\n\n`:_.NaN0`\n\n\u003c/p\u003e\u003c/details\u003e\n\n## Functionality of this mod\n\nAlright, so you probably get the general details about the default format, now allow me to introduce\nthe two readable save formats used by this mod. First of all I should note that by default the game\nabsolutely supports unencrypted save slots and globals data. Why? You see, the save loading code is\nfilled with checks like (expressed in pseudo-code):\n\n```python\ndata = get_slot_data()\nif is_encrypted(data):\n  data = parse_json(decrypt(data))\nprocess_data(data)\n```\n\nSo as you can see, **if I put regular JSON objects in the save file** instead of running them\nthrough this bizarre encryption pipeline, **the save file will remain 100% compatible with the\nregular game**. _\u0026lt;rant\u0026gt;_ Code like this was present even way back when `localStorage` (with\nits 5 MB limitation) was used for storing save data. Why haven't developers still simply thrown the\nencryption out yet? _Hell if I know!_ Moreover, skipping the encryption actually makes save files\nsmaller! You see, AES (as any other encryption algorithm) spits out raw binary data which messes\nwith common text encodings, something is needed to raw binary data in a form which can be\nrepresented and transmitted universally, which is where Base64 comes in. Base64 encodes any data\nwith plain [ASCII](https://en.wikipedia.org/wiki/ASCII) characters `A-Z`, `a-z`, `0-9`, `+`, `/` and\n`=`. However, it does that at the expense of file size because each 3 bytes are encoded with 4\ncharacters. Hence, by skipping the encryption altogether I can make the savegame smaller by one\nthird (~33%)! It also improves compression ratios because compression algorithms deal better with\ndata which contains a lot of repeating patterns (since those patterns can be easily folded together)\nand encrypted base64-encoded data looks practically random to any compression algorithm.\nAdditionally, I sped up the start up time a bit because AES encryption is a relatively time- and\nprocessing power-consuming operation. Oh, almost forgot to mention: this makes it easy to write\nscripts for reading and manipulating your save files (you cheater) with tools like\n[jq](https://stedolan.github.io/jq/). _\u0026lt;/rant\u0026gt;_\n\nAs you can see, the advantages of unencryption are obvious and there are no disadvantages (even\nincompatibility problems) other than messing with existing save editors which don't (yet) include\n`if encrypted only then decrypt` checks. One of the functions of this mod is disabling the save\nencryption. Note that I didn't disable decryption, so your regular save file will be imported\nwithout any problems.\n\nNext up, the real deal. Even unencrypted save files can reach the size of several (if not tens of)\nmegabytes. As not everyone uses tiny text editors like [Vim](https://www.vim.org/) or\n[nano](https://www.nano-editor.org/) I firgured that I might as well add a supplementary save format\nwhich puts different slots into separate files and is written in parallel with the regular save\nfile. This mod adds a new `cc-readable-save` directory which is located next to your the default\nfile, that is:\n\n| System     | Path                                                                |\n| ---------- | ------------------------------------------------------------------- |\n| MS Windows | `%LOCALAPPDATA%\\CrossCode\\cc-readable-save\\`                        |\n| macOS      | `~/Library/Application Support/CrossCode/Default/cc-readable-save/` |\n| GNU/Linux  | `~/.config/CrossCode/Default/cc.save/cc-readable-save/`             |\n\nIts structure is as follows:\n\n```\ncc-readable-save/\n├─ slots/\n│  ├─ 00.json\n│  ├─ 01.json\n│  ├─ 02.json\n│ ...\n│  └─ NN.json\n├─ autoSlot.json\n├─ globals.json\n└─ misc.json\n```\n\nThis should be pretty self-descriptive. `slots/` directory contains save slots, `autoSlot.json` is\nthe auto slot (or simply contains the text `null` if there is no auto slot), `globals.json` contains\nthe globals data and `misc.json` contains `lastSlot` along with any other fields which may be added\nin the future. Unlike the regular save file these files are written in a so-called \"formatted\" form,\nin other words with all spaces and identination, so you don't even need a JSON beautifier to edit\nthem. Moreover, you can drop additional save slots into the slots directory and they will be\nimported automatically after you launch the game. Deleted slots are deleted on disk as well. Note\nthat the slots are read in the [ASCII](https://en.wikipedia.org/wiki/ASCII) sort order, so numbers\nin the file names are used to correctly preserve the order of all of the slots.\n\n## Caveats\n\nFirst of all: **the readable save files are not backed up!** That's because the regular save file is\nstill written to the disk and it already has a backup system, so if you mess up your\n`cc-readable-save` directory you can always delete it and the save data will be restored from the\nregular save. And yes, **the readable save has priority over the regular file** (in other words, if\na readable save exists it will be loaded instead of the regular one) to allow you to easily edit\nsave data. **Readable saves are also not synced with Steam Cloud** because naturally they are bigger\nthan the original save and it already contains your data, so there is no need to push it to the\ncloud twice. I also have to mention that **there is a small performance cost to writing all of those\nreadable files**, but it should usually be unnoticeable.\n\n## Contributing\n\nTo set up the development environment run:\n\n```bash\nnpm install\nnpm run build\n\n# or:\nyarn install\nyarn run build\n```\n\nI also recommend cloning\n[`ultimate-crosscode-typedefs`](https://github.com/dmitmel/ultimate-crosscode-typedefs) somewhere\nand linking it to this package using:\n\n```bash\ncd path/to/ultimate-crosscode-typedefs\nnpm link\ncd path/to/crosscode-readable-saves\nnpm link ultimate-crosscode-typedefs\n\n# or:\ncd path/to/ultimate-crosscode-typedefs\nyarn link\ncd path/to/crosscode-readable-saves\nyarn link ultimate-crosscode-typedefs\n```\n\nSo that you can easily add TS definitions if needed.\n\n## License\n\nSee the [`LICENSE`](https://github.com/dmitmel/crosscode-readable-saves/blob/master/LICENSE) file.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmitmel%2Fcrosscode-readable-saves","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdmitmel%2Fcrosscode-readable-saves","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmitmel%2Fcrosscode-readable-saves/lists"}