Skip to content

Commit

Permalink
Variants-CIT (#3)
Browse files Browse the repository at this point in the history
- Renammed from Enchants-CIT to Variants-CIT
- CIT logic is now modular, and more easily extended.
- CIT modules are now enabled and configured via resource packs
- Added CIT modules: `axolotl_variant`, `custom_data`, `instrument`,
`jukebox_playable`, `potion_type`, `stored_enchantments`
- Removed embedded resource pack.
  • Loading branch information
Estecka authored Aug 26, 2024
1 parent b0295cb commit bb94cbd
Show file tree
Hide file tree
Showing 112 changed files with 1,444 additions and 654 deletions.
9 changes: 7 additions & 2 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
# v1

## 1.0
### 1.0.0
- Initial Release
### 1.0.1
- Fixed an incompatibility with ModernFix

## 1.1
- Added the `level` model predicate for enchanted books.

# v2
- Renammed from Enchants-CIT to Variants-CIT
- CIT logic is now modular, and can be extended via an api
- CIT modules are now enabled and configured via resource packs
- Added CIT modules: `axolotl_variant`, `custom_data`, `instrument`, `jukebox_playable`, `potion_type`, `stored_enchantments`
- Removed embedded resource pack.
863 changes: 661 additions & 202 deletions LICENSE

Large diffs are not rendered by default.

54 changes: 21 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,33 @@
# Enchants CIT
A specialized CIT logic for enchanted books, made to allow enchantment-based resource packs to work on MC 1.21 without the help of optifine nor CIT-resewn.
# Variants-CIT
A CIT logic for MC 1.21, specialized in handling items with standardized variants.

**This mod is not a plug-and-play replacement for Optifine or CIT-resewn.**
It uses its own resource format, and requires some changes be made to older packs for them to work.
**This mod is not a plug-and-play replacement for Optifine/CIT-resewn;** it uses its own resource format. Changes to older packs are required for them to work.
On low-end PCs, using this mod instead of the optifine format may lead to improved performances in scenarios where a single item has very many different variants.

The current release includes the textures from [**Even Better Enchants**](https://modrinth.com/resourcepack/even-better-enchants).
The mod is not as all-purpose as optifine, it still requires specialized code for most item type, but this code is modular and easy to expand upon. Other mods can also add custom modules for their own items.

## Resource Pack Format

### Enchantment-specific models
The mod looks for [item models](https://minecraft.wiki/w/Model#Item_models) with pathes formatted like this, where `<namespace>` and `<name>` match an enchantment's identifier:
**`/assets/<namespace>/models/item/enchanted_book/<name>.json`**

Texture pathes are defined in the models themselves; I recommend following the same naming convention as the models. (Simply replace `models` with `textures` in the path.)
Built-in modules support **Axolotl Buckets**, **Enchanted Books**, **Music Discs**, **Goat Horns**, and **Potions**.
If Mojang ever makes these items more componentized, you can expect Banner Patterns, Trim Templates, and Pottery Sherds to become supported in the future.

Enchantments with no model will fall back to the vanilla one.
For datapack makers, there is also a more generic module that can pull a variant id from the `custom_data` component of an item.

### Level-specific models
The mod provides a **`level`** predicate, which can be used to define overrides in the aforementioned models.
## Resource Pack Format
A resource pack who wants to modify an item must start by providing a configuration file to declare what item to change, where its resources are located, and which logic to use.
The targetd item type is automatically derived from the file name: `/assets/<namespace>/variants-cit/item/<name>.json`

**The models used as overrides should be stored outside of `item/enchanted_book` and its subfolders,** otherwise each level will also be treated as its own enchantment. (This is unlikely to cause bugs, but is less optimised.)
The mod will look for [item models](https://minecraft.wiki/w/Model#Item_models) stored in a chosen directory, and automatically associate them to variants with the corresponding namespace and name.

Example: `/assets/minecraft/models/item/enchanted_book/unbreaking.json`
For example, here's a module that would reproduce the behaviour of the previous version of the mod, Enchants-CIT :
`/assets/minecraft/variant-cits/item/enchanted_book.json`
```json
{
"parent": "item/levelled_enchanted_book/unbreaking_1",
"overrides": [
{
"predicate": { "level": 2 },
"model": "item/levelled_enchanted_book/unbreaking_2"
},
{
"predicate": { "level": 3 },
"model": "item/levelled_enchanted_book/unbreaking_3"
}
]
"type": "stored_enchantments",
"modelPrefix": "item/enchanted_book/",
"special": {
"multi": "enchants-cit:item/multi_enchanted_book"
}
}
```
Here, the enchantment `minecraft:unbreaking` will be associated with the model `minecraft:item/enchanted_book/unbreaking`, which is stored at `/assets/minecraft/models/item/enchanted_book/unbreaking.json`

### Multi-enchantment
The mod only supports a single model for books with multiple enchantments, hardcoded at:
**`/assets/enchants-cit/models/item/multi_enchanted_book.json`**

The behaviour of the `level` predicate is undefined on this type of books.
Some module types may define additional models to use in special cases, or take addional parameters. See the [wiki](/~https://github.com/Estecka/mc-Variants-CIT/wiki) for a more complete guide.
8 changes: 4 additions & 4 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ org.gradle.parallel=true
# check these on https://fabricmc.net/develop
minecraft_version=1.21.1
yarn_mappings=1.21.1+build.3
loader_version=0.15.11
loader_version=0.16.2

# Fabric API
fabric_version=0.102.1+1.21.1

# Mod Properties
mod_version=1.1.0
maven_group=fr.estecka.enchantscit
archives_base_name=enchants-cit
mod_version=2.0.0
maven_group=fr.estecka.variantscit
archives_base_name=variants-cit
78 changes: 0 additions & 78 deletions src/main/java/fr/estecka/enchantscit/EnchantsCit.java

This file was deleted.

35 changes: 0 additions & 35 deletions src/main/java/fr/estecka/enchantscit/LevelPredicate.java

This file was deleted.

45 changes: 0 additions & 45 deletions src/main/java/fr/estecka/enchantscit/mixin/ItemRendererMixin.java

This file was deleted.

45 changes: 45 additions & 0 deletions src/main/java/fr/estecka/variantscit/ModuleDefinition.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package fr.estecka.variantscit;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.fabric.impl.client.model.loading.ModelLoadingConstants;
import net.minecraft.client.util.ModelIdentifier;
import net.minecraft.util.Identifier;
import com.google.common.collect.ImmutableMap;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;

public record ModuleDefinition(Identifier type, String modelPrefix, Optional<Identifier> fallbackModel, Map<String,Identifier> specialModels)
{
static public final MapCodec<ModuleDefinition> CODEC = RecordCodecBuilder.<ModuleDefinition>mapCodec(builder->builder
.group(
Identifier.CODEC.fieldOf("type").forGetter(ModuleDefinition::type),
Codec.STRING.validate(ModuleDefinition::ValidatePath).fieldOf("modelPrefix").forGetter(ModuleDefinition::modelPrefix),
Identifier.CODEC.optionalFieldOf("fallback").forGetter(ModuleDefinition::fallbackModel),
Codec.unboundedMap(Codec.STRING, Identifier.CODEC).fieldOf("special").orElse(ImmutableMap.<String,Identifier>of()).forGetter(ModuleDefinition::specialModels)
)
.apply(builder, ModuleDefinition::new)
);

static public DataResult<String> ValidatePath(String path){
if (Identifier.isPathValid(path))
return DataResult.success(path);
else
return DataResult.error(()->"Invalid character in path: "+path);
}

public @Nullable ModelIdentifier GetFallbackModelId(){
return fallbackModel.map(ModelLoadingConstants::toResourceModelId).orElse(null);
}

public Map<String, @Nullable ModelIdentifier> GetSpecialModelIds(){
Map<String, @Nullable ModelIdentifier> result = new HashMap<>();
for (var entry : this.specialModels.entrySet())
result.put(entry.getKey(), ModelLoadingConstants.toResourceModelId(entry.getValue()));
return result;
}
}
78 changes: 78 additions & 0 deletions src/main/java/fr/estecka/variantscit/ModuleLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package fr.estecka.variantscit;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import org.jetbrains.annotations.Nullable;
import com.google.gson.JsonObject;
import com.mojang.serialization.JsonOps;
import net.fabricmc.fabric.api.client.model.loading.v1.PreparableModelLoadingPlugin.DataLoader;
import net.minecraft.item.Item;
import net.minecraft.registry.Registries;
import net.minecraft.resource.Resource;
import net.minecraft.resource.ResourceManager;
import net.minecraft.util.Identifier;
import net.minecraft.util.JsonHelper;

public class ModuleLoader
implements DataLoader<Map<Item,VariantManager>>
{
@Override
public CompletableFuture<Map<Item,VariantManager>> load(ResourceManager resourceManager, Executor executor){
return CompletableFuture.supplyAsync(()->ReloadModules(resourceManager), executor);
}

private Map<Item,VariantManager> ReloadModules(ResourceManager manager){
Map<Item,VariantManager> result = new HashMap<>();

for (Map.Entry<Identifier, Resource> entry : manager.findResources("variant-cits/item", id->id.getPath().endsWith(".json")).entrySet()){
Identifier resourceId = entry.getKey();
Item item = ItemFromModule(resourceId);
if (item == null)
continue;

JsonObject json;
VariantManager module;
try {
json = JsonHelper.deserialize(entry.getValue().getReader());
}
catch (IOException e){
VariantsCitMod.LOGGER.error("{}", e);
continue;
}

var dataResult = ModuleDefinition.CODEC.decoder().decode(JsonOps.INSTANCE, json);
if (dataResult.isError()){
VariantsCitMod.LOGGER.error("Error in cit module {}: {}", resourceId, dataResult.error().get().message());
continue;
}

try {
module = ModuleRegistry.CreateManager(dataResult.getOrThrow().getFirst(), json);
}
catch (IllegalArgumentException|IllegalStateException e){
VariantsCitMod.LOGGER.error("Error building cit module of type {}: {}", dataResult.getPartialOrThrow().getFirst().type(), e);
continue;
}

module.ReloadVariants(manager);
result.put(item, module);
}

return result;
}

static private @Nullable Item ItemFromModule(Identifier resourceId){
String path = resourceId.getPath();
path = path.substring("variant-cits/item".length() + 1, path.length() - ".json".length());

Identifier itemId = Identifier.of(resourceId.getNamespace(), path);

if (Registries.ITEM.containsId(itemId))
return Registries.ITEM.get(itemId);
else
return null;
}
}
Loading

0 comments on commit bb94cbd

Please sign in to comment.