Skip to content

Commit

Permalink
Improve display of enchantment conversion in JEI
Browse files Browse the repository at this point in the history
Enchanted books now only show for applicable enchantments in each recipe, and show all levels. Means you can lookup usages on a book
Empty slot icon is shown if no tool exists
A recipe can mark that modifiers are output instead of input, so that the worktable recipe shows as a way to get modifiers
  • Loading branch information
KnightMiner committed Jan 4, 2023
1 parent 712cae2 commit e3e1253
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@

import javax.annotation.Nullable;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
Expand Down Expand Up @@ -104,7 +105,7 @@ public class ModifierManager extends SimpleJsonResourceReloadListener {
private Map<ModifierId,Set<TagKey<Modifier>>> reverseTags = Collections.emptyMap();

/** List of tag to modifier mappings to try */
private Collection<EnchantmentTagMapping> enchantmentTagMap = Collections.emptyList();
private Map<TagKey<Enchantment>, Modifier> enchantmentTagMap = Collections.emptyMap();
/** Mapping from enchantment to modifiers, for conversions */
private Map<Enchantment,Modifier> enchantmentMap = Collections.emptyMap();

Expand Down Expand Up @@ -197,7 +198,7 @@ protected void apply(Map<ResourceLocation,JsonElement> splashList, ResourceManag

// load modifier to enchantment mapping
enchantmentMap = new HashMap<>();
Map<ResourceLocation,EnchantmentTagMapping> tagMappings = new HashMap<>();
this.enchantmentTagMap = new LinkedHashMap<>();
try {
for (Resource resource : pResourceManager.getResources(ENCHANTMENT_MAP)) {
JsonObject enchantmentJson = JsonHelper.getJson(resource);
Expand All @@ -218,7 +219,7 @@ protected void apply(Map<ResourceLocation,JsonElement> splashList, ResourceManag
if (tagId == null) {
throw new JsonSyntaxException("Invalid enchantment tag ID " + key.substring(1));
}
tagMappings.put(tagId, new EnchantmentTagMapping(TagKey.create(Registry.ENCHANTMENT_REGISTRY, tagId), modifier));
this.enchantmentTagMap.put(TagKey.create(Registry.ENCHANTMENT_REGISTRY, tagId), modifier);
} else {
// assume its an ID
ResourceLocation enchantId = ResourceLocation.tryParse(key);
Expand All @@ -236,8 +237,7 @@ protected void apply(Map<ResourceLocation,JsonElement> splashList, ResourceManag
} catch (IOException e) {
log.info("Failed to get enchantment map from {}", enchantmentMap);
}
this.enchantmentTagMap = tagMappings.values();
log.info("Loaded {} enchantment to modifier mappings in {} ms", enchantmentMap.size() + tagMappings.size(), (System.nanoTime() - timeStep) / 1000000f);
log.info("Loaded {} enchantment to modifier mappings in {} ms", enchantmentMap.size() + enchantmentTagMap.size(), (System.nanoTime() - timeStep) / 1000000f);

MinecraftForge.EVENT_BUS.post(new ModifiersLoadedEvent());
}
Expand Down Expand Up @@ -277,7 +277,7 @@ private Modifier loadModifier(ResourceLocation key, JsonElement element, Map<Mod
}

/** Updates the modifiers from the server */
void updateModifiersFromServer(Map<ModifierId,Modifier> modifiers, Map<ResourceLocation,Tag<Modifier>> tags, Map<Enchantment,Modifier> enchantmentMap, Collection<EnchantmentTagMapping> enchantmentTagMappings) {
void updateModifiersFromServer(Map<ModifierId,Modifier> modifiers, Map<ResourceLocation,Tag<Modifier>> tags, Map<Enchantment,Modifier> enchantmentMap, Map<TagKey<Enchantment>,Modifier> enchantmentTagMappings) {
this.dynamicModifiers = modifiers;
this.dynamicModifiersLoaded = true;
this.tags = tags;
Expand Down Expand Up @@ -328,14 +328,23 @@ public Modifier get(Enchantment enchantment) {
return enchantmentMap.get(enchantment);
}
// did not find, check the tags
for (EnchantmentTagMapping mapping : enchantmentTagMap) {
if (mapping.test(enchantment)) {
return mapping.modifier;
for (Entry<TagKey<Enchantment>,Modifier> mapping : enchantmentTagMap.entrySet()) {
if (RegistryHelper.contains(Registry.ENCHANTMENT, mapping.getKey(), enchantment)) {
return mapping.getValue();
}
}
return null;
}

/** Gets a stream of all enchantments that match the given modifiers */
public Stream<Enchantment> getEquivalentEnchantments(Predicate<ModifierId> modifiers) {
Predicate<Entry<?,Modifier>> predicate = entry -> modifiers.test(entry.getValue().getId());
return Stream.concat(
enchantmentMap.entrySet().stream().filter(predicate).map(Entry::getKey),
enchantmentTagMap.entrySet().stream().filter(predicate).flatMap(entry -> RegistryHelper.getTagValueStream(Registry.ENCHANTMENT, entry.getKey()))
).distinct().sorted(Comparator.comparing(enchantment -> Objects.requireNonNull(enchantment.getRegistryName())));
}

/** Gets a list of all modifier IDs */
public Stream<ResourceLocation> getAllLocations() {
// filter out redirects (redirects are any modifiers where the ID does not match the key
Expand Down Expand Up @@ -497,12 +506,4 @@ public boolean shouldDisplay(boolean advanced) {
return false;
}
}

/** Record representing a mapping from tag to modifier */
record EnchantmentTagMapping(TagKey<Enchantment> tag, Modifier modifier) implements Predicate<Enchantment> {
@Override
public boolean test(Enchantment enchantment) {
return RegistryHelper.contains(Registry.ENCHANTMENT, this.tag, enchantment);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import net.minecraftforge.network.NetworkEvent.Context;
import net.minecraftforge.registries.ForgeRegistries;
import slimeknights.mantle.network.packet.IThreadsafePacket;
import slimeknights.tconstruct.library.modifiers.ModifierManager.EnchantmentTagMapping;
import slimeknights.tconstruct.library.utils.GenericTagUtil;

import java.util.Collection;
Expand All @@ -35,7 +34,7 @@ public class UpdateModifiersPacket implements IThreadsafePacket {
/** Map of enchantment to modifier pair */
private final Map<Enchantment,Modifier> enchantmentMap;
/** Collection of all enchantment tag mappings */
private final Collection<EnchantmentTagMapping> enchantmentTagMappings;
private final Map<TagKey<Enchantment>, Modifier> enchantmentTagMappings;

/** Ensures both the modifiers and redirects lists are calculated, allows one packet to be used multiple times without redundant work */
private void ensureCalculated() {
Expand Down Expand Up @@ -96,12 +95,12 @@ public UpdateModifiersPacket(FriendlyByteBuf buffer) {
getModifier(modifiers, new ModifierId(buffer.readResourceLocation())));
}
enchantmentMap = enchantmentBuilder.build();
ImmutableList.Builder<EnchantmentTagMapping> enchantmentTagBuilder = ImmutableList.builder();
ImmutableMap.Builder<TagKey<Enchantment>, Modifier> enchantmentTagBuilder = ImmutableMap.builder();
size = buffer.readVarInt();
for (int i = 0; i < size; i++) {
enchantmentTagBuilder.add(new EnchantmentTagMapping(
enchantmentTagBuilder.put(
TagKey.create(Registry.ENCHANTMENT_REGISTRY, buffer.readResourceLocation()),
getModifier(modifiers, new ModifierId(buffer.readResourceLocation()))));
getModifier(modifiers, new ModifierId(buffer.readResourceLocation())));
}
enchantmentTagMappings = enchantmentTagBuilder.build();
}
Expand Down Expand Up @@ -130,9 +129,9 @@ public void encode(FriendlyByteBuf buffer) {
buffer.writeResourceLocation(entry.getValue().getId());
}
buffer.writeVarInt(enchantmentTagMappings.size());
for (EnchantmentTagMapping mapping : enchantmentTagMappings) {
buffer.writeResourceLocation(mapping.tag().location());
buffer.writeResourceLocation(mapping.modifier().getId());
for (Entry<TagKey<Enchantment>, Modifier> entry : enchantmentTagMappings.entrySet()) {
buffer.writeResourceLocation(entry.getKey().location());
buffer.writeResourceLocation(entry.getValue().getId());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ default void updateInputs(IToolStackView result, ITinkerableContainer.Mutable in
/** Gets the number of inputs for this recipe */
int getInputCount();

/** If true, the recipe modifier is an output */
default boolean isModifierOutput() {
return false;
}


/** Deprecated methods to ignore */

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import slimeknights.mantle.client.ResourceColorManager;
import slimeknights.tconstruct.TConstruct;
import slimeknights.tconstruct.library.recipe.worktable.IModifierWorktableRecipe;
import slimeknights.tconstruct.plugin.jei.TConstructJEIConstants;
Expand All @@ -32,10 +31,12 @@ public class ModifierWorktableCategory implements IRecipeCategory<IModifierWorkt
private final IDrawable background;
@Getter
private final IDrawable icon;
private final IDrawable toolIcon;
private final IDrawable[] slotIcons;
public ModifierWorktableCategory(IGuiHelper helper) {
this.background = helper.createDrawable(BACKGROUND_LOC, 0, 166, 121, 35);
this.icon = helper.createDrawableIngredient(VanillaTypes.ITEM_STACK, new ItemStack(TinkerTables.modifierWorktable));
this.toolIcon = helper.createDrawable(BACKGROUND_LOC, 128, 0, 16, 16);
this.slotIcons = new IDrawable[] {
helper.createDrawable(BACKGROUND_LOC, 176, 0, 16, 16),
helper.createDrawable(BACKGROUND_LOC, 208, 0, 16, 16)
Expand Down Expand Up @@ -64,21 +65,18 @@ public RecipeType<IModifierWorktableRecipe> getRecipeType() {
return TConstructJEIConstants.MODIFIER_WORKTABLE;
}

/** Draws a single slot icon */
private void drawSlot(PoseStack matrices, IModifierWorktableRecipe recipe, int slot, int x, int y) {
List<ItemStack> stacks = recipe.getDisplayItems(slot);
if (stacks.isEmpty()) {
// -1 as the item list includes the output slot, we skip that
slotIcons[slot].draw(matrices, x, y);
}
}

@Override
public void draw(IModifierWorktableRecipe recipe, IRecipeSlotsView slots, PoseStack matrixStack, double mouseX, double mouseY) {
if (recipe.getInputTools().isEmpty()) {
toolIcon.draw(matrixStack, 23, 16);
}
for (int i = 0; i < 2; i++) {
drawSlot(matrixStack, recipe, i, 43 + i * 18, 16);
List<ItemStack> stacks = recipe.getDisplayItems(i);
if (stacks.isEmpty()) {
slotIcons[i].draw(matrixStack, 43 + i * 18, 16);
}
}
Minecraft.getInstance().font.drawShadow(matrixStack, recipe.getTitle(), 3, 2, ResourceColorManager.WHITE.getValue());
Minecraft.getInstance().font.draw(matrixStack, recipe.getTitle(), 3, 2, 0x404040);
}

@Override
Expand All @@ -98,6 +96,6 @@ public void setRecipe(IRecipeLayoutBuilder builder, IModifierWorktableRecipe rec
builder.addSlot(RecipeIngredientRole.INPUT, 43 + i*18, 16).addItemStacks(recipe.getDisplayItems(i));
}
// modifier input
builder.addSlot(RecipeIngredientRole.CATALYST, 82, 16).addIngredients(TConstructJEIConstants.MODIFIER_TYPE, recipe.getModifierOptions(null));
builder.addSlot(recipe.isModifierOutput() ? RecipeIngredientRole.OUTPUT : RecipeIngredientRole.CATALYST, 82, 16).addIngredients(TConstructJEIConstants.MODIFIER_TYPE, recipe.getModifierOptions(null));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.item.enchantment.EnchantmentInstance;
import net.minecraft.world.level.Level;
import net.minecraftforge.registries.ForgeRegistries;
import slimeknights.mantle.data.predicate.IJsonPredicate;
import slimeknights.mantle.recipe.helper.LoggingRecipeSerializer;
import slimeknights.mantle.recipe.ingredient.SizedIngredient;
Expand All @@ -44,7 +43,10 @@
import javax.annotation.Nullable;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/** Recipe for converting enchanted books into modifier crystals */
public class EnchantmentConvertingRecipe extends AbstractWorktableRecipe {
Expand Down Expand Up @@ -160,10 +162,19 @@ public RecipeSerializer<?> getSerializer() {

/* Display */

@Override
public boolean isModifierOutput() {
return true;
}

@Override
public List<ItemStack> getInputTools() {
if (tools == null) {
tools = ForgeRegistries.ENCHANTMENTS.getValues().stream().map(enchantment -> EnchantedBookItem.createForEnchantment(new EnchantmentInstance(enchantment, 1))).toList();
Set<ModifierId> modifiers = getModifierOptions(null).stream().map(ModifierEntry::getId).collect(Collectors.toSet());
tools = ModifierManager.INSTANCE.getEquivalentEnchantments(modifiers::contains)
.flatMap(enchantment -> IntStream.rangeClosed(1, enchantment.getMaxLevel())
.mapToObj(level -> EnchantedBookItem.createForEnchantment(new EnchantmentInstance(enchantment, level))))
.toList();
}
return tools;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ public void updateInputs(IToolStackView result, Mutable inv, ModifierEntry selec
}
}

@Override
public boolean isModifierOutput() {
return true;
}

@Override
public RecipeSerializer<?> getSerializer() {
return TinkerModifiers.extractModifierSerializer.get();
Expand Down

0 comments on commit e3e1253

Please sign in to comment.