Skip to content

Options files

Alejandro González edited this page Apr 6, 2022 · 54 revisions

This document is for PackSquash version v0.3.1. Different versions may use a different set of options that are not compatible with each other. If you are using an older version, please refer to the documentation appropriate for that version, as listed in the table below:

Version Options files documentation
v0.3.0 https://github.com/ComunidadAylas/PackSquash/wiki/Options-files/1bf83590c971446817ca4a1ba718c98036a9f1b8
v0.2.1 https://github.com/ComunidadAylas/PackSquash/wiki/Options-files/ba9eb71a23ba0e446f8aec7ba0e2aa092641b6b0

Table of contents

Introduction

PackSquash requires options to be explicitly configured to function. These options are read from TOML v0.5.0 documents that contain specific keys and tables. TOML is expected to be easy for humans to read and easy for programs to parse and generate. It shares some similarities with the well-known format INI, but TOML has an authoritative specification and is more expressive.

PackSquash can parse these TOML documents from two sources:

  • From a file. The TOML document with options thus becomes the so-called options file. The path of the options file to read is passed as a command-line parameter. Options files are the recommended way for end-users to store, exchange, and make PackSquash use a set of options.
  • From its standard input stream (usually, the user keyboard or pipe). This source is used if PackSquash is not passed a path in its command line parameters or if the path is a hyphen ("-"). Reading options from the standard input is suitable for making PackSquash consume the output of another program (piping) or advanced interactive usage.

The only required option is pack_directory. The following sections describe in detail all the options you can customize. If they are too dense for you, or you aren't sure how an option works, you may find the examples at the end of this document useful to get started.

Global options

The global options are key and value pairs that control what pack is processed and how. They belong outside of any table (i.e., before any table begins). PackSquash rejects options files that contain global options not described in this section to improve extensibility. This section describes such available options.

pack_directory

Type: String

Default value: none (required)

The absolute or relative path to the directory where the pack that will be optimized resides.

If you use a literal string (i.e., surround the path with single quotes, 'like this') you won't need to escape any characters, but you won't be able to write paths that contain a single quote. On the other hand, if you use basic strings (i.e., surround the path by double quotes, "like this"), you will need to escape double quotes, backslashes, and other special characters defined by the TOML specification, but you will be able to write paths that contain a single quote. For more details about how strings are parsed, please read the TOML specification.

Example:

pack_directory = 'C:\path\to\pack'

output_file_path

Type: String

Default value: pack.zip (file pack.zip in the current working directory)

The absolute or relative path to the ZIP file that contains the optimized pack that PackSquash will generate. This path must point to a file that may already exist or not, but never to a directory.

If the ZIP file indicated by this path already exists, PackSquash may try to open and use it to generate a new version, depending on the values of the zip_spec_conformance_level and never_store_squash_times options. Please read their description for more details.

Example:

output_file_path = 'C:\path\to\result\pack\zip\file\my_pack.zip'

recompress_compressed_files

Type: Boolean

Default value: false

If true, this option makes PackSquash try to compress files whose contents are already compressed before adding them to the generated ZIP file, after all the file type-specific optimizations have been applied. This can squeeze in some extra savings at the cost of noticeably increased pack processing times. Ogg and PNG assets are the only already compressed files affected by this option.

Example:

recompress_compressed_files = true

zip_compression_iterations

Type: Integer in the [0, 255] interval

Default value: 20

The number of Zopfli compression iterations that PackSquash will do when compressing a file of 1 MiB magnitude just before it is added to the generated ZIP file. This affects files whose contents are not already compressed or all files if recompress_compressed_files is enabled.

A higher number of iterations means that bigger files will be subject to more compression iterations, which may lead to higher space savings but is slower. Lower numbers imply that, in general, fewer compression iterations will be done, which is quicker but reduces space savings.

Note that PackSquash calculates the exact number of iterations for a file depending on its size, so this number of iterations only guides that computation. More precisely, PackSquash targets a reference compression time, so smaller files will be compressed more, and larger files will be compressed less. Also, the file size is converted into a non-linear magnitude that grows slower than the file size itself (in mathematical terms, the order of the function is that of a fractional power, which is less than linear), and this magnitude is what is really used to compute the number of iterations. A consequence of this design is that PackSquash will be "hesitant" to reduce the number of iterations for bigger files to meet the target time, exceeding it, but not by too much.

Unless set to zero, the number of iterations is clamped to the [1, 20] interval, so using values outside that interval for this option will only change the magnitude threshold where iterations start being reduced to meet a target time.

Zero is a special case: no file will be compressed, no matter its size. This is useful to speed up the process without sacrificing file-specific optimization techniques. It might also speed up the loading of your pack by Minecraft clients because they won't have to decompress any file, which is a bottleneck, especially with the advent of fast storage devices. The obvious downside is that the generated ZIP files will likely be larger, which increases bandwidth requirements. However, if the decompression speed is much greater than the storage device speed (i.e., a beefy CPU is paired with a slow HDD, for example), Minecraft clients may take longer to load the pack.

Example:

zip_compression_iterations = 5

automatic_minecraft_quirks_detection

Type: Boolean

Default value: true

When this option is set to true, PackSquash will try to automatically deduce an appropriate set of Minecraft quirks that affect how pack files can be optimized by looking at the pack files. This automatic detection works fine in most circumstances, but because quirks affect specific Minecraft versions, and maybe only under some conditions, it might be inexact.

