2014-04-29 10:54:20 +10:00
package codechicken.nei.recipe ;
2022-06-24 12:32:13 +01:00
import static codechicken.lib.gui.GuiDraw.changeTexture ;
import static codechicken.lib.gui.GuiDraw.drawTexturedModalRect ;
import static codechicken.lib.gui.GuiDraw.getMousePosition ;
2022-08-19 15:03:42 +03:00
import codechicken.lib.vec.Rectangle4i ;
2021-01-17 12:03:33 -08:00
import codechicken.nei.ItemList ;
2014-04-29 10:54:20 +10:00
import codechicken.nei.NEIClientConfig ;
import codechicken.nei.NEIClientUtils ;
import codechicken.nei.NEIServerUtils ;
import codechicken.nei.PositionedStack ;
import codechicken.nei.api.DefaultOverlayRenderer ;
import codechicken.nei.api.IOverlayHandler ;
import codechicken.nei.api.IRecipeOverlayRenderer ;
import codechicken.nei.api.IStackPositioner ;
import codechicken.nei.guihook.GuiContainerManager ;
import codechicken.nei.guihook.IContainerInputHandler ;
import codechicken.nei.guihook.IContainerTooltipHandler ;
2021-01-17 12:03:33 -08:00
import com.google.common.base.Stopwatch ;
2019-12-30 20:19:16 -08:00
import java.awt.Point ;
import java.awt.Rectangle ;
import java.util.ArrayList ;
import java.util.Collection ;
import java.util.HashMap ;
import java.util.HashSet ;
import java.util.LinkedList ;
2014-04-29 10:54:20 +10:00
import java.util.List ;
2021-01-17 12:03:33 -08:00
import java.util.Objects ;
2019-12-30 20:19:16 -08:00
import java.util.Random ;
2021-01-17 12:03:33 -08:00
import java.util.Set ;
import java.util.concurrent.ExecutionException ;
import java.util.concurrent.locks.ReentrantLock ;
import java.util.stream.Collectors ;
2022-06-24 12:32:13 +01:00
import net.minecraft.client.gui.inventory.GuiContainer ;
import net.minecraft.init.Blocks ;
import net.minecraft.inventory.Container ;
import net.minecraft.item.Item ;
import net.minecraft.item.ItemStack ;
import net.minecraft.nbt.NBTTagCompound ;
import net.minecraft.tileentity.TileEntityFurnace ;
import org.lwjgl.opengl.GL11 ;
2014-04-29 10:54:20 +10:00
/**
* A Template Recipe Handler!
* How about that.
* Because it was sooo hard, and more seriously required lots of copied code to make a handler in the past.
* you can now extend this class to make your custom recipe handlers much easier to create.
* Just look at the 5 handlers included by default to work out how to do stuff if you are still stuck.
*/
2022-06-24 12:32:13 +01:00
public abstract class TemplateRecipeHandler implements ICraftingHandler , IUsageHandler {
2021-01-17 12:03:33 -08:00
protected static ReentrantLock lock = new ReentrantLock ();
public static void findFuelsOnce () {
// Ensure we only find fuels once, even if threaded
lock . lock ();
try {
2022-06-24 12:32:13 +01:00
if ( FurnaceRecipeHandler . afuels == null || FurnaceRecipeHandler . afuels . isEmpty ()) findFuels ( false );
2021-01-17 12:03:33 -08:00
} finally {
lock . unlock ();
}
}
2022-06-24 12:32:13 +01:00
2021-01-30 11:19:30 -08:00
public static void findFuelsOnceParallel () {
// Ensure we only find fuels once, even if threaded
lock . lock ();
try {
2022-06-24 12:32:13 +01:00
if ( FurnaceRecipeHandler . afuels == null || FurnaceRecipeHandler . afuels . isEmpty ()) findFuels ( true );
2021-01-30 11:19:30 -08:00
} finally {
lock . unlock ();
2022-06-24 12:32:13 +01:00
}
2021-01-30 11:19:30 -08:00
}
2021-01-17 12:03:33 -08:00
2021-01-30 11:19:30 -08:00
private static Set < Item > efuels ;
2022-06-24 12:32:13 +01:00
2021-01-17 12:03:33 -08:00
@SuppressWarnings ( "UnstableApiUsage" )
2021-01-30 11:19:30 -08:00
private static void findFuels ( boolean parallel ) {
efuels = new HashSet <> ();
2021-01-17 12:03:33 -08:00
efuels . add ( Item . getItemFromBlock ( Blocks . brown_mushroom ));
efuels . add ( Item . getItemFromBlock ( Blocks . red_mushroom ));
efuels . add ( Item . getItemFromBlock ( Blocks . standing_sign ));
efuels . add ( Item . getItemFromBlock ( Blocks . wall_sign ));
efuels . add ( Item . getItemFromBlock ( Blocks . wooden_door ));
efuels . add ( Item . getItemFromBlock ( Blocks . trapped_chest ));
2022-06-24 12:32:13 +01:00
2021-01-17 12:03:33 -08:00
Stopwatch stopwatch = Stopwatch . createStarted ();
2021-01-30 11:19:30 -08:00
if ( parallel ) {
try {
2022-06-24 12:32:13 +01:00
FurnaceRecipeHandler . afuels = ItemList . forkJoinPool
. submit (() -> ItemList . items . parallelStream ()
. map ( TemplateRecipeHandler :: identifyFuel )
. filter ( Objects :: nonNull )
. collect ( Collectors . toCollection ( ArrayList :: new )))
. get ();
2021-01-30 11:19:30 -08:00
} catch ( InterruptedException | ExecutionException e ) {
2021-03-28 11:04:50 -07:00
FurnaceRecipeHandler . afuels = new ArrayList <> ();
2021-01-30 11:19:30 -08:00
e . printStackTrace ();
}
} else {
2022-06-24 12:32:13 +01:00
FurnaceRecipeHandler . afuels = ItemList . items . stream ()
. map ( TemplateRecipeHandler :: identifyFuel )
. filter ( Objects :: nonNull )
. collect ( Collectors . toCollection ( ArrayList :: new ));
2021-01-17 12:03:33 -08:00
}
2022-06-24 12:32:13 +01:00
NEIClientConfig . logger . info ( "FindFuels took " + stopwatch . stop ());
2021-01-17 12:03:33 -08:00
}
2022-06-24 12:32:13 +01:00
2021-03-28 12:01:40 -07:00
private static FurnaceRecipeHandler . FuelPair identifyFuel ( final ItemStack itemStack ) {
2021-01-30 11:19:30 -08:00
if ( efuels . contains ( itemStack . getItem ())) return null ;
final int burnTime = TileEntityFurnace . getItemBurnTime ( itemStack );
if ( burnTime <= 0 ) return null ;
2021-03-28 12:01:40 -07:00
return new FurnaceRecipeHandler . FuelPair ( itemStack . copy (), burnTime );
2021-01-30 11:19:30 -08:00
}
2021-01-17 12:03:33 -08:00
2014-04-29 10:54:20 +10:00
/**
* This Recipe Handler runs on this internal class
* Fill the recipe array with subclasses of this to make transforming the different types of recipes out there into a nice format for NEI a much easier job.
*/
2022-06-24 12:32:13 +01:00
public abstract class CachedRecipe {
2014-04-29 10:54:20 +10:00
final long offset = System . currentTimeMillis ();
/**
* @return The item produced by this recipe, with position
*/
public abstract PositionedStack getResult ();
/**
* The ingredients required to produce the result
* Use this if you have more than one ingredient
*
* @return A list of positioned ingredient items.
*/
public List < PositionedStack > getIngredients () {
2019-12-30 20:19:16 -08:00
ArrayList < PositionedStack > stacks = new ArrayList <> ();
2014-04-29 10:54:20 +10:00
PositionedStack stack = getIngredient ();
2022-06-24 12:32:13 +01:00
if ( stack != null ) stacks . add ( stack );
2014-04-29 10:54:20 +10:00
return stacks ;
}
/**
* @return The ingredient required to produce the result
*/
public PositionedStack getIngredient () {
return null ;
}
/**
* Return extra items that are not directly involved in the ingredient->result relationship. Eg fuels.
* Use this if you have more than one other stack
*
* @return A list of positioned items.
*/
public List < PositionedStack > getOtherStacks () {
2019-12-30 20:19:16 -08:00
ArrayList < PositionedStack > stacks = new ArrayList <> ();
2020-03-04 16:39:23 -08:00
try {
PositionedStack stack = getOtherStack ();
2022-06-24 12:32:13 +01:00
if ( stack != null ) stacks . add ( stack );
2020-03-04 20:55:41 -08:00
} catch ( ArithmeticException e ) {
NEIClientConfig . logger . error ( "Error in getOtherStacks: " + e );
2020-03-04 16:39:23 -08:00
}
2014-04-29 10:54:20 +10:00
return stacks ;
}
/**
* Simple utility
*
* @return The another positioned stack
*/
public PositionedStack getOtherStack () {
return null ;
}
/**
* This will perform default cycling of ingredients, mulitItem capable
2022-06-29 14:18:48 -04:00
* @param cycle Current cycle step
* @param ingredients List of ItemStacks to cycle
* @return The provided list of ingredients, with their permutations cycled to a different permutation, if one
* is available
2014-04-29 10:54:20 +10:00
*/
public List < PositionedStack > getCycledIngredients ( int cycle , List < PositionedStack > ingredients ) {
2022-08-19 15:03:42 +03:00
if ( ! NEIClientUtils . shiftKey ()) {
for ( int itemIndex = 0 ; itemIndex < ingredients . size (); itemIndex ++ ) {
randomRenderPermutation ( ingredients . get ( itemIndex ), cycle + itemIndex );
}
}
2014-04-29 10:54:20 +10:00
return ingredients ;
}
public void randomRenderPermutation ( PositionedStack stack , long cycle ) {
Random rand = new Random ( cycle + offset );
stack . setPermutationToRender ( Math . abs ( rand . nextInt ()) % stack . items . length );
}
public void setIngredientPermutation ( Collection < PositionedStack > ingredients , ItemStack ingredient ) {
for ( PositionedStack stack : ingredients ) {
for ( int i = 0 ; i < stack . items . length ; i ++ ) {
if ( NEIServerUtils . areStacksSameTypeCrafting ( ingredient , stack . items [ i ] )) {
stack . item = stack . items [ i ] ;
stack . item . setItemDamage ( ingredient . getItemDamage ());
2015-08-19 21:17:56 -07:00
if ( ingredient . hasTagCompound ()) {
2022-06-24 12:32:13 +01:00
stack . item . setTagCompound (
( NBTTagCompound ) ingredient . getTagCompound (). copy ());
2015-08-19 21:17:56 -07:00
}
2022-06-24 12:32:13 +01:00
stack . items = new ItemStack [] { stack . item };
2014-04-29 10:54:20 +10:00
stack . setPermutationToRender ( 0 );
break ;
}
}
}
}
/**
2022-06-29 14:18:48 -04:00
* @param ingredients Collection of ItemStacks
* @param ingredient ItemStack we're looking for
* @return true if any of the permutations of the ingredients contain this ItemStack
2014-04-29 10:54:20 +10:00
*/
public boolean contains ( Collection < PositionedStack > ingredients , ItemStack ingredient ) {
2022-06-24 12:32:13 +01:00
for ( PositionedStack stack : ingredients ) if ( stack . contains ( ingredient )) return true ;
2014-04-29 10:54:20 +10:00
return false ;
}
2022-02-08 16:29:51 +09:00
/**
* NBT-friendly version of {@link #contains(Collection, ItemStack)}
*/
public boolean containsWithNBT ( Collection < PositionedStack > ingredients , ItemStack ingredient ) {
2022-06-24 12:32:13 +01:00
for ( PositionedStack stack : ingredients ) if ( stack . containsWithNBT ( ingredient )) return true ;
2022-02-08 16:29:51 +09:00
return false ;
}
2014-04-29 10:54:20 +10:00
/**
2022-06-29 14:18:48 -04:00
* @param ingredients Collection of ItemStacks
* @param ingredient Item we're looking for
* @return true if any of the permutations of the ingredients contain this Item
2014-04-29 10:54:20 +10:00
*/
2022-06-29 14:18:48 -04:00
public boolean contains ( Collection < PositionedStack > ingredients , Item ingredient ) {
for ( PositionedStack stack : ingredients ) if ( stack . contains ( ingredient )) return true ;
2014-04-29 10:54:20 +10:00
return false ;
}
}
/**
* The Rectangle is an region of the gui relative to the corner of the recipe that will activate the recipe with the corresponding outputId apon being clicked.
* Apply this over fuel icons or arrows that the user may click to see all recipes pertaining to that action.
*/
2022-06-24 12:32:13 +01:00
public static class RecipeTransferRect {
2014-04-29 10:54:20 +10:00
public RecipeTransferRect ( Rectangle rectangle , String outputId , Object ... results ) {
rect = rectangle ;
this . outputId = outputId ;
this . results = results ;
}
public boolean equals ( Object obj ) {
2022-06-24 12:32:13 +01:00
if ( ! ( obj instanceof RecipeTransferRect )) return false ;
2014-04-29 10:54:20 +10:00
return rect . equals ((( RecipeTransferRect ) obj ). rect );
}
public int hashCode () {
return rect . hashCode ();
}
Rectangle rect ;
String outputId ;
Object [] results ;
}
2022-06-24 12:32:13 +01:00
public static class RecipeTransferRectHandler implements IContainerInputHandler , IContainerTooltipHandler {
2022-06-29 14:18:48 -04:00
private static final HashMap < Class <? extends GuiContainer > , HashSet < RecipeTransferRect >> guiMap =
new HashMap <> ();
2014-04-29 10:54:20 +10:00
2022-06-24 12:32:13 +01:00
public static void registerRectsToGuis (
List < Class <? extends GuiContainer >> classes , List < RecipeTransferRect > rects ) {
if ( classes == null ) return ;
2014-04-29 10:54:20 +10:00
for ( Class <? extends GuiContainer > clazz : classes ) {
2019-12-30 20:19:16 -08:00
HashSet < RecipeTransferRect > set = guiMap . computeIfAbsent ( clazz , k -> new HashSet <> ());
2014-04-29 10:54:20 +10:00
set . addAll ( rects );
}
}
public boolean canHandle ( GuiContainer gui ) {
return guiMap . containsKey ( gui . getClass ());
}
@Override
public boolean lastKeyTyped ( GuiContainer gui , char keyChar , int keyCode ) {
2022-06-24 12:32:13 +01:00
if ( ! canHandle ( gui )) return false ;
2014-04-29 10:54:20 +10:00
2022-08-19 15:03:42 +03:00
if ( NEIClientConfig . isKeyHashDown ( "gui.recipe" )) {
return transferRect ( gui , false );
} else if ( NEIClientConfig . isKeyHashDown ( "gui.usage" )) {
return transferRect ( gui , true );
}
2014-04-29 10:54:20 +10:00
return false ;
}
@Override
public boolean mouseClicked ( GuiContainer gui , int mousex , int mousey , int button ) {
2022-06-24 12:32:13 +01:00
if ( ! canHandle ( gui )) return false ;
2014-04-29 10:54:20 +10:00
2022-06-24 12:32:13 +01:00
if ( button == 0 ) return transferRect ( gui , false );
else if ( button == 1 ) return transferRect ( gui , true );
2014-04-29 10:54:20 +10:00
return false ;
}
private boolean transferRect ( GuiContainer gui , boolean usage ) {
int [] offset = RecipeInfo . getGuiOffset ( gui );
return TemplateRecipeHandler . transferRect ( gui , guiMap . get ( gui . getClass ()), offset [ 0 ] , offset [ 1 ] , usage );
}
@Override
2022-06-24 12:32:13 +01:00
public void onKeyTyped ( GuiContainer gui , char keyChar , int keyID ) {}
2014-04-29 10:54:20 +10:00
@Override
2022-06-24 12:32:13 +01:00
public void onMouseClicked ( GuiContainer gui , int mousex , int mousey , int button ) {}
2014-04-29 10:54:20 +10:00
@Override
2022-06-24 12:32:13 +01:00
public void onMouseUp ( GuiContainer gui , int mousex , int mousey , int button ) {}
2014-04-29 10:54:20 +10:00
@Override
public boolean keyTyped ( GuiContainer gui , char keyChar , int keyID ) {
return false ;
}
@Override
public boolean mouseScrolled ( GuiContainer gui , int mousex , int mousey , int scrolled ) {
return false ;
}
@Override
2022-06-24 12:32:13 +01:00
public void onMouseScrolled ( GuiContainer gui , int mousex , int mousey , int scrolled ) {}
2014-04-29 10:54:20 +10:00
@Override
public List < String > handleTooltip ( GuiContainer gui , int mousex , int mousey , List < String > currenttip ) {
2022-06-24 12:32:13 +01:00
if ( ! canHandle ( gui )) return currenttip ;
2014-04-29 10:54:20 +10:00
if ( GuiContainerManager . shouldShowTooltip ( gui ) && currenttip . size () == 0 ) {
int [] offset = RecipeInfo . getGuiOffset ( gui );
2022-06-24 12:32:13 +01:00
currenttip = TemplateRecipeHandler . transferRectTooltip (
gui , guiMap . get ( gui . getClass ()), offset [ 0 ] , offset [ 1 ] , currenttip );
2014-04-29 10:54:20 +10:00
}
return currenttip ;
}
@Override
public List < String > handleItemDisplayName ( GuiContainer gui , ItemStack itemstack , List < String > currenttip ) {
return currenttip ;
}
@Override
2022-06-24 12:32:13 +01:00
public List < String > handleItemTooltip (
GuiContainer gui , ItemStack itemstack , int mousex , int mousey , List < String > currenttip ) {
2014-04-29 10:54:20 +10:00
return currenttip ;
}
@Override
2022-06-24 12:32:13 +01:00
public void onMouseDragged ( GuiContainer gui , int mousex , int mousey , int button , long heldTime ) {}
2014-04-29 10:54:20 +10:00
}
static {
GuiContainerManager . addInputHandler ( new RecipeTransferRectHandler ());
GuiContainerManager . addTooltipHandler ( new RecipeTransferRectHandler ());
}
/**
* Internal tick counter, initialised to random value and incremented every tick.
* Used for cycling similar ingredients and progress bars.
*/
public int cycleticks = Math . abs (( int ) System . currentTimeMillis ());
/**
* The list of matching recipes
*/
2019-12-30 20:19:16 -08:00
public ArrayList < CachedRecipe > arecipes = new ArrayList <> ();
2014-04-29 10:54:20 +10:00
/**
2021-01-17 12:03:33 -08:00
* A list of transferRects that when clicked or R is pressed will open a new recipe.
2014-04-29 10:54:20 +10:00
*/
2019-12-30 20:19:16 -08:00
public LinkedList < RecipeTransferRect > transferRects = new LinkedList <> ();
2014-04-29 10:54:20 +10:00
public TemplateRecipeHandler () {
loadTransferRects ();
RecipeTransferRectHandler . registerRectsToGuis ( getRecipeTransferRectGuis (), transferRects );
}
/**
* Add all RecipeTransferRects to the transferRects list during this call.
* Afterward they may be added to the input handler for the corresponding guis from getRecipeTransferRectGuis
*/
2022-06-24 12:32:13 +01:00
public void loadTransferRects () {}
2014-04-29 10:54:20 +10:00
/**
* In this function you need to fill up the empty recipe array with recipes.
* The default passes it to a cleaner handler if outputId is an item
*
* @param outputId A String identifier representing the type of output produced. Eg. {"item", "fuel"}
* @param results Objects representing the results that matching recipes must produce.
*/
public void loadCraftingRecipes ( String outputId , Object ... results ) {
2022-06-24 12:32:13 +01:00
if ( outputId . equals ( "item" )) loadCraftingRecipes (( ItemStack ) results [ 0 ] );
2014-04-29 10:54:20 +10:00
}
/**
* Simplified wrapper, implement this and fill the empty recipe array with recipes
*
* @param result The result the recipes must output.
*/
public void loadCraftingRecipes ( ItemStack result ) {}
/**
* In this function you need to fill up the empty recipe array with recipes
* The default passes it to a cleaner handler if inputId is an item
*
* @param inputId A String identifier representing the type of ingredients used. Eg. {"item", "fuel"}
* @param ingredients Objects representing the ingredients that matching recipes must contain.
*/
public void loadUsageRecipes ( String inputId , Object ... ingredients ) {
2022-06-24 12:32:13 +01:00
if ( inputId . equals ( "item" )) loadUsageRecipes (( ItemStack ) ingredients [ 0 ] );
2014-04-29 10:54:20 +10:00
}
/**
* Simplified wrapper, implement this and fill the empty recipe array with recipes
*
* @param ingredient The ingredient the recipes must contain.
*/
public void loadUsageRecipes ( ItemStack ingredient ) {}
/**
* @return The filepath to the texture to use when drawing this recipe
*/
public abstract String getGuiTexture ();
/**
* Simply works with the {@link DefaultOverlayRenderer}
* If the current container has been registered with this identifier, the question mark appears and an overlay guide can be drawn.
*
* @return The overlay identifier of this recipe type.
*/
2022-01-23 07:37:54 +09:00
@Override
2014-04-29 10:54:20 +10:00
public String getOverlayIdentifier () {
return null ;
}
/**
* Extension point for drawing progress bars and other overlays
*
* @param recipe The recipeIndex being drawn
*/
public void drawExtras ( int recipe ) {}
/**
* Draws a texture rectangle that changes size with time.
* Commonly used for progress bars.
*
* @param x X position on screen
* @param y Y position on screen
* @param tx Texture X position
* @param ty Texture Y position
* @param w Texture width
* @param h Texture height
* @param ticks The amount of ticks for the bar to complete
* @param direction 0 right, 1 down, 2 left, 3 up. If bit 3 is set the bar will shrink rather extend
*/
public void drawProgressBar ( int x , int y , int tx , int ty , int w , int h , int ticks , int direction ) {
drawProgressBar ( x , y , tx , ty , w , h , cycleticks % ticks / ( float ) ticks , direction );
}
/**
* Draws a texture rectangle that changes size with time.
* Commonly used for progress bars.
* If for some reason you don't like the default counter use this and specify the progress percentage.
*
* @param x X position on screen
* @param y Y position on screen
* @param tx Texture X position
* @param ty Texture Y position
* @param w Texture width
* @param h Texture height
* @param completion the percentage of progress bar completion, 0-1
* @param direction 0 right, 1 down, 2 left, 3 up. If bit 3 is set the bar will shrink rather extend
*/
public void drawProgressBar ( int x , int y , int tx , int ty , int w , int h , float completion , int direction ) {
if ( direction > 3 ) {
completion = 1 - completion ;
direction %= 4 ;
}
int var = ( int ) ( completion * ( direction % 2 == 0 ? w : h ));
switch ( direction ) {
2022-06-24 12:32:13 +01:00
case 0 : // right
2014-04-29 10:54:20 +10:00
drawTexturedModalRect ( x , y , tx , ty , var , h );
break ;
2022-06-24 12:32:13 +01:00
case 1 : // down
2014-04-29 10:54:20 +10:00
drawTexturedModalRect ( x , y , tx , ty , w , var );
break ;
2022-06-24 12:32:13 +01:00
case 2 : // left
2014-04-29 10:54:20 +10:00
drawTexturedModalRect ( x + w - var , y , tx + w - var , ty , var , h );
break ;
2022-06-24 12:32:13 +01:00
case 3 : // up
2014-04-29 10:54:20 +10:00
drawTexturedModalRect ( x , y + h - var , tx , ty + h - var , w , var );
break ;
}
}
/**
* @return The gui classes to which the transfer rects added in the constructor are to be located over. null if none.
*/
public List < Class <? extends GuiContainer >> getRecipeTransferRectGuis () {
Class <? extends GuiContainer > clazz = getGuiClass ();
if ( clazz != null ) {
2019-12-30 20:19:16 -08:00
LinkedList < Class <? extends GuiContainer >> list = new LinkedList <> ();
2014-04-29 10:54:20 +10:00
list . add ( clazz );
return list ;
}
return null ;
}
/**
* @return The class of the GuiContainer that this recipe would be crafted in.
*/
public Class <? extends GuiContainer > getGuiClass () {
return null ;
}
public TemplateRecipeHandler newInstance () {
try {
2022-06-24 12:32:13 +01:00
// Use the non parallel version since we might already be using the forkJoinPool and might have no threads
// available
2021-01-30 11:19:30 -08:00
// This will ideally have been pre-cached elsewhere and will be a NOOP
2022-06-24 12:32:13 +01:00
findFuelsOnce ();
2014-04-29 10:54:20 +10:00
return getClass (). newInstance ();
} catch ( Exception e ) {
throw new RuntimeException ( e );
}
}
public ICraftingHandler getRecipeHandler ( String outputId , Object ... results ) {
TemplateRecipeHandler handler = newInstance ();
handler . loadCraftingRecipes ( outputId , results );
return handler ;
}
public IUsageHandler getUsageHandler ( String inputId , Object ... ingredients ) {
TemplateRecipeHandler handler = newInstance ();
handler . loadUsageRecipes ( inputId , ingredients );
return handler ;
}
2022-01-22 13:16:28 +09:00
/**
* First look up {@link RecipeCatalysts} whether target ingredient is registered for it.
* If so, load all recipes for this handler.
* Fallback to {@link TemplateRecipeHandler#getUsageHandler}.
*/
public IUsageHandler getUsageAndCatalystHandler ( String inputId , Object ... ingredients ) {
TemplateRecipeHandler handler = newInstance ();
if ( inputId . equals ( "item" )) {
ItemStack candidate = ( ItemStack ) ingredients [ 0 ] ;
2022-01-23 07:37:54 +09:00
if ( RecipeCatalysts . containsCatalyst ( handler , candidate )) {
2022-01-22 13:16:28 +09:00
for ( RecipeTransferRect rect : transferRects ) {
if ( specifyTransferRect () == null || Objects . equals ( rect . outputId , specifyTransferRect ())) {
handler . loadCraftingRecipes ( rect . outputId , rect . results );
return handler ;
}
}
2022-06-24 12:32:13 +01:00
NEIClientConfig . logger . info (
"failed to load catalyst handler, implement `loadTransferRects` for your handler "
+ handler . getClass (). getName ());
2022-01-22 13:16:28 +09:00
}
}
return this . getUsageHandler ( inputId , ingredients );
}
/**
* Override this if you have multiple {@link RecipeTransferRect}s.
* Used for {@link TemplateRecipeHandler#getUsageAndCatalystHandler}.
*/
public String specifyTransferRect () {
return null ;
}
2014-04-29 10:54:20 +10:00
public int numRecipes () {
return arecipes . size ();
}
public void drawBackground ( int recipe ) {
GL11 . glColor4f ( 1 , 1 , 1 , 1 );
changeTexture ( getGuiTexture ());
drawTexturedModalRect ( 0 , 0 , 5 , 11 , 166 , 65 );
}
public void drawForeground ( int recipe ) {
GL11 . glColor4f ( 1 , 1 , 1 , 1 );
GL11 . glDisable ( GL11 . GL_LIGHTING );
changeTexture ( getGuiTexture ());
drawExtras ( recipe );
}
public List < PositionedStack > getIngredientStacks ( int recipe ) {
return arecipes . get ( recipe ). getIngredients ();
}
public PositionedStack getResultStack ( int recipe ) {
return arecipes . get ( recipe ). getResult ();
}
public List < PositionedStack > getOtherStacks ( int recipe ) {
return arecipes . get ( recipe ). getOtherStacks ();
}
public void onUpdate () {
2022-06-24 12:32:13 +01:00
if ( ! NEIClientUtils . shiftKey ()) cycleticks ++ ;
2014-04-29 10:54:20 +10:00
}
public boolean hasOverlay ( GuiContainer gui , Container container , int recipe ) {
2022-06-24 12:32:13 +01:00
return RecipeInfo . hasDefaultOverlay ( gui , getOverlayIdentifier ())
|| RecipeInfo . hasOverlayHandler ( gui , getOverlayIdentifier ());
2014-04-29 10:54:20 +10:00
}
public IRecipeOverlayRenderer getOverlayRenderer ( GuiContainer gui , int recipe ) {
IStackPositioner positioner = RecipeInfo . getStackPositioner ( gui , getOverlayIdentifier ());
2022-06-24 12:32:13 +01:00
if ( positioner == null ) return null ;
2014-04-29 10:54:20 +10:00
return new DefaultOverlayRenderer ( getIngredientStacks ( recipe ), positioner );
}
@Override
public IOverlayHandler getOverlayHandler ( GuiContainer gui , int recipe ) {
return RecipeInfo . getOverlayHandler ( gui , getOverlayIdentifier ());
}
@Override
public int recipiesPerPage () {
return 2 ;
}
@Override
2022-06-29 14:18:48 -04:00
public List < String > handleTooltip ( GuiRecipe <?> gui , List < String > currenttip , int recipe ) {
2014-04-29 10:54:20 +10:00
if ( GuiContainerManager . shouldShowTooltip ( gui ) && currenttip . size () == 0 ) {
Point offset = gui . getRecipePosition ( recipe );
currenttip = transferRectTooltip ( gui , transferRects , offset . x , offset . y , currenttip );
}
return currenttip ;
}
@Override
2022-06-29 14:18:48 -04:00
public List < String > handleItemTooltip ( GuiRecipe <?> gui , ItemStack stack , List < String > currenttip , int recipe ) {
2014-04-29 10:54:20 +10:00
return currenttip ;
}
@Override
2022-06-29 14:18:48 -04:00
public boolean keyTyped ( GuiRecipe <?> gui , char keyChar , int keyCode , int recipe ) {
2022-08-19 15:03:42 +03:00
if ( NEIClientConfig . isKeyHashDown ( "gui.recipe" )) {
return transferRect ( gui , recipe , false );
} else if ( NEIClientConfig . isKeyHashDown ( "gui.usage" )) {
return transferRect ( gui , recipe , true );
}
2014-04-29 10:54:20 +10:00
return false ;
}
@Override
2022-06-29 14:18:48 -04:00
public boolean mouseClicked ( GuiRecipe <?> gui , int button , int recipe ) {
2022-06-24 12:32:13 +01:00
if ( button == 0 ) return transferRect ( gui , recipe , false );
else if ( button == 1 ) return transferRect ( gui , recipe , true );
2014-04-29 10:54:20 +10:00
return false ;
}
2021-09-30 22:17:14 -06:00
@Override
2022-06-29 14:18:48 -04:00
public boolean mouseScrolled ( GuiRecipe <?> gui , int scroll , int recipe ) {
2022-08-19 15:03:42 +03:00
if ( ! NEIClientUtils . shiftKey ()) return false ;
final Point offset = gui . getRecipePosition ( recipe );
final Point pos = getMousePosition ();
final Point relMouse = new Point ( pos . x - gui . guiLeft - offset . x , pos . y - gui . guiTop - offset . y );
for ( PositionedStack pStack : getIngredientStacks ( recipe )) {
if (( new Rectangle4i ( pStack . relx , pStack . rely , 18 , 18 )). contains ( relMouse . x , relMouse . y )) {
int index = pStack . items . length + scroll ;
for ( int i = 0 ; i < pStack . items . length ; i ++ ) {
if ( NEIServerUtils . areStacksSameTypeCraftingWithNBT ( pStack . items [ i ] , pStack . item )) {
index = index + i ;
break ;
}
}
pStack . setPermutationToRender ( index % pStack . items . length );
return true ;
}
}
2021-09-30 22:17:14 -06:00
return false ;
}
2022-06-29 14:18:48 -04:00
private boolean transferRect ( GuiRecipe <?> gui , int recipe , boolean usage ) {
2014-04-29 10:54:20 +10:00
Point offset = gui . getRecipePosition ( recipe );
return transferRect ( gui , transferRects , offset . x , offset . y , usage );
}
2022-06-24 12:32:13 +01:00
private static boolean transferRect (
GuiContainer gui , Collection < RecipeTransferRect > transferRects , int offsetx , int offsety , boolean usage ) {
2014-04-29 10:54:20 +10:00
Point pos = getMousePosition ();
Point relMouse = new Point ( pos . x - gui . guiLeft - offsetx , pos . y - gui . guiTop - offsety );
for ( RecipeTransferRect rect : transferRects ) {
2022-06-24 12:32:13 +01:00
if ( rect . rect . contains ( relMouse )
&& ( usage
? GuiUsageRecipe . openRecipeGui ( rect . outputId , rect . results )
: GuiCraftingRecipe . openRecipeGui ( rect . outputId , rect . results ))) return true ;
2014-04-29 10:54:20 +10:00
}
return false ;
}
2022-06-24 12:32:13 +01:00
private static List < String > transferRectTooltip (
GuiContainer gui ,
Collection < RecipeTransferRect > transferRects ,
int offsetx ,
int offsety ,
List < String > currenttip ) {
2014-04-29 10:54:20 +10:00
Point pos = getMousePosition ();
Point relMouse = new Point ( pos . x - gui . guiLeft - offsetx , pos . y - gui . guiTop - offsety );
for ( RecipeTransferRect rect : transferRects ) {
if ( rect . rect . contains ( relMouse )) {
2015-04-26 04:39:53 +10:00
currenttip . add ( NEIClientUtils . translate ( "recipe.tooltip" ));
2014-04-29 10:54:20 +10:00
break ;
}
}
return currenttip ;
}
}