Skip to content

Commit d881eca

Browse files
committed
write a README
1 parent d5cb6eb commit d881eca

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

README.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# crosscode-readable-saves
2+
3+
[![go to the releases page](https://raw.githubusercontent.com/CCDirectLink/organization/master/assets/badges/[email protected])](https://github.com/dmitmel/crosscode-readable-saves/releases)
4+
5+
A mod which improves the [savegame format](https://crosscode.gamepedia.com/Savegame) of CrossCode by:
6+
7+
1. Disabling encryption (decryption is still in place, so your old save file will be imported without any problems)
8+
2. Writing the slots and the game options in separate JSON files (which are easily editable) into the `cc-readable-save` directory alongside your regular save file
9+
10+
## Overview of the default save format
11+
12+
First of all, here's some information about the regular save file. It is located in:
13+
14+
| System | Path |
15+
| ---------- | --------------------------------------------------------- |
16+
| MS Windows | `%LOCALAPPDATA%\CrossCode\cc.save` |
17+
| macOS | `~/Library/Application Support/CrossCode/Default/cc.save` |
18+
| GNU/Linux | `~/.config/CrossCode/Default/cc.save` |
19+
20+
It's default format is ([taken from the CrossCode wiki](https://crosscode.gamepedia.com/Savegame#Savefile_and_Localstorage_format), see that page for more info):
21+
22+
<!-- prettier-ignore -->
23+
```json5
24+
{
25+
"slots": [
26+
"{encrypted slot 1}",
27+
"{encrypted slot 2}",
28+
"{encrypted slot 3}",
29+
// ...
30+
"{encrypted slot N}",
31+
],
32+
"autoSlot": "{encrypted}",
33+
"globals": "{encrypted}", // game options and trophies/achievements
34+
"lastSlot": -1 // last loaded slot, slot index or -1 if that was the auto slot
35+
}
36+
```
37+
38+
Encrypted strings always start with `[-!_0_!-]`, the rest is JSON data encrypted with [AES-256](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) (in [CBC mode](<https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_block_chaining_(CBC)>)) and then encoded with [Base64](https://en.wikipedia.org/wiki/Base64). The password used for AES encryption is already known since May 2016:
39+
40+
<details><summary>Click to reveal the password (unless you want the challenge of figuring it out by reverse-engineering the game)</summary><p>
41+
42+
`:_.NaN0`
43+
44+
</p></details>
45+
46+
## Functionality of this mod
47+
48+
Alright, so you probably get the general details about the default format, now allow me to introduce the two readable save formats used by this mod. First of all I should note that by default the game absolutely supports unencrypted save slots and globals data. Why? You see, the save loading code is filled with checks like (expressed in pseudo-code):
49+
50+
```python
51+
data = get_slot_data()
52+
if is_encrypted(data):
53+
data = parse_json(decrypt(data))
54+
process_data(data)
55+
```
56+
57+
So as you can see, **if I put regular JSON objects in the save file** instead of running them through this bizarre encryption pipeline, **the save file will remain 100% compatible with the regular game**. _&lt;rant&gt;_ Code like this was present even way back when `localStorage` (with its 5 MB limitation) was used for storing save data. Why haven't developers still simply thrown the encryption out yet? _Hell if I know!_ Moreover, skipping the encryption actually makes save files smaller! You see, AES (as any other encryption algorithm) spits out raw binary data which messes with common text encodings, something is needed to raw binary data in a form which can be represented and transmitted universally, which is where Base64 comes in. Base64 encodes any data with plain [ASCII](https://en.wikipedia.org/wiki/ASCII) characters `A-Z`, `a-z`, `0-9`, `+`, `/` and `=`. However, it does that at the expense of file size because each 3 bytes are encoded with 4 characters. Hence, by skipping the encryption altogether I can make the savegame smaller by one third (~33%)! It also improves compression ratios because compression algorithms deal better with data which contains a lot of repeating patterns (since those patterns can be easily folded together) and encrypted base64-encoded data looks practically random to any compression algorithm. Additionally, I sped up the start up time a bit because AES encryption is a relatively time- and processing power-consuming operation. Oh, almost forgot to mention: this makes it easy to write scripts for reading and manipulating your save files (you cheater) with tools like [jq](https://stedolan.github.io/jq/). _&lt;/rant&gt;_
58+
59+
As you can see, the advantages of unencryption are obvious and there are no disadvantages (even incompatibility problems) other than messing with existing save editors which don't (yet) include `if encrypted only then decrypt` checks. One of the functions of this mod is disabling the save encryption. Note that I didn't disable decryption, so your regular save file will be imported without any problems.
60+
61+
Next up, the real deal. Even unencrypted save files can reach the size of several (if not tens of) megabytes. As not everyone uses tiny text editors like [Vim](https://www.vim.org/) or [nano](https://www.nano-editor.org/) I firgured that I might as well add a supplementary save format which puts different slots into separate files and is written in parallel with the regular save file. This mod adds a new `cc-readable-save` directory which is located next to your the default file, that is:
62+
63+
| System | Path |
64+
| ---------- | ------------------------------------------------------------------- |
65+
| MS Windows | `%LOCALAPPDATA%\CrossCode\cc-readable-save\` |
66+
| macOS | `~/Library/Application Support/CrossCode/Default/cc-readable-save/` |
67+
| GNU/Linux | `~/.config/CrossCode/Default/cc.save/cc-readable-save/` |
68+
69+
Its structure is as follows:
70+
71+
```
72+
cc-readable-save/
73+
├─ slots/
74+
│ ├─ 00.json
75+
│ ├─ 01.json
76+
│ ├─ 02.json
77+
│ ...
78+
│ └─ NN.json
79+
├─ autoSlot.json
80+
├─ globals.json
81+
└─ misc.json
82+
```
83+
84+
This should be pretty self-descriptive. `slots/` directory contains save slots, `autoSlot.json` is the auto slot (or simply contains the text `null` if there is no auto slot), `globals.json` contains the globals data and `misc.json` contains `lastSlot` along with any other fields which may be added in the future. Unlike the regular save file these files are written in a so-called "formatted" form, in other words with all spaces and identination, so you don't even need a JSON beautifier to edit them. Moreover, you can drop additional save slots into the slots directory and they will be imported automatically after you launch the game. Deleted slots are deleted on disk as well. Note that the slots are read in the [ASCII](https://en.wikipedia.org/wiki/ASCII) sort order, so numbers in the file names are used to correctly preserve the order of all of the slots.
85+
86+
## Caveats
87+
88+
First of all: **the readable save files are not backed up!** That's because the regular save file is still written to the disk and it already has a backup system, so if you mess up your `cc-readable-save` directory you can always delete it and the save data will be restored from the regular save. And yes, **the readable save has priority over the regular file** (in other words, if a readable save exists it will be loaded instead of the regular one) to allow you to easily edit save data. **Readable saves are also not synced with Steam Cloud** because naturally they are bigger than the original save and it already contains your data, so there is no need to push it to the cloud twice. I also have to mention that **there is a small performance cost to writing all of those readable files**, but it should usually be unnoticeable.
89+
90+
## Contributing
91+
92+
To set up the development environment run:
93+
94+
```bash
95+
npm install
96+
npm run build
97+
98+
# or:
99+
yarn install
100+
yarn run build
101+
```
102+
103+
I also recommend cloning [`ultimate-crosscode-typedefs`](https://github.com/dmitmel/ultimate-crosscode-typedefs) somewhere and linking it to this package using:
104+
105+
```bash
106+
cd path/to/ultimate-crosscode-typedefs
107+
npm link
108+
cd path/to/crosscode-readable-saves
109+
npm link ultimate-crosscode-typedefs
110+
111+
# or:
112+
cd path/to/ultimate-crosscode-typedefs
113+
yarn link
114+
cd path/to/crosscode-readable-saves
115+
yarn link ultimate-crosscode-typedefs
116+
```
117+
118+
So that you can easily add TS definitions if needed.
119+
120+
## License
121+
122+
See the [`LICENSE`](https://github.com/dmitmel/crosscode-readable-saves/blob/master/LICENSE) file.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
{
22
"name": "readable-saves",
33
"ccmodHumanName": "Readable saves",
4+
"description": "Unencrypts the save file and adds an additional save format suitable for editing by hand",
45
"version": "0.0.0",
6+
"license": "MIT",
7+
"homepage": "https://github.com/dmitmel/crosscode-readable-saves",
58
"module": true,
69
"postload": "dist/postload.js",
710
"ccmodDependencies": {

0 commit comments

Comments
 (0)