If you exactly know what quirks affect your pack and do not want PackSquash to come up with its own set of quirks to work around, set this option to false, and configure work_around_minecraft_quirks accordingly. Otherwise, you can leave it set to true.

Please note that the automatic Minecraft quirks detection may validate and process the contents of the pack.mcmeta file, even if validate_pack_metadata_file and automatic_asset_types_mask_detection are set to false. To prevent PackSquash from validating that file, these options should be all set to false.

Example:

automatic_minecraft_quirks_detection = true

work_around_minecraft_quirks

Type: Array of String

Default value: [] (empty array; no quirks worked around, unless automatic_minecraft_quirks_detection is set to true and quirks were detected)

Some Minecraft versions have some quirks that limit how some files can be compressed before they stop being interpreted correctly by the game. PackSquash can work around these quirks, but doing so may come at the cost of reduced space savings, increased processing times, or other undesirable consequences, so such workarounds should only be done if a pack is affected by them. This option allows to manually specify a comma-separated list of quirks that will be worked around if automatic_minecraft_quirks_detection is set to false. The following quirks are supported:

  • grayscale_images_gamma_miscorrection: older versions of Minecraft (probably all versions since 1.6 until 1.13 are affected) assume that grayscale images are in a fairly uncommon color space instead of the more common sRGB space presumed for the rest of color types. Because PackSquash can compress full-color images that only have gray pixels to actual grayscale format to save space, affected Minecraft versions display those images with colors that look "washed out". The workaround implemented for this quirk stops PackSquash from trying to reduce color images to grayscale format under any circumstances, which may hurt compression.
  • restrictive_banner_layer_texture_format_check: older versions of Minecraft (probably all versions from 1.6 until 1.13 are affected) require banner and shield layer textures to be stored in RGBA format, or else the layers they represent won't be applied at all, even if the palette contains transparency data. PackSquash can convert images encoded in RGBA format to palette format to save space, triggering this quirky behavior in affected versions. This workaround stops PackSquash from changing the color format of the affected textures to a palette, which includes color quantization, as it is used to generate a palette. This incurs some space costs.
  • bad_entity_eye_layer_texture_transparency_blending: all currently known Minecraft versions overlay entity layer textures in a way that does not rightly account for transparency, taking into account their color and not only their transparency values as blending coefficients to use for overlying that texture (see MC-235953). PackSquash can change the color of transparent pixels, triggering this behavior. This workaround stops PackSquash from changing the color of transparent pixels and quantizing the pixels to a palette to reduce texture file size, as both optimizations do not guarantee that the color of transparent pixels will stay the same.
  • java8_zip_parsing: the latest Minecraft versions, from 1.17 onwards, are compiled for Java 16+, which means that they do not support older Java versions. On the other hand, Java 8 was used almost ubiquitously with older Minecraft clients, especially in modded environments. However, a lot of things have changed in newer Java versions, including low-level details of how ZIP files are parsed. When a ZIP specification conformance level that adds extraction protection is used, this workaround tells PackSquash to use obfuscation techniques that work fine with Java 8. This comes at the cost of protection that is a bit different, but the small differences will extremely likely not matter in protection strength. Compressibility can be impacted negatively, though. This quirk does not have any effect if an affected ZIP specification conformance level is not chosen or if the Minecraft client is run using newer Java versions.

When automatic_minecraft_quirks_detection is set to true, PackSquash will use an automatically detected set of quirks no matter what, ignoring the value of this option.

Example:

work_around_minecraft_quirks = ['grayscale_images_gamma_miscorrection', 'restrictive_banner_layer_texture_format_check', 'bad_entity_eye_layer_texture_transparency_blending', 'java8_zip_parsing']

automatic_asset_types_mask_detection

Type: Boolean

Default value: true

By default, PackSquash will attempt to automatically deduce the appropriate set of pack files to include in the generated ZIP by checking what Minecraft versions it targets, according to the pack format version. This works fine in most circumstances and saves space if the pack contains legacy or too new files for the targeted Minecraft version, but it might be undesirable sometimes.

If you want PackSquash to include every pack file it recognizes and is enabled in allow_mods no matter what, set this option to false. Otherwise, leave it set to true to let it exclude files that are known to be not relevant.

When this option is set to true, the pack.mcmeta file may be read and validated, even if validate_pack_metadata_file and automatic_minecraft_quirks_detection are set to false. To guarantee that file is not read no matter what, these options should be all set to false.

Example:

automatic_asset_types_mask_detection = true

allow_mods

Type: Array of String

Default value: [] (empty array; skip all mod-specific files)

PackSquash supports pack files that are only consumed by certain Minecraft mods, but, in the interest of optimizing packs as much as possible, it assumes that mod-specific files will not be used by the game by default and discards (skips) them from the generated ZIP file. This will break your pack unless you tell PackSquash about the involved mods via this option, whose value is a comma-separated list of mod identifiers. The following mods are supported:

  • OptiFine: adds support for Java properties files used by several of its features (.properties) and Custom Entity Model files (.jem, .jemc, .jpm, and .jpmc). It also accepts and optimizes vanilla models in the custom item feature files directory.
  • Minecraft Transit Railway 3: adds support for Blockbench modded entity model projects for custom train models (.bbmodel and .bbmodelc) in the mtr asset namespace.

Example:

allow_mods = ['OptiFine', 'Minecraft Transit Railway 3']

