diff options
author | Linnea Gräf <nea@nea.moe> | 2024-11-17 04:01:17 +0100 |
---|---|---|
committer | Linnea Gräf <nea@nea.moe> | 2024-11-17 04:27:36 +0100 |
commit | 430ef35386e79386f84665f6bd8d54c31e45e018 (patch) | |
tree | 44d1471944b6b1954d028189598132ba7f3e53d6 /web/src/pages/docs/texture-pack-format.md | |
parent | a1b2a399efd9ff1c8b3b0dfd71b59c7de28728ea (diff) | |
download | Firmament-430ef35386e79386f84665f6bd8d54c31e45e018.tar.gz Firmament-430ef35386e79386f84665f6bd8d54c31e45e018.tar.bz2 Firmament-430ef35386e79386f84665f6bd8d54c31e45e018.zip |
feat(web): Move over some docs
Diffstat (limited to 'web/src/pages/docs/texture-pack-format.md')
-rw-r--r-- | web/src/pages/docs/texture-pack-format.md | 583 |
1 files changed, 583 insertions, 0 deletions
diff --git a/web/src/pages/docs/texture-pack-format.md b/web/src/pages/docs/texture-pack-format.md new file mode 100644 index 0000000..da66043 --- /dev/null +++ b/web/src/pages/docs/texture-pack-format.md @@ -0,0 +1,583 @@ +<!-- +SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe> + +SPDX-License-Identifier: CC0-1.0 +--> + +# Custom SkyBlock Items Texture Pack Format + +## Items by internal id (ExtraAttributes) + +Find the internal id of the item. This is usually stored in the ExtraAttributes tag (Check the Power User Config for +keybinds). Once you found it, create an item model in a resource pack like you would for +a vanilla item model, but at the coordinate `firmskyblock:<internalid>`. So for an aspect of the end, this would be +`firmskyblock:models/item/aspect_of_the_end.json` (or `assets/firmskyblock/models/item/aspect_of_the_end.json`). Then, +just use a normal minecraft item model. See https://github.com/nea89o/BadSkyblockTP/blob/master/assets/firmskyblock/models/item/magma_rod.json +as an example. The id is first turned to lower case, then gets `:` replaced with `___`, `;` with `__` and all other +characters that cannot be used in a minecraft resource location with `__XXXX` where `XXXX` is the 4 digit hex code for +the character. + +## (Placed) Skulls by texture id + +Find the texture id of a skull. This is the hash part of an url like +`https://textures.minecraft.net/texture/bc8ea1f51f253ff5142ca11ae45193a4ad8c3ab5e9c6eec8ba7a4fcb7bac40` (so after the +/texture/). You can find it in game for placed skulls using the keybinding in the Power User Config. Then place the +replacement texture at `firmskyblock:textures/placedskulls/<thathash>.png`. Keep in mind that you will probably replace +the texture with another skin texture, meaning that skin texture has its own hash. Do not mix those up, you need to use +the hash of the old skin. + +## Armor Skull Models + +You can replace the models of skull items (or other items) by specifying the `firmament:head_model` property on your +model. Note that this is resolved *after* all [overrides](#predicates) and further predicates are not resolved on the +head model. + +```json5 +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "firmskyblock:item/regular_texture" + }, + "firmament:head_model": "minecraft:block/diamond_block" // when wearing on the head render a diamond block instead (can be any item model, including custom ones) +} +``` + +## Tint Overrides + +Some items get naturally tinted by Minecraft's rendering. Examples include leather armour, spawn eggs, potions and more. +If you want to avoid your textures getting tinted, one thing you can do is use a higher texture layer: + +```json +{ + "parent": "minecraft:item/generated", + "textures": { + // Notice the layer1 instead of layer0 here + "layer1": "firmskyblock:item/regular_texture" + } +} +``` + +Some items, however, tint *all* layers. For those items you can instead specify a tint override: + +```json +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "firmskyblock:item/regular_texture" + }, + "firmament:tint_overrides": { + "0": -1 + } +} +``` + +This forces layer 0 to be tinted with the color `-1` (pure white, aka no tint). This property is inherited, so if you +attach it to one of your root models that you `"parent"` other models to, all those models will have their tints +overridden. When the property is inherited, only layers specified in the child actually overwrite the parent layers. +You can use `"0": null` to remove the tint override in a child, which will cause a fallback to the vanilla tinting +behaviour. + +## Predicates + +Firmament adds the ability for more complex [item model predicates](https://minecraft.wiki/w/Tutorials/Models#Item_predicates). +Those predicates work on any model, including models for vanilla items, but they don't mix very well with vanilla model overrides. +Vanilla predicates only ever get parsed at the top level, so including a vanilla predicate inside of a more complex +firmament parser will result in an ignored predicate. + +### Example usage + +```json +{ + "parent": "minecraft:item/handheld", + "textures": { + "layer0": "firmskyblock:item/bat_wand" + }, + "overrides": [ + { + "predicate": { + "firmament:display_name": { + "regex": ".*§d.*", + "color": "preserve" + } + }, + "model": "firmskyblock:item/recombobulated_bat_wand" + } + ] +} +``` + +You specify an override like normally, with a `model` that will replace the current model and a list of `predicate`s +that must match before that override takes place. + +At the top level `predicate` you can still use all the normal vanilla predicates, as well as the custom ones, which are +all prefixed with `firmament:`. + +#### Display Name + +Matches the display name against a [string matcher](#string-matcher) + +```json +"firmament:display_name": "Display Name Test" +``` + +#### Lore + +Tries to find at least one lore line that matches the given [string matcher](#string-matcher). + +```json +"firmament:lore": { + "regex": "Mode: Red Mushrooms", + "color": "strip" +} +``` + +#### Item type + +Filter by item type: + +```json +"firmament:item": "minecraft:clock" +``` + +#### Extra attributes + +Filter by extra attribute NBT data: + +Specify a `path` to look at, separating sub elements with a `.`. You can use a `*` to check any child. + +Then either specify a `match` sub-object or directly inline that object in the format of an [nbt matcher](#nbt-matcher). + +Inlined match: + +```json5 +"firmament:extra_attributes": { + "path": "gems.JADE_0", + "string": "PERFECT" +} +``` + +Sub object match: + +```json5 +"firmament:extra_attributes": { + "path": "gems.JADE_0", + "match": { + "string": "PERFECT" + } +} +``` + +#### Pet Data + +Filter by pet information. While you can already filter by the skyblock id for pet type and tier, this allows you to +further filter by level and some other pet info. + +```json5 +"firmament:pet" { + "id": "WOLF", + "exp": ">=25353230", + "tier": "[RARE,LEGENDARY]", + "level": "[50,)", + "candyUsed": 0 +} +``` + +| Name | Type | Description | +|-------------|------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------| +| `id` | [String](#string-matcher) | The id of the pet | +| `exp` | [Number](#number-matcher) | The total experience of the pet | +| `tier` | Rarity (like [Number](#number-matcher), but with rarity names instead) | The total experience of the pet | +| `level` | [Number](#number-matcher) | The current level of the pet | +| `candyUsed` | [Number](#number-matcher) | The number of pet candies used on the pet. This is present even if they are not shown in game (such as on a level 100 legendary pet) | + +Every part of this matcher is optional. + + +#### Logic Operators + +Logic operators allow to combine other firmament predicates into one. This is done by building boolean operators: + +```json5 +"firmament:any": [ + { + "firmament:display_name": "SkyBlock Menu (Click)" + }, + { + "firmament:display_name": "SkyBlock", + "firmament:lore": "Some Lore Requirement" + } +] +``` + +This `firmament:any` test if the display name is either "SkyBlock Menu (Click)" or "SkyBlock" (aka any of the child predicates match). + +Similarly, there is `firmament:all`, which requires all of its children to match. + +There is also `firmament:not`, which requires none of its children to match. Unlike `any` or `all`, however, `not` +only takes in one predicate `{}` directly, not an array of predicates `[{}]`. + +Note also that by default all predicate dictionaries require all predicates in it to match, so you can imagine that all +things are wrapped in an implicit `firmament:all` element. + +### String Matcher + +A string matcher allows you to match almost any string. Whenever a string matcher is expected, you can use any of these +styles of creating one. + +#### Direct + +```json +"firmament:display_name": "Test" +``` + +Directly specifying a raw string value expects the string to be *exactly* equal, after removing all formatting codes. + +#### Complex + +A complex string matcher allows you to specify whether the string will get its color codes removed or not before matching + + +```json5 +"firmament:display_name": { + "color": "strip", + "color": "preserve", + // When omitting the color property alltogether, you will fall back to "strip" +} +``` +In that same object you can then also specify how the string will be matched using another property. You can only ever +specify one of these other matchers and one color preserving property. + +```json5 +"firmament:display_name": { + "color": "strip", + // You can use a "regex" property to use a java.util.Pattern regex. It will try to match the entire string. + "regex": "So[me] Regex", + // You can use an "equals" property to test if the entire string is equal to some value. + // Equals is faster than regex, but also more limited. + "equals": "Some Text" +} +``` + +### Number Matchers + +This matches a number against either a range or a specific number. + +#### Direct number + +You can directly specify a number using that value directly: +```json5 +"firmament:pet": { + "level": 100 +} +``` + +This is best for whole numbers, since decimal numbers can be really close together but still be different. + +#### Intervals + +For ranges you can instead use an interval. This uses the standard mathematical notation for those as a string: + + +```json5 +"firmament:pet": { + "level": "(50,100]" +} +``` + +This is in the format of `(min,max)` or `[min,max]`. Either min or max can be omitted, which results in that boundary +being ignored (so `[50,)` would be 50 until infinity). You can also vary the parenthesis on either side independently. + +Specifying round parenthesis `()` means the number is exclusive, so not including this number. For example `(50,100)` +would not match just the number `50` or `100`, but would match `51`. + +Specifying square brackets `[]` means the number is inclusive. For example `[50,100]` would match both `50` and `100`. + +You can mix and match parenthesis and brackets, they only ever affect the number next to it. + +For more information in intervals check out [Wikipedia](https://en.wikipedia.org/wiki/Interval_(mathematics)). + +#### Operators + +If instead of specifying a range you just need to specify one boundary you can also use the standard operators to +compare your number: + +```json5 +"firmament:pet": { + "level": "<50" +} +``` + +This example would match if the level is less than fifty. The available operators are `<`, `>`, `<=` and `>=`. The +operator needs to be specified on the left. The versions of the operator with `=` also allow the number to be equal. + +### Nbt Matcher + +This matches a single nbt element. + +Have the type of the nbt element as json key. Can be `string`, `int`, `float`, `double`, `long`, `short` and `byte`. + +The `string` type matches like a regular [string matcher](#string-matcher): + +```json +"string": { + "color": "strip", + "regex": "^aaa bbb$" +} +``` + +The other (numeric) types can either be matched directly against a number: + +```json +"int": 10 +``` + +Or as a range: + +```json +"long": { + "min": 0, + "max": 1000 +} +``` + +Min and max are both optional, but you need to specify at least one. By default `min` is inclusive and `max` is exclusive. +You can override that like so: + +```json +"short": { + "min": 0, + "max": 1000, + "minExclusive": true, + "maxExclusive": false +} +``` + + +> [!WARNING] +> This syntax for numbers is *just* for **NBT values**. This is also why specifying the type of the number is necessary. +> For other number matchers, use [the number matchers](#number-matchers) + +## Armor textures + +You can re-*texture* armors, but not re-*model* them with firmament. + +To retexture a piece of armor place a json file at `assets/firmskyblock/overrides/armor_models/*.json`. + +```json +{ + "item_ids": [ + "TARANTULA_BOOTS", + "TARANTULA_LEGGINGS", + // ETC + ], + "layers": [ + { + "identifier": "firmskyblock:tarantula" + } + ] +} +``` + +Only one such file can exist per item id, but multiple item ids can share one texture file this way. + +The `item_ids` is the items to which this override will apply when worn. Those are neu repo ids (so what will be shown +in game as the regular SkyBlock id, not the resource pack identifier). + +### Layers + +The `layers` specify the multiple texture layers that will be used when rendering. For non leather armor, or armor +ignoring the leather armor tint just one layer is enough. + +If you want to apply armor tint to the texture you will usually want two layers. The first layer has a tint applied: + +```json +{ + "identifier": "firmskyblock:angler", + "tint": true +} +``` + +This will tint the texture before it is being rendered. + +The second layer will have no tint applied, but will have a suffix: + +```json +{ + "identifier": "firmskyblock:angler", + "suffix": "_overlay" +} +``` + +This second layer is used for the countours of the armor. + +The layer identifier will resolve to a texture file path according to vanilla armor texture rules like so: + +`assets/{identifier.namespace}/textures/models/armor/{identifier.path}_layer_{isLegs ? 2 : 1}{suffix}.png` + +Note that there is no automatic underscore insertion for suffix, so you will need to manually specify it if you want. + +The leg armor piece uses a different texture, same as with vanilla. + +### Overrides + +You can also apply overrides to these layers. These work similar to item predicate overrides, but only the custom +Firmament predicates will work. You will also just directly specify new layers instead of delegating to another file. + +```json +{ + "item_ids": [ + "TARANTULA_BOOTS", + "TARANTULA_LEGGINGS", + // ETC + ], + "layers": [ + { + "identifier": "firmskyblock:tarantula" + } + ], + "overrides": [ + { + "layers": [ + { + "identifier": "firmskyblock:tarantula_maxed" + } + ], + "predicate": { + "firmament:lore": { + "regex": "Piece Bonus: +285.*" + } + } + } + ] +} +``` + +## UI Text Color Replacement + +This allows you to replace the color of text in your inventory. This includes inventory UIs like chests and anvils, but +not screens from other mods. You can also target specific texts via a [string matcher](#string-matcher). + +```json +// This file is at assets/firmskyblock/overrides/text_colors.json +{ + "defaultColor": -10496, + "overrides": [ + { + "predicate": "Crafting", + "override": -16711936 + } + ] +} +``` + +| Field | Required | Description | +|-----------------------|----------|----------------------------------------------------------------------------------------------------| +| `defaultColor` | true | The default color to use in case no override matches | +| `overrides` | false | Allows you to replace colors for specific strings. Is an array. | +| `overrides.predicate` | true | This is a [string matcher](#string-matcher) that allows you to match on the text you are replacing | +| `overrides.override` | true | This is the replacement color that will be used if the predicate matches. | + +## Global Item Texture Replacement + +Most texture replacement is done based on the SkyBlock id of the item. However, some items you might want to re-texture +do not have an id. The next best alternative you had before was just to replace the vanilla item and add a bunch of +predicates. This tries to fix this problem, at the cost of being more performance intensive than the other re-texturing +methods. + +The entrypoint to global overrides is `firmskyblock:overrides/item`. Put your overrides into that folder, with one file +per override. + +```json5 +{ + "screen": "testrp:chocolate_factory", + "model": "testrp:time_tower", + "predicate": { + "firmament:display_name": { + "regex": "Time Tower.*" + } + } +} +``` + +There are three parts to the override. + +The `model` is an *item id* that the item will be replaced with. This means the +model will be loaded from `assets/<namespace>/models/item/<id>.json`. Make sure to use your own namespace to +avoid collisions with other texture packs that might use the same id for a gui. + +The `predicate` is just a normal [predicate](#predicates). This one does not support the vanilla predicates. You can +still use vanilla predicates in the resolved model, but this will not allow you to fall back to other global overrides. + +The `screen` specifies which screens your override will work on. This is purely for performance reasons, your filter +should work purely based on predicates if possible. You can specify multiply screens by using a json array. + +### Global item texture Screens + +In order to improve performance not all overrides are tested all the time. Instead you can prefilter by the screen that +is open. First the gui is resolved to `assets/<namespace>/filters/screen/<id>.json`. Make sure to use your own namespace +to avoid collisions with other texture packs that might use the same id for a screen. + +```json +{ + "title": "Chocolate Factory" +} +``` + +Currently, the only supported filter is `title`, which accepts a [string matcher](#string-matcher). You can also use +`firmament:always` as an always on filter (this is the recommended way). + +## Block Model Replacements + +Firmament adds the ability to retexture block models. Supported renderers are vanilla, indigo (fabric), sodium (and +anything sodium based). Firmament performs gentle world reloading so that even when the world data gets updated very +late by the server there should be no flicker. + +If you want to replace block textures in the world you can do so using block overrides. Those are stored in +`assets/firmskyblock/overrides/blocks/<id>.json`. The id does not matter, all overrides are loaded. This file specifies +which block models are replaced under which conditions: + +```json +{ + "modes": [ + "mining_3" + ], + "area": [ + { + "min": [ + -31, + 200, + -117 + ], + "max": [ + 12, + 223, + -95 + ] + } + ], + "replacements": { + "minecraft:blue_wool": "firmskyblock:mithril_deep", + "minecraft:light_blue_wool": { + "block": "firmskyblock:mithril_deep", + "sound": "minecraft:block.wet_sponge.hit" + } + } +} +``` + +| Field | Required | Description | +|-------------------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `modes` | yes | A list of `/locraw` mode names. | +| `area` | no | A list of areas. Blocks outside of the coordinate range will be ignored. If the block is in *any* range it will be considered inside | +| `area.min` | yes | The lowest coordinate in the area. Is included in the area. | +| `area.max` | yes | The highest coordinate in the area. Is included in the area. | +| `replacements` | yes | A map of block id to replacement mappings | +| `replacements` (string) | yes | You can directly specify a string. Equivalent to just setting `replacements.block`. | +| `replacements.block` | yes | You can specify a block model to be used instead of the regular one. The model will be loaded from `assets/<namespace>/models/block/<path>.json` like regular block models. | +| `replacements.sound` | no | You can also specify a sound override. This is only used for the "hit" sound effect that repeats while the block is mined. The "break" sound effect played after a block was finished mining is sadly sent by hypixel directly and cannot be replaced reliably. | + +> A quick note about optimization: Not specifying an area (by just omitting the `area` field) is quicker than having an +> area encompass the entire map. +> +> If you need to use multiple `area`s for unrelated sections of the world it might be a performance improvement to move +> unrelated models to different files to reduce the amount of area checks being done for each block. |