Requirement tooltips

This commit is contained in:
2025-03-16 04:09:22 +01:00
parent fafa7410a6
commit f961ec81e4
15 changed files with 187 additions and 343 deletions

View File

@@ -14,7 +14,7 @@ parchment_version = 2024.11.17
mod_id=mechanical_lemon_lib
mod_name=MechanicalLemonLib
mod_license=LGPL3
mod_version=0.1.49
mod_version=0.1.56
mod_group_id=com.oierbravo
mod_author=oierbravo
mod_description=Mod Utility Library

View File

@@ -21,7 +21,7 @@ public abstract class BaseRecipe<T extends RecipeInput, P extends BaseRecipePara
protected ArrayList<ICondition> conditions;
abstract public List<String> getEnabledRequirements();
//abstract public List<String> getEnabledRequirements();
public BaseRecipe(P params){
this.id = params.id;

View File

@@ -44,12 +44,12 @@ public abstract class BaseRecipeBuilder<R extends BaseRecipe<?,P>, P extends Bas
public <BRP extends BaseRecipeBuilder<?,?>> BRP withRequirement(IRecipeRequirement requirement){
//public <BRP extends BaseRecipeSerializer<?,?> BaseRecipeBuilder<R,P> withRequirement(IRecipeRequirement requirement){
params.recipeRequirements.add(requirement);
return (BRP) this;
return ((BRP) this);
}
public <BRP extends BaseRecipeBuilder<?,?>> BRP withRequirements(List<IRecipeRequirement> pRecipeRequirements) {
//public BaseRecipeBuilder<R,P> withRequirements(List<IRecipeRequirement> pRecipeRequirements) {
params.recipeRequirements.addAll(pRecipeRequirements);
return (BRP) this;
return ((BRP) this);
}
public BaseRecipeBuilder<R,P> whenModLoaded(String modid) {

View File

@@ -28,13 +28,14 @@ public interface IRecipeRequirement {
STREAM_CODEC.apply(ByteBufCodecs.list(256));
boolean test(Level pLevel, BlockEntity pBlockEntity);
/*boolean isPresent();*/
String getIdString();
String toString();
RecipeRequirementType<?> getType();
default Component toTooltipComponent(){
return LibLang.translate("ui.recipe_requirement." + getIdString() + ".tooltip", toString()).component();
//return LibLang.translate("ui.recipe_requirement." + getIdString() + ".tooltip").newLine().component().append(toString());.component();
return LibLang.translate("ui.recipe_requirement." + getIdString() + ".tooltip", toString()).newLine().space().add(Component.literal(toString())).component();
};
default Component toMissingComponent(){
return LibLang.translate("ui.recipe_requirement." + getIdString() + ".missing").component();

View File

@@ -2,21 +2,29 @@ package com.oierbravo.mechanical_lemon_lib.foundation.recipe;
import com.google.gson.JsonObject;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.level.block.entity.BlockEntity;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class RecipeRequirementsUtils {
public static ArrayList<RecipeRequirementType<?>> checkRequirements(Map<String, IRecipeRequirement> pRecipeRequirements, BlockEntity pBlockEntity){
/*public static ArrayList<RecipeRequirementType<?>> checkRequirements(Map<String, IRecipeRequirement> pRecipeRequirements, BlockEntity pBlockEntity){
ArrayList<RecipeRequirementType<?>> missingRequirements = new ArrayList<>();
pRecipeRequirements.forEach((recipeRequirementType, recipeRequirement) -> {
if(!recipeRequirement.test(pBlockEntity.getLevel(),pBlockEntity))
missingRequirements.add(recipeRequirement.getType());
});
return missingRequirements;
}*/
public static <BR extends IRecipeWithRequirements> List<Component> getRequirementsTooltips(BR recipe){
if(recipe.getRecipeRequirements().isEmpty())
return List.of();
return recipe.getRecipeRequirements().stream().map(IRecipeRequirement::toTooltipComponent).toList();
}
}

View File

@@ -0,0 +1,74 @@
package com.oierbravo.mechanical_lemon_lib.foundation.recipe.requirements;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import com.oierbravo.mechanical_lemon_lib.foundation.recipe.IRecipeRequirement;
import com.oierbravo.mechanical_lemon_lib.foundation.recipe.RecipeRequirementType;
import com.oierbravo.mechanical_lemon_lib.register.MechanicalLemonRecipeRequirementTypes;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BlockEntity;
import java.util.Optional;
public record BiomeRequirement(ResourceKey<Biome> biomeResourceKey) implements IRecipeRequirement {
public static String ID = "biome";
public static MapCodec<BiomeRequirement> CODEC = RecordCodecBuilder
.mapCodec((builder)
-> builder
.group(ResourceKey.codec(Registries.BIOME).optionalFieldOf("value", null)
.forGetter(BiomeRequirement::biomeResourceKey)).apply(builder,BiomeRequirement::new));
public static final StreamCodec<RegistryFriendlyByteBuf, BiomeRequirement> STREAM_CODEC = StreamCodec.composite(
ResourceKey.streamCodec(Registries.BIOME), BiomeRequirement::biomeResourceKey,
BiomeRequirement::new
);
public static BiomeRequirement of(ResourceKey<Biome> key) {
return new BiomeRequirement( key);
}
public boolean test(Level pLevel, BlockEntity pBlockEntity) {
if(biomeResourceKey == null)
return true;
Holder<Biome> blockEntityBiome = pLevel.getBiome(pBlockEntity.getBlockPos());
if(pLevel.isClientSide()){
return false;
}
Optional<Holder.Reference<Biome>> requiredBiomeHolder = pLevel.getServer().registryAccess().registryOrThrow(Registries.BIOME).asLookup().get(biomeResourceKey);
if(requiredBiomeHolder.isPresent()
&& blockEntityBiome.is(requiredBiomeHolder.get().key()))
return true;
return false;
}
@Override
public RecipeRequirementType<?> getType() {
return MechanicalLemonRecipeRequirementTypes.BIOME.get();
}
@Override
public String getIdString() {
return ID;
}
@Override
public String toString() {
return biomeResourceKey.location().toString();
}
}

View File

@@ -1,150 +0,0 @@
package com.oierbravo.mechanical_lemon_lib.foundation.recipe.requirements;
import com.google.gson.JsonObject;
import com.mojang.serialization.JsonOps;
import com.oierbravo.mechanical_lemon_lib.foundation.recipe.RecipeRequirement;
import com.oierbravo.mechanical_lemon_lib.foundation.recipe.RecipeRequirementType;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BlockEntity;
import java.util.Optional;
import static java.lang.constant.ConstantDescs.NULL;
public class BiomeRequirement extends RecipeRequirement {
public static final RecipeRequirementType<BiomeRequirement> TYPE = new BiomeRequirementType();
public static final BiomeRequirement EMPTY = new BiomeRequirement();
protected TagKey<Biome> biomeTagKey;
protected ResourceKey<Biome> biomeResourceKey;
public BiomeRequirement() {
}
public BiomeRequirement(TagKey<Biome> tag) {
biomeTagKey = tag;
}
public BiomeRequirement(ResourceKey<Biome> key) {
biomeResourceKey = key;
}
public BiomeRequirement(ResourceKey<Biome> key, TagKey<Biome> tag) {
this.biomeResourceKey = key;
this.biomeTagKey = tag;
}
public static BiomeRequirement of(ResourceKey<Biome> key) {
return new BiomeRequirement(key);
}
public static BiomeRequirement of(TagKey<Biome> tag) {
return new BiomeRequirement(tag);
}
public static BiomeRequirement of(ResourceKey<Biome> key, TagKey<Biome> tag) {
return new BiomeRequirement(key, tag);
}
public boolean test(Level pLevel, BlockEntity pBlockEntity) {
if(biomeResourceKey == null && biomeTagKey == null)
return true;
Holder<Biome> blockEntityBiome = pLevel.getBiome(pBlockEntity.getBlockPos());
if(pLevel.isClientSide()){
return false;
}
Optional<Holder.Reference<Biome>> requiredBiomeHolder = pLevel.getServer().registryAccess().registryOrThrow(Registries.BIOME).asLookup().get(biomeResourceKey);
if(requiredBiomeHolder.isPresent()
&& blockEntityBiome.is(requiredBiomeHolder.get().key()))
return true;
return pLevel.getServer().registryAccess().registryOrThrow(Registries.BIOME).getTag(biomeTagKey).map(t ->
t.contains(blockEntityBiome)
).orElse(false);
}
public boolean isPresent(){
if(biomeTagKey == null && biomeResourceKey == null)
return false;
return true;
}
public String toString(){
if(biomeTagKey == null && biomeResourceKey == null)
return null;
if(biomeResourceKey != null)
return biomeResourceKey.location().toString();
return biomeTagKey.location().toString();
}
@Override
public RecipeRequirementType<?> getType() {
return TYPE;
}
private static class BiomeRequirementType extends RecipeRequirementType<BiomeRequirement> {
public BiomeRequirementType() {
super("biome");
}
public BiomeRequirementType(String id) {
super(id);
}
@Override
public BiomeRequirement fromJson(JsonObject pJson) {
if (GsonHelper.isValidNode(pJson, "biome")) {
ResourceKey<Biome> biomeResourceKey = ResourceKey.codec(Registries.BIOME).parse(JsonOps.INSTANCE, pJson.get("biome")).result().get();
TagKey<Biome> biomeTag = TagKey.codec(Registries.BIOME).parse(JsonOps.INSTANCE, pJson.get("biome")).result().get();
return BiomeRequirement.of(biomeResourceKey,biomeTag);
}
return BiomeRequirement.EMPTY;
}
@Override
public JsonObject toJson(JsonObject pJson, RecipeRequirement pRecipeRequirement){
if(!pRecipeRequirement.isPresent())
return pJson;
pJson.addProperty("biome", pRecipeRequirement.toString());
return pJson;
}
@Override
public BiomeRequirement fromNetwork(FriendlyByteBuf buffer) {
boolean hasRequirement = buffer.readBoolean();
if(hasRequirement) {
ResourceLocation rl = buffer.readResourceLocation();
if (NULL.equals(rl)) return BiomeRequirement.EMPTY;
else return BiomeRequirement.of(TagKey.create(Registries.BIOME, rl));
}
return BiomeRequirement.EMPTY;
}
@Override
public void toNetwork(FriendlyByteBuf buffer, RecipeRequirement pRecipeRequirement) {
if(pRecipeRequirement == null)
pRecipeRequirement = new BiomeRequirement();
if(pRecipeRequirement instanceof BiomeRequirement){
buffer.writeBoolean(pRecipeRequirement.isPresent());
if(pRecipeRequirement.isPresent()) {
TagKey<Biome> biome = ((BiomeRequirement) pRecipeRequirement).biomeTagKey;
buffer.writeResourceLocation(biome.location());
}
}
}
}
}

View File

@@ -1,158 +0,0 @@
package com.oierbravo.mechanical_lemon_lib.foundation.recipe.requirements;
import com.google.gson.JsonObject;
import com.mojang.serialization.JsonOps;
import com.oierbravo.mechanical_lemon_lib.foundation.recipe.RecipeRequirement;
import com.oierbravo.mechanical_lemon_lib.foundation.recipe.RecipeRequirementType;
import net.minecraft.client.Minecraft;
import net.minecraft.core.Holder;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BlockEntity;
import java.util.Objects;
import java.util.Optional;
import static java.lang.constant.ConstantDescs.NULL;
public class BiomeRequirement extends RecipeRequirement {
public static final RecipeRequirementType<BiomeRequirement> TYPE = new BiomeRequirementType();
public static final BiomeRequirement EMPTY = new BiomeRequirement();
protected TagKey<Biome> biomeTagKey;
protected ResourceKey<Biome> biomeResourceKey;
public BiomeRequirement() {
}
public BiomeRequirement(TagKey<Biome> tag) {
this(null,tag);
}
public BiomeRequirement(ResourceKey<Biome> key) {
this(key,null);
}
public BiomeRequirement(ResourceKey<Biome> key, TagKey<Biome> tag) {
this.biomeResourceKey = key;
this.biomeTagKey = tag;
}
public static BiomeRequirement of(ResourceKey<Biome> key) {
return new BiomeRequirement(key);
}
public static BiomeRequirement of(TagKey<Biome> tag) {
return new BiomeRequirement(tag);
}
public static BiomeRequirement of(ResourceKey<Biome> key, TagKey<Biome> tag) {
return new BiomeRequirement(key, tag);
}
public boolean test(Level pLevel, BlockEntity pBlockEntity) {
if(biomeResourceKey == null && biomeTagKey == null)
return true;
Holder<Biome> blockEntityBiome = pLevel.getBiome(pBlockEntity.getBlockPos());
/*if(pLevel.isClientSide()){
return false;
}*/
RegistryAccess registryAccess;
if(pLevel.isClientSide())
registryAccess = Objects.requireNonNull(Minecraft.getInstance().getConnection()).registryAccess();
registryAccess = pLevel.registryAccess();
Optional<Holder.Reference<Biome>> requiredBiomeHolder = Objects.requireNonNull(registryAccess.registryOrThrow(Registries.BIOME).asLookup().get(biomeResourceKey));
if(requiredBiomeHolder.isPresent()
&& blockEntityBiome.is(requiredBiomeHolder.get().key()))
return true;
return registryAccess.registryOrThrow(Registries.BIOME).getTag(biomeTagKey).map(t ->
t.contains(blockEntityBiome)
).orElse(false);
}
public boolean isPresent(){
if(biomeTagKey == null && biomeResourceKey == null)
return false;
return true;
}
public String toString(){
if(biomeTagKey == null && biomeResourceKey == null)
return null;
if(biomeResourceKey != null)
return biomeResourceKey.location().toString();
return biomeTagKey.location().toString();
}
@Override
public RecipeRequirementType<?> getType() {
return TYPE;
}
private static class BiomeRequirementType extends RecipeRequirementType<BiomeRequirement> {
public BiomeRequirementType() {
super("biome");
}
public BiomeRequirementType(String id) {
super(id);
}
@Override
public BiomeRequirement fromJson(JsonObject pJson) {
if (GsonHelper.isValidNode(pJson, "biome")) {
ResourceKey<Biome> biomeResourceKey = ResourceKey.codec(Registries.BIOME).parse(JsonOps.INSTANCE, pJson.get("biome")).result().get();
TagKey<Biome> biomeTag = TagKey.codec(Registries.BIOME).parse(JsonOps.INSTANCE, pJson.get("biome")).result().get();
return BiomeRequirement.of(biomeResourceKey,biomeTag);
}
return BiomeRequirement.EMPTY;
}
@Override
public JsonObject toJson(JsonObject pJson, RecipeRequirement pRecipeRequirement){
if(!pRecipeRequirement.isPresent())
return pJson;
pJson.addProperty("biome", pRecipeRequirement.toString());
return pJson;
}
@Override
public BiomeRequirement fromNetwork(FriendlyByteBuf buffer) {
boolean hasRequirement = buffer.readBoolean();
if(hasRequirement) {
ResourceLocation rl = buffer.readResourceLocation();
if (NULL.equals(rl)) return BiomeRequirement.EMPTY;
else return BiomeRequirement.of(TagKey.create(Registries.BIOME, rl));
}
return BiomeRequirement.EMPTY;
}
@Override
public void toNetwork(FriendlyByteBuf buffer, RecipeRequirement pRecipeRequirement) {
if(pRecipeRequirement == null)
pRecipeRequirement = new BiomeRequirement();
if(pRecipeRequirement instanceof BiomeRequirement){
buffer.writeBoolean(pRecipeRequirement.isPresent());
if(pRecipeRequirement.isPresent()) {
TagKey<Biome> biome = ((BiomeRequirement) pRecipeRequirement).biomeTagKey;
buffer.writeResourceLocation(biome.location());
}
}
}
}
}

View File

@@ -0,0 +1,82 @@
package com.oierbravo.mechanical_lemon_lib.foundation.recipe.requirements;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import com.oierbravo.mechanical_lemon_lib.foundation.recipe.IRecipeRequirement;
import com.oierbravo.mechanical_lemon_lib.foundation.recipe.RecipeRequirementType;
import com.oierbravo.mechanical_lemon_lib.register.MechanicalLemonRecipeRequirementTypes;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.BiomeTags;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BlockEntity;
import java.util.Optional;
public record BiomeTagRequirement(TagKey<Biome> tag) implements IRecipeRequirement {
public static String ID = "biome_tag";
public BiomeTagRequirement(ResourceLocation resourceLocation){
this(TagKey.create(Registries.BIOME,resourceLocation));
}
public static MapCodec<BiomeTagRequirement> CODEC = RecordCodecBuilder
.mapCodec((builder)
-> builder
//.group(TagKey.codec(Registries.BIOME).optionalFieldOf("value", null)
.group(ResourceLocation.CODEC.optionalFieldOf("value", null)
.forGetter(BiomeTagRequirement::getResourceLocation)).apply(builder,BiomeTagRequirement::new));
public static final StreamCodec<RegistryFriendlyByteBuf, BiomeTagRequirement> STREAM_CODEC = StreamCodec.composite(
ResourceLocation.STREAM_CODEC, BiomeTagRequirement::getResourceLocation,
BiomeTagRequirement::new
);
public ResourceLocation getResourceLocation(){
return tag.location();
}
/* public static final StreamCodec<RegistryFriendlyByteBuf, BiomeTagRequirement> STREAM_CODEC = StreamCodec.composite(
ResourceKey.streamCodec(Registries.BIOME), BiomeTagRequirement::tag,
BiomeTagRequirement::new
);*/
public static BiomeTagRequirement of(TagKey<Biome> tag) {
return new BiomeTagRequirement(tag);
}
public boolean test(Level pLevel, BlockEntity pBlockEntity) {
if(tag == null)
return true;
Holder<Biome> blockEntityBiome = pLevel.getBiome(pBlockEntity.getBlockPos());
if(pLevel.isClientSide()){
return false;
}
return pLevel.getServer().registryAccess().registryOrThrow(Registries.BIOME).getTag(tag).map(t ->
t.contains(blockEntityBiome)
).orElse(false);
}
@Override
public RecipeRequirementType<?> getType() {
return MechanicalLemonRecipeRequirementTypes.BIOME_TAG.get();
}
@Override
public String getIdString() {
return ID;
}
@Override
public String toString() {
return tag.location().toString();
}
}

View File

@@ -33,14 +33,9 @@ public record MaxSpeedRequirement(Float speed) implements IRecipeRequirement {
return false;
}
/* @Override
public boolean isPresent() {
return false;
}*/
@Override
public RecipeRequirementType<?> getType() {
return MechanicalLemonRecipeRequirementTypes.MIN_SPEED.get();
return MechanicalLemonRecipeRequirementTypes.MAX_SPEED.get();
}
@Override

View File

@@ -13,7 +13,7 @@ import net.minecraft.network.codec.StreamCodec;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
public record MaxYRequirement(Integer maxY) implements IRecipeRequirement{
public record MaxYRequirement(Integer maxY) implements IRecipeRequirement {
public static String ID = "max_y";
public static MapCodec<MaxYRequirement> CODEC = RecordCodecBuilder
@@ -39,11 +39,6 @@ public record MaxYRequirement(Integer maxY) implements IRecipeRequirement{
return pos.getCenter().y <= maxY;
}
/* @Override
public boolean isPresent() {
return false;
}*/
@Override
public RecipeRequirementType<?> getType() {
return MechanicalLemonRecipeRequirementTypes.MAX_Y.get();

View File

@@ -33,11 +33,6 @@ public record MinSpeedRequirement(Float speed) implements IRecipeRequirement {
return false;
}
/* @Override
public boolean isPresent() {
return false;
}*/
@Override
public RecipeRequirementType<?> getType() {
return MechanicalLemonRecipeRequirementTypes.MIN_SPEED.get();

View File

@@ -39,11 +39,6 @@ public record MinYRequirement(Integer minY) implements IRecipeRequirement {
return pos.getCenter().y >= minY;
}
/*@Override
public boolean isPresent() {
return false;
}*/
@Override
public RecipeRequirementType<?> getType() {
return MechanicalLemonRecipeRequirementTypes.MIN_Y.get();

View File

@@ -4,10 +4,7 @@ import com.mojang.serialization.MapCodec;
import com.oierbravo.mechanical_lemon_lib.MechanicalLemonLib;
import com.oierbravo.mechanical_lemon_lib.foundation.recipe.IRecipeRequirement;
import com.oierbravo.mechanical_lemon_lib.foundation.recipe.RecipeRequirementType;
import com.oierbravo.mechanical_lemon_lib.foundation.recipe.requirements.MaxSpeedRequirement;
import com.oierbravo.mechanical_lemon_lib.foundation.recipe.requirements.MaxYRequirement;
import com.oierbravo.mechanical_lemon_lib.foundation.recipe.requirements.MinYRequirement;
import com.oierbravo.mechanical_lemon_lib.foundation.recipe.requirements.MinSpeedRequirement;
import com.oierbravo.mechanical_lemon_lib.foundation.recipe.requirements.*;
import net.minecraft.network.codec.StreamCodec;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.registries.DeferredRegister;
@@ -31,6 +28,12 @@ public class MechanicalLemonRecipeRequirementTypes {
public static final Supplier<RecipeRequirementType<MaxYRequirement>> MAX_Y =
register(MaxYRequirement.ID, MaxYRequirement.CODEC, MaxYRequirement.STREAM_CODEC);
public static final Supplier<RecipeRequirementType<BiomeRequirement>> BIOME =
register(BiomeRequirement.ID, BiomeRequirement.CODEC, BiomeRequirement.STREAM_CODEC);
public static final Supplier<RecipeRequirementType<BiomeTagRequirement>> BIOME_TAG =
register(BiomeTagRequirement.ID, BiomeTagRequirement.CODEC, BiomeTagRequirement.STREAM_CODEC);
public static void init(IEventBus modEventBus) {
RECIPE_REQUIREMENT_TYPES.register(modEventBus);
}

View File

@@ -1,15 +1,19 @@
{
"mechanical_lemon_lib.ui.progress": "Progress: %d%%",
"itemGroup.mechanical_lemon_lib": "Mechanicals",
"mechanical_lemon_lib.ui.recipe.requirements.title": "Requirements:",
"mechanical_lemon_lib.ui.recipe_requirement.none.tooltip": "No specific requirement",
"mechanical_lemon_lib.ui.recipe_requirement.biome.tooltip": "Biome: %s",
"mechanical_lemon_lib.ui.recipe_requirement.biome_tag.tooltip": "Biome: %s",
"mechanical_lemon_lib.ui.recipe_requirement.min_y.tooltip": "Min Y: %s",
"mechanical_lemon_lib.ui.recipe_requirement.max_y.tooltip": "Max Y: %s",
"mechanical_lemon_lib.ui.recipe_requirement.min_speed.tooltip": "Min Speed: %s",
"mechanical_lemon_lib.ui.recipe_requirement.max_speed.tooltip": "Max Speed: %s",
"mechanical_lemon_lib.ui.recipe_requirement.biome.missing": "Incorrect biome",
"mechanical_lemon_lib.ui.recipe_requirement.max_y.missing": "Too high",
"mechanical_lemon_lib.ui.recipe_requirement.min_y.missing": "Too low",
"mechanical_lemon_lib.ui.recipe_requirement.max_y.missing": "Y position Too high",
"mechanical_lemon_lib.ui.recipe_requirement.min_y.missing": "Y position Too low",
"mechanical_lemon_lib.ui.recipe_requirement.min_speed.missing": "Not enough speed",
"mechanical_lemon_lib.ui.recipe_requirement.max_speed.missing": "Too fast",
"mechanical_lemon_lib.ui.recipe_requirement.output.missing": "Output full or incompatible",
"mechanical_lemon_lib.ui.recipe_requirement.ingredients.missing": "Missing ingredients"
}