This option is only supported if PackSquash was compiled with support for mods, which always is the case if you use a PackSquash build downloaded from this repository.

skip_pack_icon

Type: Boolean

Default value: false

Under some circumstances, the pack.png pack icon won't be shown in the Minecraft UI, even if it is present. Therefore, skipping it will save space without any side effects if the pack is to be used only under these circumstances. If this option is set to true, the pack.png file that contains the pack icon will not be added to the generated ZIP file.

In all Minecraft versions where this was tested, which include 1.16.3 and 1.17.1, pack icons are not shown for server resource packs.

Example:

skip_pack_icon = true

validate_pack_metadata_file

Type: Boolean

Default value: true

This option controls whether the pack metadata file, pack.mcmeta, will be validated (true) or not (false). Validating this file is a good thing in most circumstances, and you should only disable this option if you are extremely concerned about performance, need to add a pack.mcmeta file to the generated ZIP file later, want to use PackSquash with folders that are not a Minecraft pack, or similar reasons.

Even if this option is set to false, the pack.mcmeta may still be validated if automatic_minecraft_quirks_detection or automatic_asset_types_mask_detection are enabled. To guarantee that the pack metadata file is not validated no matter what, both options should be set to false.

Example:

validate_pack_metadata_file = true

ignore_system_and_hidden_files

Type: Boolean

Default value: true

This option controls whether PackSquash will ignore system (i.e., whose name signals they were generated by a ubiquitous and well-known program that is not related to a Minecraft pack) and hidden files (i.e., whose name starts with a dot), not printing status messages about them, nor even trying to process them. If true, these files will be ignored. If false, these files will not be treated specially and will be processed as normal. Ignoring these files is usually a good thing to do unless your pack really contains files that are filtered out by this option.

Example:

ignore_system_and_hidden_files = false

zip_spec_conformance_level

Type: String

Default value: pedantic

PackSquash uses a custom ZIP compressor that is able to balance ZIP file specification conformance and interoperability with increased performance, space savings, compressibility, and protection against external programs being able to extract files from it. This option lets you choose the ZIP specification conformance level that is most suitable to your pack and situation. The following levels are available:

  • pedantic: the generated ZIP files will follow the ZIP file specification to the letter, with the objective that they can be used with virtually any ZIP file manipulation program. This is a safe and user-friendly default, but it has a big downside: PackSquash can't do anything that may render the ZIP files it generates unconventional. This means that identical files after file type-specific optimizations will not be stored only once (i.e., deduplicated), the generated ZIP files will not contain the metadata needed to reuse them in future runs to speed up execution, files will be able to be extracted from them as normal, and compressibility of the ZIP file internal structures will not be improved. Anyway, you still get file type-specific optimizations, Zopfli compression, and metadata removal in both the generated ZIP and the pack file, which usually have a big impact on pack sizes.
  • high: similar to pedantic, but it allows storing the metadata needed to reuse the generated ZIP files in future PackSquash runs. This metadata is stored in a way that is compatible with the vast majority of ZIP file manipulation programs, although it technically does not conform to the ZIP file specification, so, while it is technically possible to find a program that rejects the file, in practice that is highly unlikely.
  • balanced: like high, but enables deduplication of identical files in the generated ZIP file. This yields significant space savings if somewhat big files are repeated in your pack, like textures or sounds, although it also helps with smaller files. Some ZIP file manipulation programs will still properly work when files are deduplicated, while others will not, so while this has a significant impact on interoperability, how that matters to you depends on what programs you expect to use with the ZIP file.
  • disregard: PackSquash will use every trick up its sleeve to give you every feature it offers, including extraction protection and improved internal ZIP file structures compressibility, without any consideration for interoperability whatsoever. The only constraint is that the pack works as usual within Minecraft.

The following table summarizes and compares what each available conformance level offers.

pedantic high balanced disregard
File type-specific optimizations
Zopfli compression
Metadata removal*1
Identical file deduplication
Extraction protection*2
Improved internal ZIP file structures compressibility*3
Programs that can manipulate the output ZIP file Any The vast majority of programs Select programs As few as possible
Levels whose output ZIP files can be reused with this level*4 high, balanced high, balanced disregard
Appropriate for Using PackSquash for the first time, doing backups, permissively licensed packs, trusting the users of your pack, and fostering collaboration and innovation Similar use cases as pedantic, but you want to take advantage of reusing previous ZIP files Similar use cases as high, but you want file deduplication too Proprietary packs whose usage you want to limit, especially for public server resource packs; just getting the best optimization possible

*1 Metadata removal includes non-critical PNG headers, Vorbis comments and ID3 tags, and filesystem metadata such as creation time, modification time, permissions, and proprietary user. This improves privacy and reduces file sizes.

