Skip to content

Conversation

@mihe
Copy link
Contributor

@mihe mihe commented Oct 24, 2025

Resolves godotengine/godot-proposals#13404.
Supersedes #111731.

Overview

This pull request adds the ability to use delta encoding (sometimes referred to as binary patching or binary diffing) when exporting patch PCKs, first introduced in #97118.

This means that only the parts of the files that have actually changed (or some close approximation of that) will end up being exported, often resulting in much smaller patch exports, which can benefit games that distribute patches by their own means, reducing bandwidth cost and storage usage for all parties involved.

This is especially true when dealing with changes to things like *.translation files, uid_cache.bin or global_script_class_cache.cfg, which often end up being included in patch exports and which together can easily make your patch several megabytes large despite very little having actually changed.

Screenshot_20251024_130226

Implementation

This is (unlike #111731) achieved by utilizing Zstandard's --patch-from functionality (thanks to @fire for pointing me towards it) which is basically an alias for providing the old file as the dictionary to be used in its dictionary-matching stage, resulting in compressed deltas that are very similar to those of other delta encoding tools like bsdiff (when also paired with Zstandard) but with much lower export-time memory usage and (at least on average) lower decompression/runtime overhead as well.

With the help of Zstandard we generate a delta between the old file (as found in the "Base Packs" entries) and the new file, which then gets exported instead of the actual file, along with a new PACK_FILE_DELTA PCK flag.

As a result of using compression, exporting a patch PCK with this feature enabled will take slightly longer, especially when leaving the compression level set to its default of 19. This can however mostly be resolved by just lowering the compression level, at the cost of export size. Decompression speed should largely remain the same for Zstandard across all compression levels, but you can also set a negative compression limit, which will enable its "fast mode", where it sacrifices even more compression for the sake of (de)compression speeds.

We also allow the user to tweak the "minimum size reduction", which is a threshold for how much smaller (10% by default) the patch would need to be compared to the new file in order to be exported as a delta. The reason for this being that applying these patches comes at a slight runtime cost during resource loading, not just from decompressing the patch but also the I/O overhead from loading it in the first place, so it needs to be justified with some amount of space saving.

Once exported, patch PCKs (much like before) look and behave just like any other PCK, where you load them through ProjectSettings.load_resource_pack, ideally through some bootstrap script where nothing else has had a chance to be loaded yet.

We then store any delta patches alongside the regular files in PackedData, and whenever a file is loaded from PackedData we wrap the resulting FileAccessPack inside of the newly introduced FileAccessPatched, which will lazily apply all the patches as needed, meaning it's completely transparent and should hopefully just work with any existing file/resource loading.

Important

Note that this means you pay the cost of applying these patches every time you load a patched resource that isn't already cached by ResourceLoader. The patches are not applied to the original PCKs in any way, nor are the patched resources cached anywhere on disk.

Performance

Export size will mostly depend on whether the original file is compressed or not. So things like textures or even GDScript files, when using its default export mode of "Compressed binary tokens", will diff poorly and often fall below the size reduction threshold. The same mostly goes for compressed localization files as well.

Important

Disabling compression on anything you intend to patch is key to getting good results, as compression scrambles data in a way where the old and the new file will look almost nothing alike.

In the real-world projects I've tested with you usually see an average reduction of around 60-90%, depending on the ratio of compressed resources, and an average runtime overhead of about 0.1 milliseconds per individual patch being applied, with patches to larger files sometimes being in the order of a few milliseconds.

DOGWALK

In the interest of showing a real-world example from an actual game, I've generated patches for the two updates of DOGWALK that have been published since its initial release. You can find the Godot project available through its Supporter Pack, with earlier versions being downloadable with the help of the Steam console and SteamDB.

These numbers are from using a compression level of 19. As mentioned already, faster (de)compression speeds can be had by using a negative compression level, at the cost of compression ratio.

(Also note that the files listed here will be slightly different compared to in #111731.)

v1.0.1 to v1.0.2

[Click to expand/collapse]

The first patch contains modifications to the following file types:

  • 8x texture files
  • 5x *.tscn files
  • 2x glTF files
  • 2x .json files
  • 1x *.tres files
  • 1x *.gd file
  • 1x global_script_class_cache.cfg
  • 1x uid_cache.bin
  • 1x project.godot

Out of those changes, 7 files (6 textures and 1 glTF file) fell below the reduction threshold and were not exported as a delta.

Without delta encoding the patch PCK ended up being 8.55 MiB, and with delta encoding the patch PCK ended up being 2.11 MiB, which is a reduction in size of roughly 75%.

For a breakdown of the individual files, see the output from the --verbose export:

Used delta encoding for patch of 'res://.godot/exported/133200997/export-99b6d6e785812c481ec56f0c19253d65-pine_cuts_atlas_albedo_01.res', resulting in a patch of 88 bytes, which reduced the size by 96.5% (2429 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/exported/133200997/export-75cc15c6f96624c92a89cd4ea423aab0-SE-clearing.scn', resulting in a patch of 811 bytes, which reduced the size by 84.5% (4410 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/SL-clearing_terrain.gltf-6c7bfff97231b94de231cd87b0a043cc.scn', resulting in a patch of 317184 bytes, which reduced the size by 45.2% (261137 bytes) compared to the actual file.
Skipped delta encoding for patch of 'res://.godot/imported/SL-fence-paths.gltf-5301a3dc110611ca08d2d765b45cc210.scn', as it resulted in a patch of 101353 bytes, which only reduced the size by 1.1% (1128 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/c1_0.png-633c826446b972eb64aa7ce688537a89.s3tc.ctex', resulting in a patch of 5996 bytes, which reduced the size by 99.8% (2998616 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/c1_1.png-f4d5442a5958d63be4969f9c43b55385.s3tc.ctex', resulting in a patch of 2922 bytes, which reduced the size by 99.9% (3001690 bytes) compared to the actual file.
Skipped delta encoding for patch of 'res://.godot/imported/c1_2.png-9836fb6c6208e9abc7dd976d1dfb2114.ctex', as it resulted in a patch of 12362 bytes, which only reduced the size by 3.9% (498 bytes) compared to the actual file.
Skipped delta encoding for patch of 'res://.godot/imported/c1_3.png-242aee2106e53d55e5258038d675c5d2.ctex', as it resulted in a patch of 11149 bytes, which only reduced the size by 3.9% (455 bytes) compared to the actual file.
Skipped delta encoding for patch of 'res://.godot/imported/c1_4.png-a2aaa3eae0a8fc20dc1fb8b773a2a2fc.ctex', as it resulted in a patch of 20890 bytes, which only reduced the size by 1.5% (314 bytes) compared to the actual file.
Skipped delta encoding for patch of 'res://.godot/imported/c1_5.png-13279df50fab7cb69d9d4b5c4cf35607.ctex', as it resulted in a patch of 12173 bytes, which only reduced the size by 2.7% (335 bytes) compared to the actual file.
Skipped delta encoding for patch of 'res://.godot/imported/c1_6.png-58b98eacb8e3e715db9592bbc6721513.ctex', as it resulted in a patch of 19576 bytes, which only reduced the size by 1.6% (320 bytes) compared to the actual file.
Skipped delta encoding for patch of 'res://.godot/imported/c1_7.png-cbe2618dd59d397fdcd297bc57e2a89a.ctex', as it resulted in a patch of 19487 bytes, which only reduced the size by 1.1% (221 bytes) compared to the actual file.
Used delta encoding for patch of 'res://source/entities/player_entities/pinda.gdc', resulting in a patch of 19361 bytes, which reduced the size by 89.7% (168843 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/exported/133200997/export-4810a76f52cab761a40b217606f3b3f7-world.scn', resulting in a patch of 2491 bytes, which reduced the size by 96.6% (70578 bytes) compared to the actual file.
Used delta encoding for patch of 'res://source/sequences/credits/credits.json', resulting in a patch of 128 bytes, which reduced the size by 97.4% (4880 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/exported/133200997/export-1ba630fc40b6c6f9f6410e00a7d23a6e-credits.scn', resulting in a patch of 477 bytes, which reduced the size by 94.7% (8439 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/exported/133200997/export-f7d1d2a6eca5754467a7d6172d8ffd11-credit_slide.scn', resulting in a patch of 82 bytes, which reduced the size by 96.4% (2207 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/exported/133200997/export-06339610f1a89a2edfbfa400f9fe80ce-menu_ui.scn', resulting in a patch of 474 bytes, which reduced the size by 84.4% (2558 bytes) compared to the actual file.
Used delta encoding for patch of 'res://material_index.json', resulting in a patch of 68 bytes, which reduced the size by 99.7% (25938 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/global_script_class_cache.cfg', resulting in a patch of 141 bytes, which reduced the size by 98.0% (6779 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/uid_cache.bin', resulting in a patch of 210 bytes, which reduced the size by 99.9% (175366 bytes) compared to the actual file.
Used delta encoding for patch of 'res://project.binary', resulting in a patch of 33 bytes, which reduced the size by 99.9% (26852 bytes) compared to the actual file.

v1.0.2 to v1.0.4

[Click to expand/collapse]

The second patch contains modifications to the following file types:

  • 64x glTF files
  • 7x *.gd files
  • 3x texture files
  • 4x *.tres files
  • 4x *.tscn files
  • 1x *.json file
  • 1x global_script_class_cache.cfg
  • 1x uid_cache.bin
  • 1x project.godot

Out of those changes, 10 files (9 glTF files and 1 texture) fell below the reduction threshold and were not exported as a delta.

Without delta encoding the patch PCK ended up being 14.64 MiB, and with delta encoding the patch PCK ended up being 5.03 MiB, which is a reduction in size of roughly 66%.

For a breakdown of the individual files, see the output from the --verbose export:

Used delta encoding for patch of 'res://.godot/imported/LI-bush_001.gltf-40b8180f1a8db565195bb533fe5b3b60.scn', resulting in a patch of 1276 bytes, which reduced the size by 96.9% (40252 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_002.gltf-046eef6042349a872843bd2bad57871d.scn', resulting in a patch of 393 bytes, which reduced the size by 99.0% (37576 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_003.gltf-d8b6330d3fbe3be54b19ef784d826f6f.scn', resulting in a patch of 131 bytes, which reduced the size by 99.7% (42750 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_004.gltf-44dfe26583b38b9bacbc865c65056616.scn', resulting in a patch of 126 bytes, which reduced the size by 99.7% (43311 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_small_001.gltf-fd7ac3b286c919a158b306ecbdb65c35.scn', resulting in a patch of 107 bytes, which reduced the size by 99.6% (30384 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_small_002.gltf-4c9d050b1c074ff3d5423d3e5923b648.scn', resulting in a patch of 337 bytes, which reduced the size by 98.9% (30131 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_small_003.gltf-c5f1b275891f4c31b9784b8fc30cad59.scn', resulting in a patch of 99 bytes, which reduced the size by 99.7% (30922 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage-snowy_001.gltf-556d234ef38f9ddf45c29e8e2fbd3bda.scn', resulting in a patch of 236 bytes, which reduced the size by 92.4% (2858 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage-snowy_002.gltf-fcb65cf55f75e73cf40e47ccc7e74694.scn', resulting in a patch of 247 bytes, which reduced the size by 90.7% (2415 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage-snowy_003.gltf-ff44781b0785aff6e0f0fba2504a5904.scn', resulting in a patch of 1638 bytes, which reduced the size by 26.6% (593 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage-snowy_004.gltf-0b9ac5457a4160af4672287ac31606df.scn', resulting in a patch of 1996 bytes, which reduced the size by 26.3% (714 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage-snowy_005.gltf-bf1c764613b8fbc17f3c09534ddc67e4.scn', resulting in a patch of 154 bytes, which reduced the size by 94.9% (2848 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage-snowy_006.gltf-fe91dd6bc077731e9831797c06039603.scn', resulting in a patch of 447 bytes, which reduced the size by 81.7% (1998 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage-snowy_small_001.gltf-189c3413a03374f594c5fd1da5f290fe.scn', resulting in a patch of 1480 bytes, which reduced the size by 26.4% (530 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage-snowy_small_002.gltf-36a183595198521e77f51fb267bbe794.scn', resulting in a patch of 268 bytes, which reduced the size by 91.4% (2860 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage-snowy_small_003.gltf-df154c9af2225b4e10e2a899bc5d401c.scn', resulting in a patch of 150 bytes, which reduced the size by 94.8% (2729 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage_001.gltf-27d68679ea3dfb3c0bcb765feb133896.scn', resulting in a patch of 179 bytes, which reduced the size by 93.6% (2632 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage_002.gltf-fa162cd4cdb0eeea6328f050e8d6ef75.scn', resulting in a patch of 1760 bytes, which reduced the size by 30.9% (788 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage_003.gltf-47ffef07e418a23b9f05bed81fafafe4.scn', resulting in a patch of 155 bytes, which reduced the size by 94.2% (2534 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage_004.gltf-ba2cb17ac74eb94060ddd32ab8207ff7.scn', resulting in a patch of 1802 bytes, which reduced the size by 25.4% (613 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage_005.gltf-0f77c124e37bed036c3a7d999dceb178.scn', resulting in a patch of 343 bytes, which reduced the size by 89.6% (2963 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage_006.gltf-316c5c718168f980bb653f8cd4644a67.scn', resulting in a patch of 133 bytes, which reduced the size by 94.6% (2341 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage_007.gltf-ab10a69cdb3259654a86117e6b1f268a.scn', resulting in a patch of 2050 bytes, which reduced the size by 26.5% (739 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage_008.gltf-5c1b2b549e76a49e9329055a815afd41.scn', resulting in a patch of 1760 bytes, which reduced the size by 24.6% (575 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage_009.gltf-86062acae855ef8da4f0192b18566a14.scn', resulting in a patch of 1599 bytes, which reduced the size by 33.5% (805 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage_010.gltf-e7890f91e8ee4789ab125803c3cabf69.scn', resulting in a patch of 461 bytes, which reduced the size by 85.4% (2705 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage_011.gltf-8a6eed4426edd1f2d08e02acda003b1e.scn', resulting in a patch of 1451 bytes, which reduced the size by 34.9% (779 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage_012.gltf-8f12950bd8b25dc07d659e0c22f604e0.scn', resulting in a patch of 128 bytes, which reduced the size by 95.3% (2608 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage_small_001.gltf-884d1bc365df4345b1f0a67137c33d94.scn', resulting in a patch of 971 bytes, which reduced the size by 76.4% (3148 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage_small_002.gltf-83f8fb5bbfe90f84f7601ee69c0ab163.scn', resulting in a patch of 1598 bytes, which reduced the size by 38.2% (986 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage_small_003.gltf-33bc06b77915fc3a7da9d3145a566af4.scn', resulting in a patch of 184 bytes, which reduced the size by 93.3% (2576 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage_small_004.gltf-b6c8e7c7acafc669df48bb8769618cb1.scn', resulting in a patch of 1923 bytes, which reduced the size by 22.7% (565 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage_top_001.gltf-ed2c90ebad7fca378f6c6c5ad107b353.scn', resulting in a patch of 42 bytes, which reduced the size by 99.8% (18505 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage_top_002.gltf-67d330a74fc8f5d641e040adec30e1c8.scn', resulting in a patch of 999 bytes, which reduced the size by 75.2% (3026 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage_top_003.gltf-9ef1a3dc5dc9965df4429232a5984d9a.scn', resulting in a patch of 747 bytes, which reduced the size by 82.5% (3521 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-bush_foliage_top_004.gltf-7b5bd6068a817dd027a42f82d80e22ea.scn', resulting in a patch of 824 bytes, which reduced the size by 79.2% (3138 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/exported/133200997/export-e17e8915be33ba3caa7e4c702c918edc-bush.res', resulting in a patch of 41 bytes, which reduced the size by 98.4% (2460 bytes) compared to the actual file.
Skipped delta encoding for patch of 'res://.godot/imported/LI-fence_plank_01.gltf-e13215b4301c7b31a0949889125e2a89.scn', as it resulted in a patch of 7154 bytes, which only reduced the size by 3.8% (280 bytes) compared to the actual file.
Skipped delta encoding for patch of 'res://.godot/imported/LI-fence_plank_02.gltf-6c1a23e046402ba81b318a02d735da28.scn', as it resulted in a patch of 7808 bytes, which only reduced the size by 2.9% (232 bytes) compared to the actual file.
Skipped delta encoding for patch of 'res://.godot/imported/LI-fence_plank_03.gltf-0db9a0a5e23e0cdb2a27b16f295d7913.scn', as it resulted in a patch of 7511 bytes, which only reduced the size by 0.6% (42 bytes) compared to the actual file.
Skipped delta encoding for patch of 'res://.godot/imported/LI-fence_plank_04.gltf-2ac84343d96045227a99e36057e94150.scn', as it resulted in a patch of 8435 bytes, which only reduced the size by 1.1% (92 bytes) compared to the actual file.
Skipped delta encoding for patch of 'res://.godot/imported/LI-fence_plank_05.gltf-48c19d68954b8336cc05a17fefda8146.scn', as it resulted in a patch of 7223 bytes, which only reduced the size by 1.5% (111 bytes) compared to the actual file.
Skipped delta encoding for patch of 'res://.godot/imported/LI-fence_plank_06.gltf-7402b271f99e4981e1d342f5000e25b6.scn', as it resulted in a patch of 7670 bytes, which only reduced the size by 1.1% (84 bytes) compared to the actual file.
Skipped delta encoding for patch of 'res://.godot/imported/LI-stone_plateau_001.gltf-81ce09b4a5ed8da31a696426534976cf.scn', as it resulted in a patch of 45568 bytes, which only reduced the size by 8.0% (3945 bytes) compared to the actual file.
Skipped delta encoding for patch of 'res://.godot/imported/LI-stone_plateau_002.gltf-574959712e3c543d31ad36128a2b6dc0.scn', as it resulted in a patch of 37499 bytes, which only reduced the size by 6.8% (2723 bytes) compared to the actual file.
Skipped delta encoding for patch of 'res://.godot/imported/LI-stone_plateau_003.gltf-37026e870d8fb0a798544f0dccc7b496.scn', as it resulted in a patch of 35427 bytes, which only reduced the size by 9.3% (3649 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/exported/133200997/export-293680cc51e9cd0486e497a8eb604d9d-stone_wall_snowy.res', resulting in a patch of 46 bytes, which reduced the size by 98.2% (2449 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-stone_wall_001.gltf-6c68ad4d827d2b7e25c8ec1694a9da78.scn', resulting in a patch of 24679 bytes, which reduced the size by 23.2% (7459 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-stone_wall_002.gltf-3999d05482c9e000e4436ec5e6510ca9.scn', resulting in a patch of 19573 bytes, which reduced the size by 33.2% (9724 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-stone_wall_003.gltf-8f877b58d5015175bf038b80b67f27c7.scn', resulting in a patch of 16707 bytes, which reduced the size by 32.6% (8092 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-stone_wall_004.gltf-dfd11977b987307e51beb8311c1ce28c.scn', resulting in a patch of 26682 bytes, which reduced the size by 23.9% (8374 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-stone_wall_005.gltf-b3c147109498a6276fff778d55741fda.scn', resulting in a patch of 34375 bytes, which reduced the size by 18.8% (7961 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-stone_wall_006.gltf-d1dd2bfefcf060652e63c3d0e5781138.scn', resulting in a patch of 19784 bytes, which reduced the size by 35.6% (10938 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-stone_wall_007.gltf-a3603ba590e9d8f97ea68bbb95e0a776.scn', resulting in a patch of 4841 bytes, which reduced the size by 73.2% (13240 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-stone_wall_008.gltf-624b84d84206001949001db0306e0295.scn', resulting in a patch of 11429 bytes, which reduced the size by 56.0% (14544 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-stone_wall_009.gltf-1e8816b13883295f833fb7319071709f.scn', resulting in a patch of 4774 bytes, which reduced the size by 81.9% (21665 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-stone_wall_010.gltf-2362d3699279fcc9458103e49cc790e8.scn', resulting in a patch of 545 bytes, which reduced the size by 97.3% (19327 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-stone_wall_0011.gltf-ae3bd59c7d1d082cdb0fdb86508668ed.scn', resulting in a patch of 4800 bytes, which reduced the size by 77.2% (16242 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-stone_wall_012.gltf-e8446df129f613e4df46c3cdf8589041.scn', resulting in a patch of 12062 bytes, which reduced the size by 55.2% (14882 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/LI-stone_wall_013.gltf-7e139cd3a8ca569ca6b10c933d1c3b81.scn', resulting in a patch of 9597 bytes, which reduced the size by 51.9% (10362 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/exported/133200997/export-8751d5cceb104760e2f281683e020794-stone_wall.res', resulting in a patch of 44 bytes, which reduced the size by 98.2% (2454 bytes) compared to the actual file.
Skipped delta encoding for patch of 'res://.godot/imported/stone_plateau_albedo.png-090b3b252fbd6390538b00add7a29c3b.ctex', as it resulted in a patch of 2307541 bytes, which only reduced the size by 4.1% (97877 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/stone_plateau_albedo.png-4e0e64b2e65449c1344dc953e684fdd1.s3tc.ctex', resulting in a patch of 985202 bytes, which reduced the size by 82.4% (4607282 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/PR-traffic_cone.gltf-fe0a84d532dd8a51f807efa767a4fb5e.scn', resulting in a patch of 7857 bytes, which reduced the size by 11.3% (1001 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/exported/133200997/export-3943d6ae2e8b37b6d9da82a68c5f8ec7-traffic_cone.res', resulting in a patch of 48 bytes, which reduced the size by 97.9% (2286 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/bush_foliage_atlas_albedo_01.png-08ce4663401c96283ce790aed759bd1b.s3tc.ctex', resulting in a patch of 1352345 bytes, which reduced the size by 75.8% (4240139 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/SL-clearing-bushes.gltf-47565441b9825109bba0dbc787560a44.scn', resulting in a patch of 25695 bytes, which reduced the size by 45.9% (21834 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/SL-clearing_shrubs.gltf-d979ffa9eda7d4d041d54adcf325b78a.scn', resulting in a patch of 3539 bytes, which reduced the size by 78.1% (12643 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/SL-fence-boulders.gltf-8f9ed2988aaf279616f03b0bd45b9280.scn', resulting in a patch of 2506 bytes, which reduced the size by 47.4% (2256 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/imported/SL-fence-vegetation.gltf-2b0c3486f9d852252ed746c8c54f60c9.scn', resulting in a patch of 53437 bytes, which reduced the size by 10.8% (6494 bytes) compared to the actual file.
Used delta encoding for patch of 'res://source/audio/sfx/pinda/pinda_sfx.gdc', resulting in a patch of 1267 bytes, which reduced the size by 94.5% (21837 bytes) compared to the actual file.
Used delta encoding for patch of 'res://source/entities/player_entities/camera.gdc', resulting in a patch of 2973 bytes, which reduced the size by 86.2% (18631 bytes) compared to the actual file.
Used delta encoding for patch of 'res://source/entities/player_entities/chocomel.gdc', resulting in a patch of 9015 bytes, which reduced the size by 88.5% (69185 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/exported/133200997/export-6d7bc4d39f8b5352d8abad820bf44d70-chocomel.scn', resulting in a patch of 424 bytes, which reduced the size by 97.6% (17404 bytes) compared to the actual file.
Used delta encoding for patch of 'res://source/entities/player_entities/leash.gdc', resulting in a patch of 288 bytes, which reduced the size by 99.3% (39588 bytes) compared to the actual file.
Used delta encoding for patch of 'res://source/entities/player_entities/pinda.gdc', resulting in a patch of 8067 bytes, which reduced the size by 95.7% (181161 bytes) compared to the actual file.
Used delta encoding for patch of 'res://source/entities/camera_magnet_zone.gdc', resulting in a patch of 33 bytes, which reduced the size by 99.2% (4035 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/exported/133200997/export-4810a76f52cab761a40b217606f3b3f7-world.scn', resulting in a patch of 3608 bytes, which reduced the size by 95.1% (70323 bytes) compared to the actual file.
Used delta encoding for patch of 'res://source/sequences/credits/credits.json', resulting in a patch of 73 bytes, which reduced the size by 98.5% (4952 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/exported/133200997/export-1ba630fc40b6c6f9f6410e00a7d23a6e-credits.scn', resulting in a patch of 324 bytes, which reduced the size by 96.4% (8582 bytes) compared to the actual file.
Used delta encoding for patch of 'res://source/user_interface/menus/settings_menu.gdc', resulting in a patch of 742 bytes, which reduced the size by 97.4% (27554 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/exported/133200997/export-3b7d2a6a20074e4b07b060ce359c7ebe-settings_menu.scn', resulting in a patch of 655 bytes, which reduced the size by 94.9% (12253 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/global_script_class_cache.cfg', resulting in a patch of 144 bytes, which reduced the size by 97.9% (6776 bytes) compared to the actual file.
Used delta encoding for patch of 'res://.godot/uid_cache.bin', resulting in a patch of 65 bytes, which reduced the size by 100.0% (175587 bytes) compared to the actual file.
Used delta encoding for patch of 'res://project.binary', resulting in a patch of 33 bytes, which reduced the size by 99.9% (26852 bytes) compared to the actual file.

Runtime overhead

[Click to expand/collapse]

On my machine (AMD 9950X3D) the overhead from applying the above mentioned patches averages around 66 µs, with roughly 60% of that being spent actually decoding the patches, and the rest being I/O. The median is 13 µs, with a worst-case of 1858 µs. In total the two patch PCKs added 3722 µs (3.7 ms) of overhead to resource loading across 56 resources when starting a new game.

I've seen very similar numbers on Android (OnePlus 8T from 2020, Snapdragon 865) in another real-world project, with averages hovering around 80 µs, with roughly half of that being spent on I/O.

For a breakdown of the individual files, see the output from a --verbose startup of the game:

Applied delta patch to 'res://.godot/global_script_class_cache.cfg' from 'v1.0.2.pck' in 14 μs (4 μs I/O, 9 μs decoding).
Applied delta patch to 'res://.godot/uid_cache.bin' from 'v1.0.2.pck' in 20 μs (6 μs I/O, 14 μs decoding).
Applied delta patch to 'res://.godot/global_script_class_cache.cfg' from 'v1.0.2.pck' in 6 μs (3 μs I/O, 3 μs decoding).
Applied delta patch to 'res://.godot/global_script_class_cache.cfg' from 'v1.0.4.pck' in 4 μs (3 μs I/O, 1 μs decoding).
Applied delta patch to 'res://.godot/uid_cache.bin' from 'v1.0.2.pck' in 14 μs (4 μs I/O, 10 μs decoding).
Applied delta patch to 'res://.godot/uid_cache.bin' from 'v1.0.4.pck' in 13 μs (4 μs I/O, 9 μs decoding).
Applied delta patch to 'res://source/entities/player_entities/camera.gdc' from 'v1.0.4.pck' in 43 μs (7 μs I/O, 36 μs decoding).
Applied delta patch to 'res://source/entities/player_entities/chocomel.gdc' from 'v1.0.4.pck' in 78 μs (6 μs I/O, 72 μs decoding).
Applied delta patch to 'res://.godot/imported/c1_0.png-633c826446b972eb64aa7ce688537a89.s3tc.ctex' from 'v1.0.2.pck' in 255 μs (8 μs I/O, 247 μs decoding).
Applied delta patch to 'res://.godot/imported/c1_1.png-f4d5442a5958d63be4969f9c43b55385.s3tc.ctex' from 'v1.0.2.pck' in 222 μs (6 μs I/O, 216 μs decoding).
Applied delta patch to 'res://.godot/exported/133200997/export-06339610f1a89a2edfbfa400f9fe80ce-menu_ui.scn' from 'v1.0.2.pck' in 12 μs (5 μs I/O, 7 μs decoding).
Applied delta patch to 'res://source/entities/player_entities/camera.gdc' from 'v1.0.4.pck' in 36 μs (6 μs I/O, 30 μs decoding).
Applied delta patch to 'res://.godot/exported/133200997/export-3b7d2a6a20074e4b07b060ce359c7ebe-settings_menu.scn' from 'v1.0.4.pck' in 22 μs (8 μs I/O, 13 μs decoding).
Applied delta patch to 'res://source/user_interface/menus/settings_menu.gdc' from 'v1.0.4.pck' in 21 μs (5 μs I/O, 16 μs decoding).
Applied delta patch to 'res://source/user_interface/menus/settings_menu.gdc' from 'v1.0.4.pck' in 14 μs (4 μs I/O, 10 μs decoding).
Applied delta patch to 'res://source/entities/player_entities/pinda.gdc' from 'v1.0.2.pck' in 126 μs (6 μs I/O, 120 μs decoding).
Applied delta patch to 'res://source/entities/player_entities/pinda.gdc' from 'v1.0.4.pck' in 65 μs (5 μs I/O, 59 μs decoding).
Applied delta patch to 'res://.godot/exported/133200997/export-4810a76f52cab761a40b217606f3b3f7-world.scn' from 'v1.0.2.pck' in 27 μs (8 μs I/O, 18 μs decoding).
Applied delta patch to 'res://.godot/exported/133200997/export-4810a76f52cab761a40b217606f3b3f7-world.scn' from 'v1.0.4.pck' in 21 μs (5 μs I/O, 16 μs decoding).
Applied delta patch to 'res://source/entities/player_entities/pinda.gdc' from 'v1.0.2.pck' in 125 μs (9 μs I/O, 116 μs decoding).
Applied delta patch to 'res://source/entities/player_entities/pinda.gdc' from 'v1.0.4.pck' in 68 μs (7 μs I/O, 61 μs decoding).
Applied delta patch to 'res://.godot/imported/SL-fence-boulders.gltf-8f9ed2988aaf279616f03b0bd45b9280.scn' from 'v1.0.4.pck' in 10 μs (6 μs I/O, 4 μs decoding).
Applied delta patch to 'res://.godot/exported/133200997/export-293680cc51e9cd0486e497a8eb604d9d-stone_wall_snowy.res' from 'v1.0.4.pck' in 5 μs (3 μs I/O, 2 μs decoding).
Applied delta patch to 'res://.godot/imported/stone_plateau_albedo.png-4e0e64b2e65449c1344dc953e684fdd1.s3tc.ctex' from 'v1.0.4.pck' in 1858 μs (46 μs I/O, 1811 μs decoding).
Applied delta patch to 'res://.godot/imported/LI-bush_001.gltf-40b8180f1a8db565195bb533fe5b3b60.scn' from 'v1.0.4.pck' in 8 μs (4 μs I/O, 4 μs decoding).
Applied delta patch to 'res://.godot/exported/133200997/export-e17e8915be33ba3caa7e4c702c918edc-bush.res' from 'v1.0.4.pck' in 4 μs (3 μs I/O, 1 μs decoding).
Applied delta patch to 'res://.godot/imported/LI-bush_small_002.gltf-4c9d050b1c074ff3d5423d3e5923b648.scn' from 'v1.0.4.pck' in 9 μs (5 μs I/O, 4 μs decoding).
Applied delta patch to 'res://.godot/imported/LI-bush_002.gltf-046eef6042349a872843bd2bad57871d.scn' from 'v1.0.4.pck' in 7 μs (4 μs I/O, 3 μs decoding).
Applied delta patch to 'res://.godot/imported/LI-bush_003.gltf-d8b6330d3fbe3be54b19ef784d826f6f.scn' from 'v1.0.4.pck' in 7 μs (4 μs I/O, 3 μs decoding).
Applied delta patch to 'res://.godot/imported/LI-bush_small_003.gltf-c5f1b275891f4c31b9784b8fc30cad59.scn' from 'v1.0.4.pck' in 7 μs (4 μs I/O, 3 μs decoding).
Applied delta patch to 'res://.godot/imported/LI-bush_004.gltf-44dfe26583b38b9bacbc865c65056616.scn' from 'v1.0.4.pck' in 7 μs (4 μs I/O, 3 μs decoding).
Applied delta patch to 'res://.godot/imported/LI-bush_small_001.gltf-fd7ac3b286c919a158b306ecbdb65c35.scn' from 'v1.0.4.pck' in 6 μs (4 μs I/O, 2 μs decoding).
Applied delta patch to 'res://.godot/imported/LI-bush_foliage_top_004.gltf-7b5bd6068a817dd027a42f82d80e22ea.scn' from 'v1.0.4.pck' in 5 μs (4 μs I/O, 1 μs decoding).
Applied delta patch to 'res://.godot/imported/LI-stone_wall_008.gltf-624b84d84206001949001db0306e0295.scn' from 'v1.0.4.pck' in 9 μs (5 μs I/O, 4 μs decoding).
Applied delta patch to 'res://.godot/exported/133200997/export-8751d5cceb104760e2f281683e020794-stone_wall.res' from 'v1.0.4.pck' in 5 μs (4 μs I/O, 1 μs decoding).
Applied delta patch to 'res://.godot/imported/LI-stone_wall_007.gltf-a3603ba590e9d8f97ea68bbb95e0a776.scn' from 'v1.0.4.pck' in 9 μs (5 μs I/O, 4 μs decoding).
Applied delta patch to 'res://.godot/imported/LI-stone_wall_006.gltf-d1dd2bfefcf060652e63c3d0e5781138.scn' from 'v1.0.4.pck' in 11 μs (5 μs I/O, 6 μs decoding).
Applied delta patch to 'res://.godot/imported/LI-stone_wall_005.gltf-b3c147109498a6276fff778d55741fda.scn' from 'v1.0.4.pck' in 20 μs (7 μs I/O, 13 μs decoding).
Applied delta patch to 'res://.godot/imported/LI-stone_wall_004.gltf-dfd11977b987307e51beb8311c1ce28c.scn' from 'v1.0.4.pck' in 17 μs (6 μs I/O, 11 μs decoding).
Applied delta patch to 'res://.godot/exported/133200997/export-99b6d6e785812c481ec56f0c19253d65-pine_cuts_atlas_albedo_01.res' from 'v1.0.2.pck' in 8 μs (6 μs I/O, 2 μs decoding).
Applied delta patch to 'res://.godot/imported/SL-fence-vegetation.gltf-2b0c3486f9d852252ed746c8c54f60c9.scn' from 'v1.0.4.pck' in 25 μs (6 μs I/O, 17 μs decoding).
Applied delta patch to 'res://.godot/imported/LI-stone_wall_0011.gltf-ae3bd59c7d1d082cdb0fdb86508668ed.scn' from 'v1.0.4.pck' in 10 μs (6 μs I/O, 4 μs decoding).
Applied delta patch to 'res://.godot/imported/LI-stone_wall_010.gltf-2362d3699279fcc9458103e49cc790e8.scn' from 'v1.0.4.pck' in 6 μs (4 μs I/O, 2 μs decoding).
Applied delta patch to 'res://.godot/imported/LI-stone_wall_009.gltf-1e8816b13883295f833fb7319071709f.scn' from 'v1.0.4.pck' in 8 μs (5 μs I/O, 3 μs decoding).
Applied delta patch to 'res://.godot/exported/133200997/export-75cc15c6f96624c92a89cd4ea423aab0-SE-clearing.scn' from 'v1.0.2.pck' in 17 μs (8 μs I/O, 9 μs decoding).
Applied delta patch to 'res://.godot/imported/LI-stone_wall_012.gltf-e8446df129f613e4df46c3cdf8589041.scn' from 'v1.0.4.pck' in 11 μs (6 μs I/O, 5 μs decoding).
Applied delta patch to 'res://.godot/imported/SL-clearing-bushes.gltf-47565441b9825109bba0dbc787560a44.scn' from 'v1.0.4.pck' in 24 μs (10 μs I/O, 14 μs decoding).
Applied delta patch to 'res://.godot/imported/SL-clearing_terrain.gltf-6c7bfff97231b94de231cd87b0a043cc.scn' from 'v1.0.2.pck' in 169 μs (40 μs I/O, 129 μs decoding).
Applied delta patch to 'res://.godot/imported/SL-clearing_shrubs.gltf-d979ffa9eda7d4d041d54adcf325b78a.scn' from 'v1.0.4.pck' in 13 μs (8 μs I/O, 5 μs decoding).
Applied delta patch to 'res://.godot/exported/133200997/export-6d7bc4d39f8b5352d8abad820bf44d70-chocomel.scn' from 'v1.0.4.pck' in 12 μs (7 μs I/O, 5 μs decoding).
Applied delta patch to 'res://source/entities/player_entities/chocomel.gdc' from 'v1.0.4.pck' in 79 μs (7 μs I/O, 71 μs decoding).
Applied delta patch to 'res://source/entities/camera_magnet_zone.gdc' from 'v1.0.4.pck' in 11 μs (8 μs I/O, 3 μs decoding).
Applied delta patch to 'res://.godot/imported/PR-traffic_cone.gltf-fe0a84d532dd8a51f807efa767a4fb5e.scn' from 'v1.0.4.pck' in 10 μs (5 μs I/O, 5 μs decoding).
Applied delta patch to 'res://.godot/exported/133200997/export-3943d6ae2e8b37b6d9da82a68c5f8ec7-traffic_cone.res' from 'v1.0.4.pck' in 4 μs (3 μs I/O, 1 μs decoding).
Applied delta patch to 'res://source/entities/player_entities/camera.gdc' from 'v1.0.4.pck' in 34 μs (5 μs I/O, 29 μs decoding).
Applied delta patch to 'res://source/entities/player_entities/chocomel.gdc' from 'v1.0.4.pck' in 71 μs (6 μs I/O, 64 μs decoding).

Potential improvements

  • Have the include/exclude filtering use the actual resource paths rather than the exported paths.
  • Provide some other way than --verbose for logging delta encoding details during export.
  • Add profiling monitors for time spent applying patches.
  • Emit warnings during export if compression is enabled on applicable resource types.
  • Provide an export setting for actually caching patched resources in the user:// folder.

@mihe mihe force-pushed the delta-encoding-zstd branch from b020c16 to 8661ce6 Compare October 25, 2025 12:38
@fire
Copy link
Member

fire commented Oct 25, 2025

Have the include/exclude filtering use the actual resource paths rather than the exported paths.

For a future pull request, I think the dependency code for checking resources is broken, it might be working or not. The best way to save sizes is to not include a resource into a pck.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add ability to export only the difference between two files

2 participants