Added JEI integration (#2436).

This commit is contained in:
Sebastian Hartte
2016-10-04 01:34:29 +02:00
parent b8344da734
commit 8df692053a
46 changed files with 1555 additions and 170 deletions
@@ -0,0 +1,40 @@
package appeng.integration.modules;
import appeng.helpers.Reflected;
import appeng.integration.IIntegrationModule;
import appeng.integration.abstraction.IJEI;
import appeng.integration.modules.jei.NullJEI;
public class JEI implements IIntegrationModule
{
@Reflected
public static JEI instance;
private IJEI jei = new NullJEI();
@Override
public void init() throws Throwable
{
}
@Override
public void postInit()
{
}
public void setJei( IJEI jei )
{
this.jei = jei;
}
public IJEI getJei()
{
return jei;
}
}
@@ -0,0 +1,125 @@
package appeng.integration.modules.jei;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.I18n;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import mezz.jei.api.IGuiHelper;
import mezz.jei.api.gui.IDrawable;
import mezz.jei.api.gui.IDrawableAnimated;
import mezz.jei.api.gui.IDrawableStatic;
import mezz.jei.api.gui.IGuiItemStackGroup;
import mezz.jei.api.gui.IRecipeLayout;
import mezz.jei.api.ingredients.IIngredients;
import mezz.jei.api.recipe.BlankRecipeCategory;
import appeng.api.AEApi;
import appeng.api.config.CondenserOutput;
import appeng.api.definitions.IMaterials;
import appeng.api.implementations.items.IStorageComponent;
import appeng.core.AppEng;
import appeng.tile.misc.TileCondenser;
class CondenserCategory extends BlankRecipeCategory<CondenserOutputWrapper>
{
public static final String UID = "appliedenergistics2.condenser";
private final String localizedName;
private final IDrawable background;
private final IDrawable iconTrash;
private final IDrawableAnimated progress;
private final IDrawable iconButton;
public CondenserCategory( IGuiHelper guiHelper )
{
this.localizedName = I18n.format( "gui.appliedenergistics2.Condenser" );
ResourceLocation location = new ResourceLocation( AppEng.MOD_ID, "textures/guis/condenser.png" );
this.background = guiHelper.createDrawable( location, 50, 25, 94, 48 );
ResourceLocation statesLocation = new ResourceLocation( AppEng.MOD_ID, "textures/guis/states.png" );
this.iconTrash = guiHelper.createDrawable( statesLocation, 241, 81, 14, 14, 28, 0, 2, 0 );
this.iconButton = guiHelper.createDrawable( statesLocation, 240, 240, 16, 16, 28, 0, 78, 0 );
IDrawableStatic progressDrawable = guiHelper.createDrawable( location, 178, 25, 6, 18, 0, 0, 70, 0 );
this.progress = guiHelper.createAnimatedDrawable( progressDrawable, 40, IDrawableAnimated.StartDirection.BOTTOM, false );
}
@Override
public String getUid()
{
return CondenserCategory.UID;
}
@Override
public String getTitle()
{
return localizedName;
}
@Override
public IDrawable getBackground()
{
return background;
}
@Override
public void drawAnimations( Minecraft minecraft )
{
progress.draw( minecraft );
}
@Override
public void drawExtras( Minecraft minecraft )
{
iconTrash.draw( minecraft );
iconButton.draw( minecraft );
}
@Override
public void setRecipe( IRecipeLayout recipeLayout, CondenserOutputWrapper recipeWrapper, IIngredients ingredients )
{
IGuiItemStackGroup itemStacks = recipeLayout.getItemStacks();
itemStacks.init( 0, false, 54, 26 );
// Get all storage cells and cycle them through a fake input slot
itemStacks.init( 1, true, 50, 0 );
itemStacks.set( 1, getViableStorageComponents( recipeWrapper ) );
// This only sets the output
itemStacks.set( ingredients );
}
private List<ItemStack> getViableStorageComponents( CondenserOutputWrapper recipeWrapper )
{
CondenserOutput condenserOutput = recipeWrapper.getCondenserOutput();
IMaterials materials = AEApi.instance().definitions().materials();
List<ItemStack> viableComponents = new ArrayList<>();
materials.cell1kPart().maybeStack( 1 ).ifPresent( itemStack -> addViableComponent( condenserOutput, viableComponents, itemStack ) );
materials.cell4kPart().maybeStack( 1 ).ifPresent( itemStack -> addViableComponent( condenserOutput, viableComponents, itemStack ) );
materials.cell16kPart().maybeStack( 1 ).ifPresent( itemStack -> addViableComponent( condenserOutput, viableComponents, itemStack ) );
materials.cell64kPart().maybeStack( 1 ).ifPresent( itemStack -> addViableComponent( condenserOutput, viableComponents, itemStack ) );
return viableComponents;
}
private void addViableComponent( CondenserOutput condenserOutput, List<ItemStack> viableComponents, ItemStack itemStack )
{
IStorageComponent comp = (IStorageComponent) itemStack.getItem();
int storage = comp.getBytes( itemStack ) * TileCondenser.BYTE_MULTIPLIER;
if( storage >= condenserOutput.requiredPower )
{
viableComponents.add( itemStack );
}
}
}
@@ -0,0 +1,79 @@
package appeng.integration.modules.jei;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import mezz.jei.api.IGuiHelper;
import mezz.jei.api.gui.IDrawable;
import mezz.jei.api.recipe.IRecipeHandler;
import mezz.jei.api.recipe.IRecipeWrapper;
import appeng.api.config.CondenserOutput;
import appeng.core.AppEng;
class CondenserOutputHandler implements IRecipeHandler<CondenserOutput>
{
private final ItemStack matterBall;
private final ItemStack singularity;
private final IDrawable iconButtonMatterBall;
private final IDrawable iconButtonSingularity;
public CondenserOutputHandler( IGuiHelper guiHelper, ItemStack matterBall, ItemStack singularity )
{
this.matterBall = matterBall;
this.singularity = singularity;
ResourceLocation statesLocation = new ResourceLocation( AppEng.MOD_ID, "textures/guis/states.png" );
this.iconButtonMatterBall = guiHelper.createDrawable( statesLocation, 16, 112, 14, 14, 28, 0, 78, 0 );
this.iconButtonSingularity = guiHelper.createDrawable( statesLocation, 32, 112, 14, 14, 28, 0, 78, 0 );
}
@Override
public Class<CondenserOutput> getRecipeClass()
{
return CondenserOutput.class;
}
@Override
public String getRecipeCategoryUid()
{
return CondenserCategory.UID;
}
@Override
public String getRecipeCategoryUid( CondenserOutput recipe )
{
return CondenserCategory.UID;
}
@Override
public IRecipeWrapper getRecipeWrapper( CondenserOutput recipe )
{
switch( recipe )
{
case MATTER_BALLS:
return new CondenserOutputWrapper( recipe, matterBall, iconButtonMatterBall );
case SINGULARITY:
return new CondenserOutputWrapper( recipe, singularity, iconButtonSingularity );
default:
return null;
}
}
@Override
public boolean isRecipeValid( CondenserOutput recipe )
{
switch( recipe )
{
case MATTER_BALLS:
return matterBall != null;
case SINGULARITY:
return singularity != null;
default:
return false;
}
}
}
@@ -0,0 +1,81 @@
package appeng.integration.modules.jei;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;
import com.google.common.base.Splitter;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.I18n;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fml.client.config.HoverChecker;
import mezz.jei.api.gui.IDrawable;
import mezz.jei.api.ingredients.IIngredients;
import mezz.jei.api.recipe.BlankRecipeWrapper;
import appeng.api.config.CondenserOutput;
class CondenserOutputWrapper extends BlankRecipeWrapper
{
private final ItemStack outputItem;
private final CondenserOutput condenserOutput;
private final HoverChecker buttonHoverChecker;
private final IDrawable buttonIcon;
CondenserOutputWrapper( CondenserOutput condenserOutput, ItemStack outputItem, IDrawable buttonIcon )
{
this.condenserOutput = condenserOutput;
this.outputItem = outputItem;
this.buttonIcon = buttonIcon;
this.buttonHoverChecker = new HoverChecker( 28, 28 + 16, 78, 78 + 16, 0 );
}
@Override
public void getIngredients( IIngredients ingredients )
{
ingredients.setOutput( ItemStack.class, outputItem );
}
public CondenserOutput getCondenserOutput()
{
return condenserOutput;
}
@Nullable
@Override
public List<String> getTooltipStrings( int mouseX, int mouseY )
{
if( buttonHoverChecker.checkHover( mouseX, mouseY ) )
{
String key;
switch( condenserOutput )
{
case MATTER_BALLS:
key = "gui.tooltips.appliedenergistics2.MatterBalls";
break;
case SINGULARITY:
key = "gui.tooltips.appliedenergistics2.Singularity";
break;
default:
return Collections.emptyList();
}
return Splitter.on( "\\n" ).splitToList( I18n.format( key, condenserOutput.requiredPower ) );
}
return Collections.emptyList();
}
@Override
public void drawInfo( Minecraft minecraft, int recipeWidth, int recipeHeight, int mouseX, int mouseY )
{
buttonIcon.draw( minecraft );
}
}
@@ -0,0 +1,65 @@
package appeng.integration.modules.jei;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.item.ItemStack;
import mezz.jei.api.ingredients.IIngredients;
import mezz.jei.api.recipe.BlankRecipeWrapper;
import mezz.jei.api.recipe.wrapper.IShapedCraftingRecipeWrapper;
/**
* Acts as a fake facade recipe wrapper, created by {@link FacadeRegistryPlugin}.
*/
class FacadeRecipeWrapper extends BlankRecipeWrapper implements IShapedCraftingRecipeWrapper
{
private final ItemStack textureItem;
private final ItemStack cableAnchor;
private final ItemStack facade;
FacadeRecipeWrapper( ItemStack textureItem, ItemStack cableAnchor, ItemStack facade )
{
this.textureItem = textureItem;
this.cableAnchor = cableAnchor;
this.facade = facade;
}
@Override
public int getWidth()
{
return 3;
}
@Override
public int getHeight()
{
return 3;
}
@Override
public void getIngredients( IIngredients ingredients )
{
List<ItemStack> input = new ArrayList<>( 9 );
input.add( null );
input.add( cableAnchor );
input.add( null );
input.add( cableAnchor );
input.add( textureItem );
input.add( cableAnchor );
input.add( null );
input.add( cableAnchor );
input.add( null );
ingredients.setInputs( ItemStack.class, input );
ingredients.setOutput( ItemStack.class, facade );
}
}
@@ -0,0 +1,95 @@
package appeng.integration.modules.jei;
import java.util.Collections;
import java.util.List;
import net.minecraft.item.ItemStack;
import mezz.jei.api.recipe.IFocus;
import mezz.jei.api.recipe.IRecipeCategory;
import mezz.jei.api.recipe.IRecipeRegistryPlugin;
import mezz.jei.api.recipe.IRecipeWrapper;
import mezz.jei.api.recipe.VanillaRecipeCategoryUid;
import appeng.items.parts.ItemFacade;
/**
* This plugin will dynamically add facade recipes for any item that can be turned into a facade.
*/
class FacadeRegistryPlugin implements IRecipeRegistryPlugin
{
private final ItemFacade itemFacade;
private final ItemStack cableAnchor;
FacadeRegistryPlugin( ItemFacade itemFacade, ItemStack cableAnchor )
{
this.itemFacade = itemFacade;
this.cableAnchor = cableAnchor;
}
@Override
public <V> List<String> getRecipeCategoryUids( IFocus<V> focus )
{
if( focus.getMode() == IFocus.Mode.OUTPUT && focus.getValue() instanceof ItemStack )
{
// Looking up how a certain facade is crafted
ItemStack itemStack = (ItemStack) focus.getValue();
if( itemStack.getItem() instanceof ItemFacade )
{
return Collections.singletonList( VanillaRecipeCategoryUid.CRAFTING );
}
}
else if( focus.getMode() == IFocus.Mode.INPUT && focus.getValue() instanceof ItemStack )
{
// Looking up if a certain block can be used to make a facade
ItemStack itemStack = (ItemStack) focus.getValue();
if( itemFacade.createFacadeForItem( itemStack, true ) != null )
{
return Collections.singletonList( VanillaRecipeCategoryUid.CRAFTING );
}
}
return Collections.emptyList();
}
@SuppressWarnings( "unchecked" )
@Override
public <T extends IRecipeWrapper, V> List<T> getRecipeWrappers( IRecipeCategory<T> recipeCategory, IFocus<V> focus )
{
if( !VanillaRecipeCategoryUid.CRAFTING.equals( recipeCategory.getUid() ) )
{
return Collections.emptyList();
}
if( focus.getMode() == IFocus.Mode.OUTPUT && focus.getValue() instanceof ItemStack )
{
// Looking up how a certain facade is crafted
ItemStack itemStack = (ItemStack) focus.getValue();
if( itemStack.getItem() instanceof ItemFacade )
{
ItemFacade facadeItem = (ItemFacade) itemStack.getItem();
ItemStack textureItem = facadeItem.getTextureItem( itemStack );
return Collections.singletonList( (T) new FacadeRecipeWrapper( textureItem, cableAnchor, itemStack ) );
}
}
else if( focus.getMode() == IFocus.Mode.INPUT && focus.getValue() instanceof ItemStack )
{
// Looking up if a certain block can be used to make a facade
ItemStack itemStack = (ItemStack) focus.getValue();
ItemStack facade = itemFacade.createFacadeForItem( itemStack, false );
if( facade != null )
{
return Collections.singletonList( (T) new FacadeRecipeWrapper( itemStack, cableAnchor, facade ) );
}
}
return Collections.emptyList();
}
}
@@ -0,0 +1,64 @@
package appeng.integration.modules.jei;
import net.minecraft.client.resources.I18n;
import net.minecraft.util.ResourceLocation;
import mezz.jei.api.IGuiHelper;
import mezz.jei.api.gui.IDrawable;
import mezz.jei.api.gui.IGuiItemStackGroup;
import mezz.jei.api.gui.IRecipeLayout;
import mezz.jei.api.ingredients.IIngredients;
import mezz.jei.api.recipe.BlankRecipeCategory;
import appeng.core.AppEng;
class GrinderRecipeCategory extends BlankRecipeCategory<GrinderRecipeWrapper>
{
public static final String UID = "appliedenergistics2.grinder";
private final String localizedName;
private final IDrawable background;
public GrinderRecipeCategory( IGuiHelper guiHelper )
{
this.localizedName = I18n.format( "tile.appliedenergistics2.grindstone.name" );
ResourceLocation location = new ResourceLocation( AppEng.MOD_ID, "textures/guis/grinder.png" );
this.background = guiHelper.createDrawable( location, 11, 16, 154, 64 );
}
@Override
public String getUid()
{
return GrinderRecipeCategory.UID;
}
@Override
public String getTitle()
{
return localizedName;
}
@Override
public IDrawable getBackground()
{
return background;
}
@Override
public void setRecipe( IRecipeLayout recipeLayout, GrinderRecipeWrapper recipeWrapper, IIngredients ingredients )
{
IGuiItemStackGroup itemStacks = recipeLayout.getItemStacks();
itemStacks.init( 0, true, 0, 0 );
itemStacks.init( 1, false, 100, 46 );
itemStacks.init( 2, false, 118, 46 );
itemStacks.init( 3, false, 136, 46 );
itemStacks.set( ingredients );
}
}
@@ -0,0 +1,42 @@
package appeng.integration.modules.jei;
import mezz.jei.api.recipe.IRecipeHandler;
import mezz.jei.api.recipe.IRecipeWrapper;
import appeng.api.features.IGrinderEntry;
class GrinderRecipeHandler implements IRecipeHandler<IGrinderEntry>
{
@Override
public Class<IGrinderEntry> getRecipeClass()
{
return IGrinderEntry.class;
}
@Override
public String getRecipeCategoryUid()
{
return GrinderRecipeCategory.UID;
}
@Override
public String getRecipeCategoryUid( IGrinderEntry recipe )
{
return GrinderRecipeCategory.UID;
}
@Override
public IRecipeWrapper getRecipeWrapper( IGrinderEntry recipe )
{
return new GrinderRecipeWrapper( recipe );
}
@Override
public boolean isRecipeValid( IGrinderEntry recipe )
{
return true;
}
}
@@ -0,0 +1,77 @@
package appeng.integration.modules.jei;
import java.awt.Color;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.item.ItemStack;
import mezz.jei.api.ingredients.IIngredients;
import mezz.jei.api.recipe.BlankRecipeWrapper;
import appeng.api.features.IGrinderEntry;
class GrinderRecipeWrapper extends BlankRecipeWrapper
{
private final IGrinderEntry recipe;
GrinderRecipeWrapper( IGrinderEntry recipe )
{
this.recipe = recipe;
}
@Override
public void getIngredients( IIngredients ingredients )
{
ingredients.setInput( ItemStack.class, recipe.getInput() );
List<ItemStack> outputs = new ArrayList<>( 3 );
outputs.add( recipe.getOutput() );
if( recipe.getOptionalOutput() != null )
{
outputs.add( recipe.getOptionalOutput() );
}
if( recipe.getSecondOptionalOutput() != null )
{
outputs.add( recipe.getSecondOptionalOutput() );
}
ingredients.setOutputs( ItemStack.class, outputs );
}
@Override
public void drawInfo( Minecraft minecraft, int recipeWidth, int recipeHeight, int mouseX, int mouseY )
{
FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
int x = 118;
final float scale = 0.85f;
final float invScale = 1 / scale;
GlStateManager.scale( scale, scale, 1 );
if( recipe.getOptionalOutput() != null )
{
String text = String.format( "%d%%", (int) ( recipe.getOptionalChance() * 100 ) );
float width = fr.getStringWidth( text ) * scale;
int xScaled = (int) Math.round( ( x + ( 18 - width ) / 2 ) * invScale );
fr.drawString( text, xScaled, (int) ( 65 * invScale ), Color.gray.getRGB() );
x += 18;
}
if( recipe.getSecondOptionalOutput() != null )
{
String text = String.format( "%d%%", (int) ( recipe.getSecondOptionalChance() * 100 ) );
float width = fr.getStringWidth( text ) * scale;
int xScaled = (int) Math.round( ( x + ( 18 - width ) / 2 ) * invScale );
fr.drawString( text, xScaled, (int) ( 65 * invScale ), Color.gray.getRGB() );
}
GlStateManager.scale( invScale, invScale, 1 );
}
}
@@ -0,0 +1,82 @@
package appeng.integration.modules.jei;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.I18n;
import net.minecraft.util.ResourceLocation;
import mezz.jei.api.IGuiHelper;
import mezz.jei.api.gui.IDrawable;
import mezz.jei.api.gui.IDrawableAnimated;
import mezz.jei.api.gui.IDrawableStatic;
import mezz.jei.api.gui.IGuiItemStackGroup;
import mezz.jei.api.gui.IRecipeLayout;
import mezz.jei.api.ingredients.IIngredients;
import mezz.jei.api.recipe.BlankRecipeCategory;
import appeng.core.AppEng;
class InscriberRecipeCategory extends BlankRecipeCategory<InscriberRecipeWrapper>
{
private static final int SLOT_INPUT_TOP = 0;
private static final int SLOT_INPUT_MIDDLE = 1;
private static final int SLOT_INPUT_BOTTOM = 2;
private static final int SLOT_OUTPUT = 3;
static final String UID = "appliedenergistics2.inscriber";
private final IDrawable background;
private final String localizedName;
private final IDrawableAnimated progress;
public InscriberRecipeCategory( IGuiHelper guiHelper )
{
ResourceLocation location = new ResourceLocation( AppEng.MOD_ID, "textures/guis/inscriber.png" );
this.background = guiHelper.createDrawable( location, 44, 15, 97, 64 );
this.localizedName = I18n.format( "tile.appliedenergistics2.inscriber.name" );
IDrawableStatic progressDrawable = guiHelper.createDrawable( location, 135, 177, 6, 18, 24, 0, 91, 0 );
this.progress = guiHelper.createAnimatedDrawable( progressDrawable, 40, IDrawableAnimated.StartDirection.BOTTOM, false );
}
@Override
public String getUid()
{
return UID;
}
@Override
public String getTitle()
{
return localizedName;
}
@Override
public IDrawable getBackground()
{
return background;
}
@Override
public void drawAnimations( Minecraft minecraft )
{
this.progress.draw( minecraft );
}
@Override
public void setRecipe( IRecipeLayout recipeLayout, InscriberRecipeWrapper recipeWrapper, IIngredients ingredients )
{
IGuiItemStackGroup itemStacks = recipeLayout.getItemStacks();
itemStacks.init( SLOT_INPUT_TOP, true, 0, 0 );
itemStacks.init( SLOT_INPUT_MIDDLE, true, 18, 23 );
itemStacks.init( SLOT_INPUT_BOTTOM, true, 0, 46 );
itemStacks.init( SLOT_OUTPUT, false, 68, 24 );
itemStacks.set( ingredients );
}
}
@@ -0,0 +1,43 @@
package appeng.integration.modules.jei;
import mezz.jei.api.recipe.IRecipeHandler;
import mezz.jei.api.recipe.IRecipeWrapper;
import appeng.api.features.IInscriberRecipe;
class InscriberRecipeHandler implements IRecipeHandler<IInscriberRecipe>
{
@Override
public Class<IInscriberRecipe> getRecipeClass()
{
return IInscriberRecipe.class;
}
@Override
public String getRecipeCategoryUid()
{
return InscriberRecipeCategory.UID;
}
@Override
public String getRecipeCategoryUid( IInscriberRecipe recipe )
{
return InscriberRecipeCategory.UID;
}
@Override
public IRecipeWrapper getRecipeWrapper( IInscriberRecipe recipe )
{
return new InscriberRecipeWrapper( recipe );
}
@Override
public boolean isRecipeValid( IInscriberRecipe recipe )
{
return true;
}
}
@@ -0,0 +1,38 @@
package appeng.integration.modules.jei;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.minecraft.item.ItemStack;
import mezz.jei.api.ingredients.IIngredients;
import mezz.jei.api.recipe.BlankRecipeWrapper;
import appeng.api.features.IInscriberRecipe;
class InscriberRecipeWrapper extends BlankRecipeWrapper
{
private final IInscriberRecipe recipe;
public InscriberRecipeWrapper( IInscriberRecipe recipe )
{
this.recipe = recipe;
}
@Override
public void getIngredients( IIngredients ingredients )
{
List<List<ItemStack>> inputSlots = new ArrayList<>( 3 );
inputSlots.add( Collections.singletonList( recipe.getTopOptional().orElse( null ) ) );
inputSlots.add( recipe.getInputs() );
inputSlots.add( Collections.singletonList( recipe.getBottomOptional().orElse( null ) ) );
ingredients.setInputLists( ItemStack.class, inputSlots );
ingredients.setOutput( ItemStack.class, recipe.getOutput() );
}
}
@@ -0,0 +1,51 @@
package appeng.integration.modules.jei;
import java.util.Collections;
import java.util.List;
import net.minecraft.item.ItemStack;
import mezz.jei.api.recipe.IFocus;
import mezz.jei.api.recipe.IRecipeCategory;
import mezz.jei.api.recipe.IRecipeRegistryPlugin;
import mezz.jei.api.recipe.IRecipeWrapper;
import appeng.api.AEApi;
import appeng.api.features.IInscriberRegistry;
/**
* Exposes the inscriber registry recipes to JEI.
*/
class InscriberRegistryPlugin implements IRecipeRegistryPlugin
{
private final IInscriberRegistry inscriber = AEApi.instance().registries().inscriber();
@Override
public <V> List<String> getRecipeCategoryUids( IFocus<V> focus )
{
if( !( focus.getValue() instanceof ItemStack ) )
{
return Collections.emptyList();
}
if( focus.getMode() == IFocus.Mode.INPUT )
{
ItemStack input = (ItemStack) focus.getValue();
for( ItemStack validInput : inscriber.getInputs() )
{
}
}
return Collections.emptyList();
}
@Override
public <T extends IRecipeWrapper, V> List<T> getRecipeWrappers( IRecipeCategory<T> recipeCategory, IFocus<V> focus )
{
return null;
}
}
@@ -0,0 +1,185 @@
package appeng.integration.modules.jei;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import com.google.common.collect.ImmutableList;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import mezz.jei.api.BlankModPlugin;
import mezz.jei.api.IJeiRuntime;
import mezz.jei.api.IModRegistry;
import appeng.api.AEApi;
import appeng.api.config.CondenserOutput;
import appeng.api.definitions.IDefinitions;
import appeng.api.definitions.IItemDefinition;
import appeng.api.definitions.IMaterials;
import appeng.api.features.IInscriberRecipe;
import appeng.container.implementations.ContainerCraftingTerm;
import appeng.container.implementations.ContainerPatternTerm;
import appeng.core.AEConfig;
import appeng.core.features.AEFeature;
import appeng.core.localization.GuiText;
import appeng.integration.IntegrationRegistry;
import appeng.integration.IntegrationType;
import appeng.integration.modules.JEI;
import appeng.items.parts.ItemFacade;
@mezz.jei.api.JEIPlugin
public class JEIPlugin extends BlankModPlugin
{
@Override
public void register( IModRegistry registry )
{
registry.addRecipeHandlers( new ShapedRecipeHandler(), new ShapelessRecipeHandler() );
IDefinitions definitions = AEApi.instance().definitions();
registerFacadeRecipe( definitions, registry );
registerInscriberRecipes( definitions, registry );
registerCondenserRecipes( definitions, registry );
registerGrinderRecipes( definitions, registry );
registerDescriptions( definitions, registry );
// Allow recipe transfer from JEI to crafting and pattern terminal
registry.getRecipeTransferRegistry().addRecipeTransferHandler( new RecipeTransferHandler<>( ContainerCraftingTerm.class ) );
registry.getRecipeTransferRegistry().addRecipeTransferHandler( new RecipeTransferHandler<>( ContainerPatternTerm.class ) );
}
private void registerDescriptions( IDefinitions definitions, IModRegistry registry )
{
IMaterials materials = definitions.materials();
final String message;
if( AEConfig.instance.isFeatureEnabled( AEFeature.CertusQuartzWorldGen ) )
{
message = GuiText.ChargedQuartz.getLocal() + "\n\n" + GuiText.ChargedQuartzFind.getLocal();
}
else
{
message = GuiText.ChargedQuartzFind.getLocal();
}
addDescription( registry, materials.certusQuartzCrystalCharged(), message );
if( AEConfig.instance.isFeatureEnabled( AEFeature.MeteoriteWorldGen ) )
{
addDescription( registry, materials.logicProcessorPress(), GuiText.inWorldCraftingPresses.getLocal() );
addDescription( registry, materials.calcProcessorPress(), GuiText.inWorldCraftingPresses.getLocal() );
addDescription( registry, materials.engProcessorPress(), GuiText.inWorldCraftingPresses.getLocal() );
}
if( AEConfig.instance.isFeatureEnabled( AEFeature.InWorldFluix ) )
{
addDescription( registry, materials.fluixCrystal(), GuiText.inWorldFluix.getLocal() );
}
if( AEConfig.instance.isFeatureEnabled( AEFeature.InWorldSingularity ) )
{
addDescription( registry, materials.qESingularity(), GuiText.inWorldSingularity.getLocal() );
}
if( AEConfig.instance.isFeatureEnabled( AEFeature.InWorldPurification ) )
{
addDescription( registry, materials.purifiedCertusQuartzCrystal(), GuiText.inWorldPurificationCertus.getLocal() );
addDescription( registry, materials.purifiedNetherQuartzCrystal(), GuiText.inWorldPurificationNether.getLocal() );
addDescription( registry, materials.purifiedFluixCrystal(), GuiText.inWorldPurificationFluix.getLocal() );
}
}
private void addDescription( IModRegistry registry, IItemDefinition itemDefinition, String message )
{
itemDefinition.maybeStack( 1 ).ifPresent( itemStack -> registry.addDescription( itemStack, message ) );
}
private void registerGrinderRecipes( IDefinitions definitions, IModRegistry registry )
{
ItemStack grindstone = definitions.blocks().grindstone().maybeStack( 1 ).orElse( null );
if( grindstone == null )
{
return;
}
registry.addRecipes( AEApi.instance().registries().grinder().getRecipes() );
registry.addRecipeHandlers( new GrinderRecipeHandler() );
registry.addRecipeCategories( new GrinderRecipeCategory( registry.getJeiHelpers().getGuiHelper() ) );
registry.addRecipeCategoryCraftingItem( grindstone, GrinderRecipeCategory.UID );
}
private void registerCondenserRecipes( IDefinitions definitions, IModRegistry registry )
{
ItemStack condenser = definitions.blocks().condenser().maybeStack( 1 ).orElse( null );
if( condenser == null )
{
return;
}
ItemStack matterBall = definitions.materials().matterBall().maybeStack( 1 ).orElse( null );
if( matterBall != null )
{
registry.addRecipes( ImmutableList.of( CondenserOutput.MATTER_BALLS ) );
}
ItemStack singularity = definitions.materials().singularity().maybeStack( 1 ).orElse( null );
if( singularity != null )
{
registry.addRecipes( ImmutableList.of( CondenserOutput.SINGULARITY ) );
}
if( matterBall != null || singularity != null )
{
registry.addRecipeCategories( new CondenserCategory( registry.getJeiHelpers().getGuiHelper() ) );
registry.addRecipeCategoryCraftingItem( condenser, CondenserCategory.UID );
registry.addRecipeHandlers( new CondenserOutputHandler( registry.getJeiHelpers().getGuiHelper(), matterBall, singularity ) );
}
}
private void registerInscriberRecipes( IDefinitions definitions, IModRegistry registry )
{
registry.addRecipeHandlers( new InscriberRecipeHandler() );
registry.addRecipeCategories( new InscriberRecipeCategory( registry.getJeiHelpers().getGuiHelper() ) );
// Register the inscriber as the crafting item for the inscription category
definitions.blocks().inscriber().maybeStack( 1 ).ifPresent( inscriber ->
{
registry.addRecipeCategoryCraftingItem( inscriber, InscriberRecipeCategory.UID );
} );
List<IInscriberRecipe> inscriberRecipes = new ArrayList<>( AEApi.instance().registries().inscriber().getRecipes() );
registry.addRecipes( inscriberRecipes );
}
// Handle the generic crafting recipe for patterns in JEI
private void registerFacadeRecipe( IDefinitions definitions, IModRegistry registry )
{
Optional<Item> itemFacade = definitions.items().facade().maybeItem();
Optional<ItemStack> cableAnchor = definitions.parts().cableAnchor().maybeStack( 1 );
if( itemFacade.isPresent() && cableAnchor.isPresent() )
{
registry.addRecipeRegistryPlugin( new FacadeRegistryPlugin( (ItemFacade) itemFacade.get(), cableAnchor.get() ) );
}
}
@Override
public void onRuntimeAvailable( IJeiRuntime jeiRuntime )
{
JEI jeiModule = (JEI) IntegrationRegistry.INSTANCE.getInstance( IntegrationType.JEI );
jeiModule.setJei( new JeiRuntimeAdapter( jeiRuntime ) );
}
}
@@ -0,0 +1,38 @@
package appeng.integration.modules.jei;
import com.google.common.base.Strings;
import mezz.jei.api.IJeiRuntime;
import appeng.integration.abstraction.IJEI;
class JeiRuntimeAdapter implements IJEI
{
private final IJeiRuntime runtime;
JeiRuntimeAdapter( IJeiRuntime jeiRuntime )
{
this.runtime = jeiRuntime;
}
@Override
public boolean isEnabled()
{
return true;
}
@Override
public String getSearchText()
{
return Strings.nullToEmpty( runtime.getItemListOverlay().getFilterText() );
}
@Override
public void setSearchText( String searchText )
{
runtime.getItemListOverlay().setFilterText( Strings.nullToEmpty( searchText ) );
}
}
@@ -0,0 +1,25 @@
package appeng.integration.modules.jei;
import appeng.integration.abstraction.IJEI;
public class NullJEI implements IJEI
{
@Override
public boolean isEnabled()
{
return false;
}
@Override
public String getSearchText()
{
return "";
}
@Override
public void setSearchText( String searchText )
{
}
}
@@ -0,0 +1,125 @@
package appeng.integration.modules.jei;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import mezz.jei.api.gui.IGuiIngredient;
import mezz.jei.api.gui.IRecipeLayout;
import mezz.jei.api.recipe.VanillaRecipeCategoryUid;
import mezz.jei.api.recipe.transfer.IRecipeTransferError;
import mezz.jei.api.recipe.transfer.IRecipeTransferHandler;
import appeng.container.slot.SlotCraftingMatrix;
import appeng.container.slot.SlotFakeCraftingMatrix;
import appeng.core.AELog;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketJEIRecipe;
import appeng.util.Platform;
class RecipeTransferHandler<T extends Container> implements IRecipeTransferHandler<T>
{
private final Class<T> containerClass;
RecipeTransferHandler( Class<T> containerClass )
{
this.containerClass = containerClass;
}
@Override
public Class<T> getContainerClass()
{
return containerClass;
}
@Override
public String getRecipeCategoryUid()
{
return VanillaRecipeCategoryUid.CRAFTING;
}
@Nullable
@Override
public IRecipeTransferError transferRecipe( T container, IRecipeLayout recipeLayout, EntityPlayer player, boolean maxTransfer, boolean doTransfer )
{
if( !doTransfer )
{
return null;
}
Map<Integer, ? extends IGuiIngredient<ItemStack>> ingredients = recipeLayout.getItemStacks().getGuiIngredients();
final NBTTagCompound recipe = new NBTTagCompound();
int slotIndex = 0;
for( Map.Entry<Integer, ? extends IGuiIngredient<ItemStack>> ingredientEntry : ingredients.entrySet() )
{
IGuiIngredient<ItemStack> ingredient = ingredientEntry.getValue();
if( !ingredient.isInput() )
{
continue;
}
for( final Slot slot : container.inventorySlots )
{
if( slot instanceof SlotCraftingMatrix || slot instanceof SlotFakeCraftingMatrix )
{
if( slot.getSlotIndex() == slotIndex )
{
final NBTTagList tags = new NBTTagList();
final List<ItemStack> list = new LinkedList<ItemStack>();
// prefer pure crystals.
for( ItemStack stack : ingredient.getAllIngredients() )
{
if( Platform.isRecipePrioritized( stack ) )
{
list.add( 0, stack );
}
else
{
list.add( stack );
}
}
for( final ItemStack is : list )
{
final NBTTagCompound tag = new NBTTagCompound();
is.writeToNBT( tag );
tags.appendTag( tag );
}
recipe.setTag( "#" + slot.getSlotIndex(), tags );
break;
}
}
}
slotIndex++;
}
try
{
NetworkHandler.instance.sendToServer( new PacketJEIRecipe( recipe ) );
}
catch( IOException e )
{
AELog.debug( e );
}
return null;
}
}
@@ -0,0 +1,43 @@
package appeng.integration.modules.jei;
import mezz.jei.api.recipe.IRecipeHandler;
import mezz.jei.api.recipe.IRecipeWrapper;
import mezz.jei.api.recipe.VanillaRecipeCategoryUid;
import appeng.recipes.game.ShapedRecipe;
class ShapedRecipeHandler implements IRecipeHandler<ShapedRecipe>
{
@Override
public Class<ShapedRecipe> getRecipeClass()
{
return ShapedRecipe.class;
}
@Override
public String getRecipeCategoryUid()
{
return VanillaRecipeCategoryUid.CRAFTING;
}
@Override
public String getRecipeCategoryUid( ShapedRecipe recipe )
{
return VanillaRecipeCategoryUid.CRAFTING;
}
@Override
public IRecipeWrapper getRecipeWrapper( ShapedRecipe recipe )
{
return new ShapedRecipeWrapper( recipe );
}
@Override
public boolean isRecipeValid( ShapedRecipe recipe )
{
return recipe.isEnabled();
}
}
@@ -0,0 +1,85 @@
package appeng.integration.modules.jei;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.minecraft.item.ItemStack;
import mezz.jei.api.ingredients.IIngredients;
import mezz.jei.api.recipe.BlankRecipeWrapper;
import mezz.jei.api.recipe.wrapper.IShapedCraftingRecipeWrapper;
import scala.actors.threadpool.Arrays;
import appeng.api.exceptions.MissingIngredientError;
import appeng.api.exceptions.RegistrationError;
import appeng.api.recipes.IIngredient;
import appeng.core.AEConfig;
import appeng.recipes.game.ShapedRecipe;
import appeng.util.Platform;
class ShapedRecipeWrapper extends BlankRecipeWrapper implements IShapedCraftingRecipeWrapper
{
private final ShapedRecipe recipe;
public ShapedRecipeWrapper( ShapedRecipe recipe )
{
this.recipe = recipe;
}
@Override
public void getIngredients( IIngredients ingredients )
{
final boolean useSingleItems = AEConfig.instance.disableColoredCableRecipesInJEI();
Object[] items = recipe.getIngredients();
int width = recipe.getWidth();
int height = recipe.getHeight();
List<List<ItemStack>> in = new ArrayList<>( width * height );
for( int x = 0; x < width; x++ )
{
for( int y = 0; y < height; y++ )
{
if( items[( x * height + y )] != null )
{
final IIngredient ing = (IIngredient) items[( x * height + y )];
List<ItemStack> slotList = Collections.emptyList();
try
{
ItemStack[] is = ing.getItemStackSet();
slotList = useSingleItems ? Platform.findPreferred( is ) : Arrays.asList( is );
}
catch( final RegistrationError | MissingIngredientError ignored )
{
}
in.add( slotList );
}
else
{
in.add( Collections.emptyList() );
}
}
}
ingredients.setInputLists( ItemStack.class, in );
ingredients.setOutput( ItemStack.class, recipe.getRecipeOutput() );
}
@Override
public int getWidth()
{
return recipe.getWidth();
}
@Override
public int getHeight()
{
return recipe.getHeight();
}
}
@@ -0,0 +1,43 @@
package appeng.integration.modules.jei;
import mezz.jei.api.recipe.IRecipeHandler;
import mezz.jei.api.recipe.IRecipeWrapper;
import mezz.jei.api.recipe.VanillaRecipeCategoryUid;
import appeng.recipes.game.ShapelessRecipe;
class ShapelessRecipeHandler implements IRecipeHandler<ShapelessRecipe>
{
@Override
public Class<ShapelessRecipe> getRecipeClass()
{
return ShapelessRecipe.class;
}
@Override
public String getRecipeCategoryUid()
{
return VanillaRecipeCategoryUid.CRAFTING;
}
@Override
public String getRecipeCategoryUid( ShapelessRecipe recipe )
{
return VanillaRecipeCategoryUid.CRAFTING;
}
@Override
public IRecipeWrapper getRecipeWrapper( ShapelessRecipe recipe )
{
return new ShapelessRecipeWrapper( recipe );
}
@Override
public boolean isRecipeValid( ShapelessRecipe recipe )
{
return recipe.isEnabled();
}
}
@@ -0,0 +1,56 @@
package appeng.integration.modules.jei;
import java.util.ArrayList;
import java.util.List;
import com.google.common.collect.Lists;
import net.minecraft.item.ItemStack;
import mezz.jei.api.ingredients.IIngredients;
import mezz.jei.api.recipe.BlankRecipeWrapper;
import mezz.jei.api.recipe.wrapper.ICraftingRecipeWrapper;
import appeng.api.exceptions.MissingIngredientError;
import appeng.api.exceptions.RegistrationError;
import appeng.api.recipes.IIngredient;
import appeng.recipes.game.ShapelessRecipe;
class ShapelessRecipeWrapper extends BlankRecipeWrapper implements ICraftingRecipeWrapper
{
private final ShapelessRecipe recipe;
public ShapelessRecipeWrapper( ShapelessRecipe recipe )
{
this.recipe = recipe;
}
@Override
public void getIngredients( IIngredients ingredients )
{
List<Object> recipeInput = this.recipe.getInput();
List<List<ItemStack>> inputs = new ArrayList<>( recipeInput.size() );
for( Object inputObj : recipeInput )
{
if( inputObj instanceof IIngredient )
{
IIngredient ingredient = (IIngredient) inputObj;
try
{
inputs.add( Lists.newArrayList( ingredient.getItemStackSet() ) );
}
catch( RegistrationError | MissingIngredientError registrationError )
{
throw new RuntimeException( "Unable to register recipe with JEI" );
}
}
}
ingredients.setInputLists( ItemStack.class, inputs );
ingredients.setOutput( ItemStack.class, this.recipe.getRecipeOutput() );
}
}