*2 Due to Minecraft limitations, extraction protection is done using techniques that are not considered secure by modern information security standards (more specifically, they do not hold the Kerckhoffs's principle). In order words, it is not reasonable to expect strong security guarantees from this protection.

*3 Compressibility improvements do not reduce the actual size of the generated ZIP files. However, they allow for higher savings if the generated ZIP files are compressed again. This is useful when serving packs over an HTTP server with static compression enabled because it reduces bandwidth requirements, transparently compressing and decompressing the pack while it is being downloaded.

*4 In general, you should be careful when you try to reuse a generated ZIP file to speed up the optimization of a pack if you do any modification to the options file, update PackSquash, move that file between devices, modify it outside of PackSquash, or the set of Minecraft quirks to work around changes. Failure to follow this advice may lead to the generation of incorrect ZIP files in ways that may not be immediately obvious. Just changing the conformance level to another that is compatible with the level used in the previous run is fine, however. It is also okay to reuse a generated ZIP file as many times as desired if you don't change anything. These are the catches you should keep in mind:

  • First of all, you may set the never_store_squash_times option to a value that does not save the metadata needed to reuse ZIP files, independently of the conformance level. You should not reuse ZIP files that were generated with this option enabled (i.e., set to true) after you disable it (i.e., set it to false). Doing the opposite thing (i.e., from false to true) is fine, but that will end up not reusing the ZIP file.
  • Any change to an option that affects how files are compressed or optimized will not be applied for non-modified files because they will not be processed again.
  • If the set of Minecraft quirks to work around changes, either because PackSquash detects that the pack was upgraded or downgraded to work with another Minecraft version or you've explicitly set them to a different value, the change will not be applied for non-modified files.
  • PackSquash quickly detects whether a file was modified or not by looking at the modification timestamp provided by the filesystem and comparing it with an encrypted timestamp stored in the ZIP file. The encryption key used is device-specific (see the documentation on system identifiers for more information). If modification timestamps are not available or reliable, this detection may not work as expected (this usually is not the case unless you copy files between partitions or devices, though).
  • You should not modify otherwise reusable generated ZIP files outside of PackSquash. Doing so may change the file structure or timestamp metadata in ways that PackSquash doesn't expect. You can copy the generated file around and read or extract files from it.
  • Some effort is made to make ZIP files generated in the current version of PackSquash compatible with future versions, but this compatibility is by no means guaranteed. It is best to start from scratch after updating PackSquash unless you validate that the versions are compatible.
  • Reusing ZIP files that were generated with size_increasing_zip_obfuscation set to false after it is changed to true, and vice versa, is not safe. Trying to do so will, in the best-case scenario, end up not reusing the ZIP file at all, and in the worst-case scenario, corrupting data.

With these gotchas out of the way, to reuse a ZIP file that was previously generated by PackSquash, it suffices to set output_file_path to the path of that file. The previous version of the file will be overwritten after the pack is processed.

Example:

zip_spec_conformance_level = 'high'

size_increasing_zip_obfuscation

Type: Boolean

Default value: false

If zip_spec_conformance_level is set to disregard, enabling this option will add more protections against inspecting, extracting, or tampering with the generated ZIP file that will slightly increase its size. This option does not affect whether protections that do not increase the file size are added or not and does not have any effect if the conformance level does not feature protection.

Example:

size_increasing_zip_obfuscation = true

percentage_of_zip_structures_tuned_for_obfuscation_discretion

Type: Integer in the [0, 100] interval

Default value: 0

If zip_spec_conformance_level is set to disregard, this option sets the approximate probability for each internal generated ZIP file structure to be stored in a way that favors additional discretion of the fact that protection techniques were used, as opposed to a way that favors increased compressibility of the result ZIP file. This option is ignored for other conformance levels.

When this option is set to 0 (minimum value), every ZIP record will be stored favoring increased compressibility. Conversely, when it is set to 100 (maximum value), every ZIP record will be stored favoring increased discretion. Other values combine increased discretion and compressibility.

Example:

percentage_of_zip_structures_tuned_for_obfuscation_discretion = 100

never_store_squash_times

Type: Boolean

Default value: false

This option controls whether PackSquash will refuse to store the metadata needed to reuse previously generated ZIP files, and likewise not expect such data if the output ZIP file already exists, thus not reusing its contents to speed up the process in any way, no matter what the zip_spec_conformance_level is.

You might want to set this to true if you are concerned about the presence of encrypted metadata in the generated ZIP files, do not care about potential speedups in later runs, file modification timestamps are unreliable for some reason, or do not want PackSquash to get and use a system ID in any way. In fact, if PackSquash will not be run anymore on this pack, it is a good idea to set this to true, as this improves compressibility a bit and removes the now unnecessary metadata.

Example:

never_store_squash_times = true

threads

Type: Integer greater than zero

Default value: number of available physical CPU threads

The maximum number of concurrent threads that PackSquash will use to process the pack files. Higher numbers can spawn more threads, so if your computer has enough physical CPU threads, several files can be processed at once, improving the speed substantially. However, you might want to use a lower number of threads due to memory, power consumption, or CPU time limitation concerns. This number is tentative, meaning that PackSquash may spawn extra threads for internal purposes.

Example:

threads = 4

spooling_buffers_size

Type: Integer greater than or equal to zero

Default value: half of the available main memory reported by the operating system / (number of available physical CPU threads + 1)

The maximum size of the in-memory buffers that temporarily hold data to be written to the generated ZIP file, in MiB. Ideally, if the buffers are big enough to hold the entire ZIP file and any additional scratch data, PackSquash will work almost entirely in memory and not do any disk operation, which is pretty fast. However, if some buffer grows bigger than this size threshold, it has to be rolled over to disk, which usually is much slower to operate with than main memory, because otherwise PackSquash could run out of available memory and be forced to abort its execution, which is a bad thing. The default value is meant to be an educated guess of the optimum value, taking into account the installed physical memory (RAM), the size of the pagination file or swap, the amount of memory currently used by other applications, that other applications may be launched or increase their memory demands while PackSquash executes, and the fact that PackSquash uses a buffer for each thread that processes packs + one for the generated ZIP file.

If you run into out-of-memory errors while executing PackSquash, try decrementing this value to be able to use it without such problems. Conversely, if you observe that PackSquash disk usage suddenly rises notably and there is enough available memory to spare, try incrementing this value for maximum performance.

Example:

spooling_buffers_size = 128

open_files_limit

Type: Integer greater than zero

Default value: 512

The tentative maximum number of files that PackSquash will keep open at the same time. The default value is a conservative limit that should be almost always fine, but if lots of threads are spawned to process lots of pack files, there can be problems because most operating systems limit the number of open files a process can have at the same time.

Under normal circumstances, you should only reduce this value if you hit the open files limit. Conversely, you should only increase it if you are sure that your operating system is fine with that fact and threads is smaller than or equal to this value. Otherwise, the concurrency will be effectively limited by the maximum number of files that can be opened.

Example:

open_files_limit = 256

Per-file options

PackSquash supports customizing how several pack file types are compressed, on a per-file basis, via tables. Tables represent a group of options that are applied to the files whose relative path matches a extended glob pattern syntax contained in the table name.

For matching, the path component separator is normalized to a forward slash (/), so the configuration files are operating system agnostic. Also, the * and ? metacharacters can never match a path separator. The backslash character may be used to escape special characters.

For example, you can match any files inside a "music" or "ambience" folder that have a non-empty name and an audio file extension with the following pattern:

**/{music,ambience}/?*.{og[ga],mp3,wav,flac}

Another example that matches the same files as before, but only when they are in the "music" or "ambience" folders of a resource pack assets folder is:

assets/*/sounds/{music,ambience}/?*.{og[ga],mp3,wav,flac}

Keep in mind that if your pattern contains a dot or characters that are not ASCII letters, ASCII digits, underscores, and dashes (A-Za-z0-9_-), you will need to put them in a string (i.e., between single quotes, like 'this') when writing the table name in the options file.

Of course, different file types require different options. PackSquash will detect on the fly the file type the configuration you write is intended for. If several patterns match a single file, PackSquash will use the first one that customizes options appropriate for the file type, and if no pattern is appropriate or no pattern matches, use default options. There is a list of options you can change per file type below.

Audio files

You can customize how PackSquash transcodes the audio files of a pack via the following key and value pairs.

These options are only supported if PackSquash was compiled with support for audio transcoding, which always is the case if you use a PackSquash build downloaded from this repository. When support for audio transcoding is compiled out, only Ogg files will be accepted, and they will just be copied over.

transcode_ogg

Type: Boolean

Default value: true

When true, Ogg files will be reencoded again to apply resampling, channel mixing, pitch shifting, and bitrate reduction, which may degrade their quality, but commonly saves quite a bit of space. If you change it to false, Ogg files will be added to the generated ZIP file without being reencoded or modified. Non-Ogg audio files will be reencoded no matter the value of this option.

Example:

transcode_ogg = false

channels

Type: Integer greater than zero

Default value: number of channels of the input audio data

Specifies the number of audio channels that the processed audio file will have in the generated ZIP file. Values different to 1 (mono) or 2 (stereo) make little sense to use with current versions of Minecraft. As per MC-146721, Minecraft computes positional sound effects depending on whether sounds are mono or stereo, so even though mono sounds are more space-efficient (because they contain half the samples), downmixing stereo sounds to mono or upmixing mono sounds to stereo has side effects.

It should be noted that, although mono files contain half the audio data than stereo ones, this does not necessarily translate to half the space savings. The Vorbis codec used in Ogg files employs joint encoding, which encodes several audio signals as the data needed to reconstruct them from one main signal, and that is pretty efficient for common sounds.

Example:

channels = 2

sampling_frequency

Type: Integer greater than zero

Default value: 32000

Specifies the sampling frequency (i.e., number of samples per second) to which the input audio file will be resampled (in Hertz, Hz). If this frequency is higher than the sampling frequency of the input audio file, the resampling will be skipped to avoid wasting space with redundant samples.

As per the Nyquist-Shannon theorem, for a given sampling frequency of 𝑥 Hz, only frequencies up to 𝑥 ÷ 2 Hz can be recreated without aliasing artifacts, in general. Human speech typically employs frequencies up to 6 kHz, so a sampling frequency of 12 kHz saves space while still providing acceptable audio quality. However, other sounds (e.g., music) have a broader frequency spectrum, up to 20 kHz (the generally accepted upper limit of the human hearing range). Therefore, in any case, a frequency greater than 40 kHz (or 44.1 kHz, due to technical reasons) is wasteful for encoding audio that will be heard by humans and is not meant to be edited any further. The default value, 32000 Hz, is meant to sound faithful to vanilla sounds that have a wide frequency spectrum while still providing significant savings.

Example:

sampling_frequency = 44100

target_pitch

Type: Float

Default value: 1.0

Sets the in-game pitch shift coefficient that will result in the audio being played back at its original speed, affecting the perceived pitch and tempo. This coefficient is specified as an argument to the playsound command and other places where Minecraft accepts a sound pitch number. For values smaller than 1, the audio stored in the generated ZIP file will be sped up, so it has less duration, and the generated file is smaller. Conversely, for values larger than 1, the audio file will be slowed down, be longer, and thus bigger. A value that exactly is one does not modify the audio.

Changing the sampling frequency is a better way to save space than using this option. The effect on audio quality and file size that this option has is similar to lowering or increasing the sampling rate by the same factor. However, because this option enforces the sound playback to be pitch-shifted for it to sound right, this coefficient can be used as a shared secret, slowing down ripping attempts. Nevertheless, the offered protection is weak: there is a theoretical maximum of 230 keys (i.e., 32-bit IEEE 754 floating-point numbers in (0, 2], the interval accepted by Minecraft), which by itself is not difficult to brute force, and further practical considerations reduce the keyspace significantly.

Example:

target_pitch = 1.5

minimum_bitrate

Type: Integer greater than zero

Default value: 40000

Specifies the minimum bits per second (bps or bit/s) that the Ogg Vorbis encoder will try to use to represent the audio signal. Higher values mean higher quality, but also bigger size.

Example:

minimum_bitrate = 64000

maximum_bitrate

Type: Integer greater than zero

Default value: 96000

Specifies the maximum bits per second (bps or bit/s) that the Ogg Vorbis encoder will try to use to represent the audio signal. Higher values mean higher quality, but also bigger size. The default value, 96 kbit/s, is a somewhat common optimistic threshold for transparent quality.

Example:

maximum_bitrate = 128000

JSON files

You can customize how PackSquash optimizes the .json, .jsonc (JSON with comments), .mcmeta and .mcmetac files of a pack with the following key and value pairs. If allow_mods includes OptiFine, these options also apply to .jem, .jemc, .jpm, and .jpmc files. If allow_mods includes Minecraft Transit Railway 3, these options also apply to custom model files with .bbmodel and .bbmodelc extensions.

minify_json

Type: Boolean

Default value: true

When true, the JSON data will be minified, removing comments and unnecessary whitespace to improve space savings. If this is changed to false, the JSON will be prettified instead, reindenting it and adding spaces that make the content easier to read by humans, which takes more space but ensures consistent formatting. In any case, PackSquash will validate the JSON file.

Example:

minify_json = false

delete_bloat_keys

Type: Boolean

Default value: true

If this option is set to true, PackSquash will delete known-superfluous keys from JSON files, like credits or metadata added by pack authoring tools, that are completely ignored by Minecraft. This improves privacy and space savings. On the contrary, when set to false, those keys will be left as-is in the JSON file.

Example:

delete_bloat_keys = false

always_allow_json_comments

Type: Boolean

Default value: true

If true, PackSquash will allow comments in JSON files whose usual extension does not end with an extra c letter, which explicitly marks the file as having an extended JSON format that may contain comments. If false, comments will only be allowed in JSON files with those specific extensions: .jsonc, .mcmetac, etc.

Example:

always_allow_json_comments = false

PNG files

You can customize how PackSquash optimizes the PNG files of a pack with the following key and value pairs.

image_data_compression_iterations

Type: Integer in the [0, 255] interval

Default value: 5

Sets the number of Zopfli compression iterations that PackSquash will do to compress raw pixel data that amounts to a magnitude of 1 MiB. This option is similar to zip_compression_iterations and is used to feed the same linear model but with different parameters better suited for image compression.

When the number of compression iterations drops to zero, which happens when this option is set to zero or the texture is pretty big, a much faster DEFLATE compression algorithm is used instead of Zopfli. This extra performance may come at the cost of file size. On the other side, the number of iterations is limited to a maximum of 15. Values greater than 15 are still useful for this setting because they change the threshold where iterations start being reduced in order to keep acceptable performance levels.

Example:

image_data_compression_iterations = 15

color_quantization_target

Type: String

Default value: auto

Sets the color quantization target for an image, which affects whether the lossy color quantization process is performed and how. Quantization is useful because it replaces the colors in the image with those in a palette that can fit in a certain bit depth, which helps save space considerably. Higher bit depths can represent more color variety but take more space. Lower bit depths are more space-efficient but may reduce color fidelity because fewer different colors can be represented. The supported color quantization targets are as follows:

  • none: no color quantization will be done at all. This means that PackSquash will only apply lossless optimizations to the image, not changing any visible colors in any way.
  • auto: like eight_bit_depth, but the image will not be color-quantized if PackSquash determines that not doing so is more space-efficient.
  • eight_bit_depth: the image will be reduced to at most 256 colors, which fit in 8 bits. This can only effectively be a lossy process if the input texture is more than 16x16 pixels because 16x16 pixels images contain at most 256 colors.
  • four_bit_depth: the image will be reduced to at most 16 colors, which fit in 4 bits. This halves the per-color storage requirements compared with 8 bits. However, there is only so much you can do with just 16 colors. Textures that are bigger than 4x4 pixels and have color variety will be susceptible to quality loss.
  • two_bit_depth: the image will be reduced to at most four colors, which fit in 2 bits. This halves the per-color storage requirements compared with 4 bits. This quantization target is only practical for extremely simple textures or if you find posterization effects artistically fitting.
  • one_bit_depth: the image will be reduced to at most two colors, which fit in 1 bit. This quantization target is only practical for extremely simple textures or if you find posterization effects artistically fitting.

With the exception of none, all of the targets above use an image-specific palette, and a configurable amount of dithering (see the color_quantization_dithering_level option). auto and eight_bit_depth provide a reasonably good quality while yielding high space savings, even for big textures with plenty of color variety.

Example:

color_quantization_target = 'none'

color_quantization_dithering_level

Type: Float in the [0, 1] interval

Default value: 0.85

The level of dithering that will be applied when quantizing colors. This option has no effect if color_quantization_target is not set to perform color quantization.

Dithering is a technique that improves the perceived color depth of color-quantized images by diffusing the reduced number of available colors in areas that lost color information. The dithered areas appear more as if they had their original colors preserved, reducing color banding artifacts. However, dithering can introduce noisy, hard-to-compress diffusion patterns.

In most images, especially natural-looking ones, color quantization saves enough space to compensate for the decreased dithered areas compressibility, so lots of dithering is a good idea because it gives better-looking results and still reduces file sizes. Extreme counterexamples are big images composed of big constant color blocks whose color is not in the quantized palette: here, dithering would reduce compressibility a lot while yielding a worse look than just completely replacing the color of the blocks, so reducing the dithering level is warranted.

color_quantization_dithering_level = 1

maximum_width_and_height

Type: Integer greater than or equal to zero

Default value: 8192

Sets the maximum width and height of the images that PackSquash will accept without throwing an error. The rationale behind this option is that limiting the size of the images that PackSquash can deal with sets a high bound of memory usage and image processing time, helping authoring efficient packs, and improving the compatibility of the pack with GPUs that only support smaller texture sizes.

In relation to the last point, Minecraft internally builds texture atlases with textures of resource packs, for efficiency reasons (a texture atlas is generated by stitching individual textures together so that they become part of a single larger texture). Assuming a maximum texture size of 65536x65536, 256 individual textures of 4096x4096 would fit in such an atlas, which is a fairly low number and not enough to hold all vanilla textures. Resource packs that replace only a few atlased textures may get away with textures that are even bigger than 4096x4096, but that might only happen on "beefy" GPUs, and, in general, it does not make much sense to mix small textures with such big textures.

It only makes sense to increase the default value if you know what you are doing, the affected images contain several animation frames or are texture atlases themselves, or use mods that somehow relax the need for GPUs to support big textures. If you do not plan on pushing Minecraft to its limits or making high-definition resource packs, setting this to an even lower value than the default is a good thing.

Example:

maximum_width_and_height = 4096

skip_alpha_optimizations

Type: Boolean

Default value: false

If set to true, this option prevents the color values of completely transparent pixels from being changed to achieve better compression. This optimization is visually lossless: completely transparent pixels are invisible no matter their color, and images that lack an alpha channel are not affected. However, if the image is meant to be edited further or contains steganographic data, this optimization may have undesirable side effects. Disabling alpha optimizations also reduces the time it takes to optimize an image, at the cost of a maybe increased file size.

Example:

skip_alpha_optimizations = true

Shader files

You can customize how PackSquash optimizes the .vsh, .fsh, and .glsl files of a pack with the following key and value pairs.

minify_shader

Type: Boolean

Default value: true

When true, the shader source code will be minified, which removes comments and unnecessary whitespace to improve space savings. If you change this option to false, the shader source code will just be added to the generated ZIP file after being validated, without changing its contents at all.

Example:

minify_shader = false

Legacy language files

You can customize how PackSquash optimizes the .lang files used in older resource packs with the following key and value pairs. Please note that these files are only optimized on resource packs that target Minecraft 1.12.2 or older versions unless you set automatic_asset_types_mask_detection to false.

minify_legacy_language

Type: Boolean

Default value: true

If true, the legacy language file will be minified: empty lines and comments will be removed. This saves space and improves parsing performance. If false, the file will still be validated for errors but left as-is. Line endings are normalized to Unix style (using a single LF character) no matter what.

Example:

minify_legacy_language = false

strip_legacy_language_bom

Type: Boolean

Default value: true

If true, the BOM in the first line of the file will be stripped. This usually saves space and avoids user confusion, as the BOM is normally introduced inadvertently, and Minecraft interprets the BOM as a part of the line. Therefore, the BOM may undesirably become part of the key of the first language string, causing it not to work or prevent a comment from being parsed as such.

However, if a pack relies on the BOM being there because it refers to the first language string with a BOM, this behavior might have undesirable consequences. In such cases, set this option to false to leave the BOM alone.

Example:

strip_legacy_language_bom = false

Command function files

You can customize how PackSquash optimizes the .mcfunction files used in data packs with the following key and value pairs.

minify_command_function

Type: Boolean

Default value: true

If true, the command function file will be minified: empty lines and comments will be removed. This saves space and improves parsing performance. If false, the file will still be validated for errors but left as-is. Line endings are normalized to Unix style (using a single LF character) no matter what.

Example:

minify_command_function = false

Properties files

You can customize how PackSquash optimizes the .properties files of a pack with the following key and value pairs. Please note that these files only are processed if allow_mods includes OptiFine.

These options are only supported if PackSquash was compiled with support for the OptiFine mod, which always is the case if you use a PackSquash build downloaded from this repository.

minify_properties

Type: Boolean

Default value: true

When true, the properties will be minified, which removes comments and unnecessary whitespace to improve space savings. If you change this option to false, the properties will not be changed at all, but they will still be validated by PackSquash.

Example:

minify_properties = false

Custom files

Any unknown pack file can be marked as a custom file with the following key and value pairs, making it possible to customize how PackSquash deals with files that would otherwise be inevitably skipped. Please be mindful that this feature does not substitute proper support for files that are read by the game: if you are using it to work around such a missing feature, please let us know by opening an issue or getting in touch over Discord. Custom file options are ignored for files that belong to any known type.

force_include

Type: Boolean

Default value: false

If true, the custom file will be copied to the generated ZIP file as-is, without any specific optimizations. A false value explicitly asks for the default behavior of skipping the file.

Example:

force_include = true

Examples

You can run the examples proposed in this section by copying their contents to a text file, saving it wherever you like, and then launching PackSquash with the path to your options file as the first parameter. To do so, you can use a command prompt or terminal.

On Windows, you can open a command prompt by following these instructions, and then type a command like this (please remember to replace the example paths with the appropriate ones):

"C:\path\to\your\packsquash\executable\packsquash.exe" "C:\path\to\your\settings\file.toml"

Alternatively, if you don't like to type commands in the Windows command prompt, you can create a shortcut that does this for work for you or drag-and-drop the file to the executable. Keep in mind that doing so might complicate troubleshooting, as the PackSquash window will be immediately closed if something goes wrong, and you won't be able to see the error messages that PackSquash has shown.

Of course, you are free to modify these examples to suit your needs better or even create your options files from scratch.

Basic options file

This is a minimal valid options file. It only specifies the pack directory and leaves the rest of the options set to their defaults. The generated ZIP file will be saved at pack.zip in the current directory. We suggest starting with a minimal options file and adding options to it as needed to keep the file smaller, more readable, and easier to upgrade to future PackSquash versions.

pack_directory = 'C:\path\to\pack'

Basic options file with extraction protection

This example is like Basic options file, but it enables PackSquash to do more aggressive ZIP file optimizations, including extraction protection, described in the zip_spec_conformance_level option documentation. However, it might be a bad idea to do these optimizations blindly: they make the ZIP file more cumbersome to work with, the extraction protection is not unbreakable, and they change how PackSquash reuses previously generated ZIP files. Check out the mentioned option documentation for more information.

pack_directory = 'C:\path\to\pack'
zip_spec_conformance_level = 'disregard'

Complex options file

This example options file changes every option that PackSquash offers, just for the sake of doing so. You will probably not need to do this in practice, and some values may be outright inappropriate for you, but this is useful to see how everything is grouped together.

# Lines that start with # are comments, and PackSquash ignores them.
# You can also start a comment in the middle of a line with #, that
# spans until the end of the line

# Global options
pack_directory = 'C:\path\to\pack'
output_file_path = 'C:\path\to\result\pack\zip\file\my_pack.zip'
recompress_compressed_files = true
zip_compression_iterations = 5
automatic_minecraft_quirks_detection = true
# The value of this option is ignored due to automatic quirk detection
# being enabled, but this usually does not matter
work_around_minecraft_quirks = ['grayscale_images_gamma_miscorrection', 'restrictive_banner_layer_texture_format_check', 'bad_entity_eye_layer_texture_transparency_blending', 'java8_zip_parsing']
automatic_asset_types_mask_detection = true
allow_mods = ['OptiFine', 'Minecraft Transit Railway 3']
skip_pack_icon = true
validate_pack_metadata_file = true
ignore_system_and_hidden_files = false
zip_spec_conformance_level = 'high'
# These two are actually ignored due to the ZIP spec conformance level
size_increasing_zip_obfuscation = true
percentage_of_zip_structures_tuned_for_obfuscation_discretion = 100
never_store_squash_times = true
# System dependent values. Use them as-is only if you have a good reason,
# not just because you have copied and pasted this options file
threads = 4
spooling_buffers_size = 128 # MiB
open_files_limit = 256

# Per-file options below

# Ogg files do not get transcoded
['**/*?.ogg']
transcode_ogg = false

# Lossless music files get pitch shifted and compressed with good quality
['**/*?.{flac,wav}']
channels = 2
sampling_frequency = 44100
target_pitch = 1.5
minimum_bitrate = 64000
maximum_bitrate = 128000

# JSON files with comments get prettified and nothing is removed from them
['**/*?.jsonc']
minify_json = false
delete_bloat_keys = false

# Do not allow comments in any JSON file.
# Comments may be an useful JSON extension for documentation purposes, so
# please avoid blindly copying and pasting this unless you really want to
# limit their usage to .jsonc, .jemc, .jpmc, .mcmetac and .bbmodelc files!
['**/*?.{json,jem,jpm,mcmeta,bbmodel}']
always_allow_json_comments = false

# Quantize big natural-looking image, doing the highest quality dither
['assets/craftmine/textures/landscape.png']
color_quantization_target = 'eight_bit_depth'
color_quantization_dithering_level = 1

# Compress other textures losslessly no matter what. Keep them small
['**/*?.png']
image_data_compression_iterations = 15
color_quantization_target = 'none'
maximum_width_and_height = 2048
skip_alpha_optimizations = true

# Don't minify shaders
['**/*?.{fsh,vsh,glsl}']
minify_shader = false

# Don't touch Minecraft 1.12.2 or older language files
['**/*?.lang']
minify_legacy_language = false
strip_legacy_language_bom = false

# Don't minify properties files
['**/*?.properties']
minify_properties = false

# Don't minify an example command function.
# Note that command functions are only accepted in data packs, and
# data packs do not contain other file types shown throughout this
# example file!
['data/craftmine/functions/main.mcfunction']
minify_command_function = false

# Include copyright and authorship information files in any directory.
# More information:
# https://www.gnu.org/prep/maintain/html_node/License-Notices.html
# https://www.gnu.org/prep/maintain/html_node/Recording-Contributors.html
['**/{COPYING,AUTHORS}']
force_include = true