mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-11-16 23:11:40 +01:00
Plenty to process
- The Mechanical Mixer now supports custom mixing recipes - The Mechanical Press now interacts with the basin to apply compressing recipes - Added JEI integration for Mixing, Compressing, Sawing and Block Cutting recipes
This commit is contained in:
parent
9bd07d4ed0
commit
43980d550d
22 changed files with 1167 additions and 243 deletions
|
@ -0,0 +1,86 @@
|
|||
package com.simibubi.create.compat.jei;
|
||||
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.foundation.gui.ScreenElementRenderer;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
|
||||
public class AnimatedMixer extends AnimatedKinetics {
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return 50;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return 150;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int xOffset, int yOffset) {
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.enableDepthTest();
|
||||
GlStateManager.translatef(xOffset, yOffset, 0);
|
||||
GlStateManager.rotatef(-15.5f, 1, 0, 0);
|
||||
GlStateManager.rotatef(22.5f, 0, 1, 0);
|
||||
GlStateManager.translatef(-45, -5, 0);
|
||||
GlStateManager.scaled(.45f, .45f, .45f);
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
ScreenElementRenderer.renderBlock(this::cogwheel);
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
ScreenElementRenderer.renderBlock(this::body);
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
ScreenElementRenderer.renderBlock(this::pole);
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
ScreenElementRenderer.renderBlock(this::head);
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
ScreenElementRenderer.renderBlock(this::basin);
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
private BlockState cogwheel() {
|
||||
float t = 25;
|
||||
GlStateManager.translatef(t, -t, -t);
|
||||
GlStateManager.rotated(getCurrentAngle() * 2, 0, 1, 0);
|
||||
GlStateManager.translatef(-t, t, t);
|
||||
return AllBlocks.SHAFTLESS_COGWHEEL.get().getDefaultState().with(BlockStateProperties.AXIS, Axis.Y);
|
||||
}
|
||||
|
||||
private BlockState body() {
|
||||
return AllBlocks.MECHANICAL_MIXER.get().getDefaultState();
|
||||
}
|
||||
|
||||
private BlockState pole() {
|
||||
GlStateManager.translatef(0, 51, 0);
|
||||
return AllBlocks.MECHANICAL_MIXER_POLE.get().getDefaultState();
|
||||
}
|
||||
|
||||
private BlockState head() {
|
||||
float t = 25;
|
||||
GlStateManager.translatef(0, 51, 0);
|
||||
GlStateManager.translatef(t, -t, -t);
|
||||
GlStateManager.rotated(getCurrentAngle() * 4, 0, 1, 0);
|
||||
GlStateManager.translatef(-t, t, t);
|
||||
return AllBlocks.MECHANICAL_MIXER_HEAD.get().getDefaultState();
|
||||
}
|
||||
|
||||
private BlockState basin() {
|
||||
GlStateManager.translatef(0, 85, 0);
|
||||
return AllBlocks.BASIN.get().getDefaultState();
|
||||
}
|
||||
}
|
|
@ -14,6 +14,12 @@ import net.minecraft.util.Direction.Axis;
|
|||
|
||||
public class AnimatedPress extends AnimatedKinetics {
|
||||
|
||||
private boolean basin;
|
||||
|
||||
public AnimatedPress(boolean basin) {
|
||||
this.basin = basin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return 50;
|
||||
|
@ -45,6 +51,12 @@ public class AnimatedPress extends AnimatedKinetics {
|
|||
GlStateManager.pushMatrix();
|
||||
ScreenElementRenderer.renderBlock(this::head);
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
if (basin) {
|
||||
GlStateManager.pushMatrix();
|
||||
ScreenElementRenderer.renderBlock(this::basin);
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
@ -79,5 +91,10 @@ public class AnimatedPress extends AnimatedKinetics {
|
|||
return AllBlocks.MECHANICAL_PRESS_HEAD.get().getDefaultState().with(BlockStateProperties.HORIZONTAL_FACING,
|
||||
Direction.EAST);
|
||||
}
|
||||
|
||||
private BlockState basin() {
|
||||
GlStateManager.translatef(0, 85, 0);
|
||||
return AllBlocks.BASIN.get().getDefaultState();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
package com.simibubi.create.compat.jei;
|
||||
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.foundation.gui.ScreenElementRenderer;
|
||||
import com.simibubi.create.modules.contraptions.components.saw.SawBlock;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
|
||||
public class AnimatedSaw extends AnimatedKinetics {
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return 50;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return 50;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int xOffset, int yOffset) {
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.enableDepthTest();
|
||||
GlStateManager.translatef(xOffset, yOffset, 0);
|
||||
GlStateManager.rotatef(-15.5f, 1, 0, 0);
|
||||
GlStateManager.rotatef(22.5f, 0, 1, 0);
|
||||
GlStateManager.translatef(-45, -5, 0);
|
||||
GlStateManager.scaled(.6f, .6f, .6f);
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
ScreenElementRenderer.renderBlock(this::shaft);
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
ScreenElementRenderer.renderBlock(this::block);
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
private BlockState shaft() {
|
||||
float t = 25;
|
||||
GlStateManager.translatef(t, -t, t);
|
||||
GlStateManager.rotated(-getCurrentAngle() * 2, 0, 0, 1);
|
||||
GlStateManager.translatef(-t, t, -t);
|
||||
return AllBlocks.SHAFT.get().getDefaultState().with(BlockStateProperties.AXIS, Axis.X);
|
||||
}
|
||||
|
||||
private BlockState block() {
|
||||
return AllBlocks.SAW.get().getDefaultState().with(BlockStateProperties.FACING, Direction.UP)
|
||||
.with(SawBlock.RUNNING, true).with(SawBlock.AXIS_ALONG_FIRST_COORDINATE, true);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
package com.simibubi.create.compat.jei;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.ScreenResources;
|
||||
import com.simibubi.create.compat.jei.BlockCuttingCategory.CondensedBlockCuttingRecipe;
|
||||
import com.simibubi.create.foundation.item.ItemHelper;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
|
||||
import mezz.jei.api.constants.VanillaTypes;
|
||||
import mezz.jei.api.gui.IRecipeLayout;
|
||||
import mezz.jei.api.gui.drawable.IDrawable;
|
||||
import mezz.jei.api.gui.ingredient.IGuiItemStackGroup;
|
||||
import mezz.jei.api.ingredients.IIngredients;
|
||||
import mezz.jei.api.recipe.category.IRecipeCategory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.item.crafting.StonecuttingRecipe;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public class BlockCuttingCategory implements IRecipeCategory<CondensedBlockCuttingRecipe> {
|
||||
|
||||
private AnimatedSaw saw;
|
||||
private static ResourceLocation ID = new ResourceLocation(Create.ID, "block_cutting");
|
||||
private IDrawable icon;
|
||||
private IDrawable background = new EmptyBackground(177, 70);
|
||||
|
||||
public BlockCuttingCategory() {
|
||||
icon = new DoubleItemIcon(() -> new ItemStack(AllBlocks.SAW.get()),
|
||||
() -> new ItemStack(Items.STONE_BRICK_STAIRS));
|
||||
saw = new AnimatedSaw();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDrawable getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getUid() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends CondensedBlockCuttingRecipe> getRecipeClass() {
|
||||
return CondensedBlockCuttingRecipe.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return Lang.translate("recipe.block_cutting");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDrawable getBackground() {
|
||||
return background;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIngredients(CondensedBlockCuttingRecipe recipe, IIngredients ingredients) {
|
||||
ingredients.setInputIngredients(recipe.getIngredients());
|
||||
ingredients.setOutputs(VanillaTypes.ITEM, recipe.getOutputs());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRecipe(IRecipeLayout recipeLayout, CondensedBlockCuttingRecipe recipe, IIngredients ingredients) {
|
||||
IGuiItemStackGroup itemStacks = recipeLayout.getItemStacks();
|
||||
itemStacks.init(0, true, 4, 4);
|
||||
itemStacks.set(0, Arrays.asList(recipe.getIngredients().get(0).getMatchingStacks()));
|
||||
|
||||
List<ItemStack> results = recipe.getOutputs();
|
||||
for (int outputIndex = 0; outputIndex < results.size(); outputIndex++) {
|
||||
int xOffset = (outputIndex % 5) * 19;
|
||||
int yOffset = (outputIndex / 5) * -19;
|
||||
|
||||
itemStacks.init(outputIndex + 1, false, 77 + xOffset, 47 + yOffset);
|
||||
itemStacks.set(outputIndex + 1, results.get(outputIndex).getStack());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(CondensedBlockCuttingRecipe recipe, double mouseX, double mouseY) {
|
||||
ScreenResources.JEI_SLOT.draw(4, 4);
|
||||
int size = recipe.getOutputs().size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
int xOffset = (i % 5) * 19;
|
||||
int yOffset = (i / 5) * -19;
|
||||
ScreenResources.JEI_SLOT.draw(77 + xOffset, 47 + yOffset);
|
||||
}
|
||||
ScreenResources.JEI_DOWN_ARROW.draw(31, 6);
|
||||
ScreenResources.JEI_SHADOW.draw(19, 55);
|
||||
saw.draw(33, 35);
|
||||
}
|
||||
|
||||
public static class CondensedBlockCuttingRecipe extends StonecuttingRecipe {
|
||||
|
||||
List<ItemStack> outputs = new ArrayList<>();
|
||||
|
||||
public CondensedBlockCuttingRecipe(Ingredient ingredient) {
|
||||
super(new ResourceLocation(""), "", ingredient, ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
public void addOutput(ItemStack stack) {
|
||||
outputs.add(stack);
|
||||
}
|
||||
|
||||
public List<ItemStack> getOutputs() {
|
||||
return outputs;
|
||||
}
|
||||
|
||||
public static List<CondensedBlockCuttingRecipe> condenseRecipes(List<IRecipe<?>> stoneCuttingRecipes) {
|
||||
List<CondensedBlockCuttingRecipe> condensed = new ArrayList<>();
|
||||
Recipes: for (IRecipe<?> recipe : stoneCuttingRecipes) {
|
||||
Ingredient i1 = recipe.getIngredients().get(0);
|
||||
for (CondensedBlockCuttingRecipe condensedRecipe : condensed) {
|
||||
if (ItemHelper.matchIngredients(i1, condensedRecipe.getIngredients().get(0))) {
|
||||
condensedRecipe.addOutput(recipe.getRecipeOutput());
|
||||
continue Recipes;
|
||||
}
|
||||
}
|
||||
CondensedBlockCuttingRecipe cr = new CondensedBlockCuttingRecipe(i1);
|
||||
cr.addOutput(recipe.getRecipeOutput());
|
||||
condensed.add(cr);
|
||||
}
|
||||
return condensed;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -3,24 +3,32 @@ package com.simibubi.create.compat.jei;
|
|||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.AllRecipes;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.compat.jei.BlockCuttingCategory.CondensedBlockCuttingRecipe;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
import com.simibubi.create.modules.contraptions.components.press.MechanicalPressTileEntity;
|
||||
import com.simibubi.create.modules.contraptions.processing.StochasticOutput;
|
||||
import com.simibubi.create.modules.logistics.block.inventories.FlexcrateScreen;
|
||||
import com.simibubi.create.modules.schematics.block.SchematicannonScreen;
|
||||
|
||||
import mezz.jei.api.IModPlugin;
|
||||
import mezz.jei.api.JeiPlugin;
|
||||
import mezz.jei.api.gui.ingredient.IGuiItemStackGroup;
|
||||
import mezz.jei.api.registration.IGuiHandlerRegistration;
|
||||
import mezz.jei.api.registration.IRecipeCatalystRegistration;
|
||||
import mezz.jei.api.registration.IRecipeCategoryRegistration;
|
||||
import mezz.jei.api.registration.IRecipeRegistration;
|
||||
import mezz.jei.api.registration.ISubtypeRegistration;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.ICraftingRecipe;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.item.crafting.IRecipeSerializer;
|
||||
import net.minecraft.item.crafting.IRecipeType;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.text.StringTextComponent;
|
||||
|
@ -36,6 +44,10 @@ public class CreateJEI implements IModPlugin {
|
|||
private PressingCategory pressingCategory;
|
||||
private BlastingViaFanCategory blastingCategory;
|
||||
private BlockzapperUpgradeCategory blockzapperCategory;
|
||||
private MixingCategory mixingCategory;
|
||||
private SawingCategory sawingCategory;
|
||||
private BlockCuttingCategory blockCuttingCategory;
|
||||
private PackingCategory packingCategory;
|
||||
|
||||
@Override
|
||||
public ResourceLocation getPluginUid() {
|
||||
|
@ -49,6 +61,10 @@ public class CreateJEI implements IModPlugin {
|
|||
smokingCategory = new SmokingViaFanCategory();
|
||||
blastingCategory = new BlastingViaFanCategory();
|
||||
blockzapperCategory = new BlockzapperUpgradeCategory();
|
||||
mixingCategory = new MixingCategory();
|
||||
sawingCategory = new SawingCategory();
|
||||
blockCuttingCategory = new BlockCuttingCategory();
|
||||
packingCategory = new PackingCategory();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -59,7 +75,8 @@ public class CreateJEI implements IModPlugin {
|
|||
@Override
|
||||
public void registerCategories(IRecipeCategoryRegistration registration) {
|
||||
registration.addRecipeCategories(crushingCategory, splashingCategory, pressingCategory, smokingCategory,
|
||||
blastingCategory, blockzapperCategory);
|
||||
blastingCategory, blockzapperCategory, mixingCategory, sawingCategory, blockCuttingCategory,
|
||||
packingCategory);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -72,6 +89,19 @@ public class CreateJEI implements IModPlugin {
|
|||
registration.addRecipes(findRecipesByType(IRecipeType.SMOKING), smokingCategory.getUid());
|
||||
registration.addRecipes(findRecipesByTypeExcluding(IRecipeType.SMELTING, IRecipeType.SMOKING),
|
||||
blastingCategory.getUid());
|
||||
registration.addRecipes(findRecipes(AllRecipes.MIXING), mixingCategory.getUid());
|
||||
registration
|
||||
.addRecipes(
|
||||
findRecipes(r -> r.getSerializer() == IRecipeSerializer.CRAFTING_SHAPELESS
|
||||
&& !MechanicalPressTileEntity.canCompress(r.getIngredients())),
|
||||
mixingCategory.getUid());
|
||||
registration.addRecipes(findRecipes(AllRecipes.CUTTING), sawingCategory.getUid());
|
||||
registration.addRecipes(
|
||||
CondensedBlockCuttingRecipe.condenseRecipes(findRecipesByType(IRecipeType.STONECUTTING)),
|
||||
blockCuttingCategory.getUid());
|
||||
registration.addRecipes(findRecipes(
|
||||
r -> (r instanceof ICraftingRecipe) && MechanicalPressTileEntity.canCompress(r.getIngredients())),
|
||||
packingCategory.getUid());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -91,6 +121,13 @@ public class CreateJEI implements IModPlugin {
|
|||
registration.addRecipeCatalyst(blastingFan, blastingCategory.getUid());
|
||||
registration.addRecipeCatalyst(new ItemStack(AllBlocks.MECHANICAL_PRESS.get()), pressingCategory.getUid());
|
||||
registration.addRecipeCatalyst(new ItemStack(AllItems.PLACEMENT_HANDGUN.get()), blockzapperCategory.getUid());
|
||||
registration.addRecipeCatalyst(new ItemStack(AllBlocks.MECHANICAL_MIXER.get()), mixingCategory.getUid());
|
||||
registration.addRecipeCatalyst(new ItemStack(AllBlocks.BASIN.get()), mixingCategory.getUid());
|
||||
registration.addRecipeCatalyst(new ItemStack(AllBlocks.SAW.get()), sawingCategory.getUid());
|
||||
registration.addRecipeCatalyst(new ItemStack(AllBlocks.SAW.get()), blockCuttingCategory.getUid());
|
||||
registration.addRecipeCatalyst(new ItemStack(Blocks.STONECUTTER), blockCuttingCategory.getUid());
|
||||
registration.addRecipeCatalyst(new ItemStack(AllBlocks.MECHANICAL_PRESS.get()), packingCategory.getUid());
|
||||
registration.addRecipeCatalyst(new ItemStack(AllBlocks.BASIN.get()), packingCategory.getUid());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -103,6 +140,11 @@ public class CreateJEI implements IModPlugin {
|
|||
return findRecipesByType(recipe.type);
|
||||
}
|
||||
|
||||
private static List<IRecipe<?>> findRecipes(Predicate<IRecipe<?>> pred) {
|
||||
return Minecraft.getInstance().world.getRecipeManager().getRecipes().stream().filter(pred)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static List<IRecipe<?>> findRecipesByType(IRecipeType<?> type) {
|
||||
return Minecraft.getInstance().world.getRecipeManager().getRecipes().stream().filter(r -> r.getType() == type)
|
||||
.collect(Collectors.toList());
|
||||
|
@ -129,4 +171,15 @@ public class CreateJEI implements IModPlugin {
|
|||
return byType;
|
||||
}
|
||||
|
||||
static void addStochasticTooltip(IGuiItemStackGroup itemStacks, List<StochasticOutput> results) {
|
||||
itemStacks.addTooltipCallback((slotIndex, input, ingredient, tooltip) -> {
|
||||
if (input)
|
||||
return;
|
||||
StochasticOutput output = results.get(slotIndex - 1);
|
||||
if (output.getChance() != 1)
|
||||
tooltip.add(1, TextFormatting.GOLD
|
||||
+ Lang.translate("recipe.processing.chance", (int) (output.getChance() * 100)));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import mezz.jei.api.ingredients.IIngredients;
|
|||
import mezz.jei.api.recipe.category.IRecipeCategory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.text.TextFormatting;
|
||||
|
||||
public class CrushingCategory implements IRecipeCategory<CrushingRecipe> {
|
||||
|
||||
|
@ -78,14 +77,7 @@ public class CrushingCategory implements IRecipeCategory<CrushingRecipe> {
|
|||
itemStacks.set(outputIndex + 1, results.get(outputIndex).getStack());
|
||||
}
|
||||
|
||||
itemStacks.addTooltipCallback((slotIndex, input, ingredient, tooltip) -> {
|
||||
if (input)
|
||||
return;
|
||||
StochasticOutput output = results.get(slotIndex - 1);
|
||||
if (output.getChance() != 1)
|
||||
tooltip.add(1, TextFormatting.GOLD
|
||||
+ Lang.translate("recipe.processing.chance", (int) (output.getChance() * 100)));
|
||||
});
|
||||
CreateJEI.addStochasticTooltip(itemStacks, results);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
113
src/main/java/com/simibubi/create/compat/jei/MixingCategory.java
Normal file
113
src/main/java/com/simibubi/create/compat/jei/MixingCategory.java
Normal file
|
@ -0,0 +1,113 @@
|
|||
package com.simibubi.create.compat.jei;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableInt;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.ScreenResources;
|
||||
import com.simibubi.create.foundation.item.ItemHelper;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
|
||||
import mezz.jei.api.constants.VanillaTypes;
|
||||
import mezz.jei.api.gui.IRecipeLayout;
|
||||
import mezz.jei.api.gui.drawable.IDrawable;
|
||||
import mezz.jei.api.gui.ingredient.IGuiItemStackGroup;
|
||||
import mezz.jei.api.ingredients.IIngredients;
|
||||
import mezz.jei.api.recipe.category.IRecipeCategory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public class MixingCategory implements IRecipeCategory<IRecipe<?>> {
|
||||
|
||||
private AnimatedMixer mixer;
|
||||
private static ResourceLocation ID = new ResourceLocation(Create.ID, "mixing");
|
||||
private IDrawable icon;
|
||||
private IDrawable background = new EmptyBackground(177, 70);
|
||||
|
||||
public MixingCategory() {
|
||||
icon = new DoubleItemIcon(() -> new ItemStack(AllBlocks.MECHANICAL_MIXER.get()),
|
||||
() -> new ItemStack(AllBlocks.BASIN.get()));
|
||||
mixer = new AnimatedMixer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDrawable getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getUid() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return Lang.translate("recipe.mixing");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDrawable getBackground() {
|
||||
return background;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIngredients(IRecipe<?> recipe, IIngredients ingredients) {
|
||||
ingredients.setInputIngredients(recipe.getIngredients());
|
||||
ingredients.setOutput(VanillaTypes.ITEM, recipe.getRecipeOutput());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRecipe(IRecipeLayout recipeLayout, IRecipe<?> recipe, IIngredients ingredients) {
|
||||
IGuiItemStackGroup itemStacks = recipeLayout.getItemStacks();
|
||||
|
||||
NonNullList<Ingredient> recipeIngredients = recipe.getIngredients();
|
||||
List<Pair<Ingredient, MutableInt>> actualIngredients = ItemHelper.condenseIngredients(recipeIngredients);
|
||||
|
||||
int size = actualIngredients.size();
|
||||
int xOffset = size < 3 ? (3 - size) * 19 / 2 : 0;
|
||||
int i = 0;
|
||||
while (i < size) {
|
||||
Pair<Ingredient, MutableInt> ingredient = actualIngredients.get(i);
|
||||
itemStacks.init(i, true, 16 + xOffset + (i % 3) * 19, 50 - (i / 3) * 19);
|
||||
List<ItemStack> asList = Arrays.asList(ingredient.getKey().getMatchingStacks());
|
||||
itemStacks.set(i, asList.stream().map(stack -> {
|
||||
stack = stack.copy();
|
||||
stack.setCount(ingredient.getRight().getValue());
|
||||
return stack;
|
||||
}).collect(Collectors.toList()));
|
||||
i++;
|
||||
}
|
||||
|
||||
itemStacks.init(i, false, 141, 50);
|
||||
itemStacks.set(i, recipe.getRecipeOutput().getStack());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(IRecipe<?> recipe, double mouseX, double mouseY) {
|
||||
List<Pair<Ingredient, MutableInt>> actualIngredients = ItemHelper.condenseIngredients(recipe.getIngredients());
|
||||
|
||||
int size = actualIngredients.size();
|
||||
int xOffset = size < 3 ? (3 - size) * 19 / 2 : 0;
|
||||
for (int i = 0; i < size; i++)
|
||||
ScreenResources.JEI_SLOT.draw(16 + xOffset + (i % 3) * 19, 50 - (i / 3) * 19);
|
||||
ScreenResources.JEI_SLOT.draw(141, 50);
|
||||
ScreenResources.JEI_DOWN_ARROW.draw(136, 32);
|
||||
ScreenResources.JEI_SHADOW.draw(81, 57);
|
||||
mixer.draw(getBackground().getWidth() / 2 + 20, 8);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Class<? extends IRecipe<?>> getRecipeClass() {
|
||||
return (Class<? extends IRecipe<?>>) IRecipe.class;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package com.simibubi.create.compat.jei;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.ScreenResources;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
|
||||
import mezz.jei.api.constants.VanillaTypes;
|
||||
import mezz.jei.api.gui.IRecipeLayout;
|
||||
import mezz.jei.api.gui.drawable.IDrawable;
|
||||
import mezz.jei.api.gui.ingredient.IGuiItemStackGroup;
|
||||
import mezz.jei.api.ingredients.IIngredients;
|
||||
import mezz.jei.api.recipe.category.IRecipeCategory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public class PackingCategory implements IRecipeCategory<IRecipe<?>> {
|
||||
|
||||
private AnimatedPress press;
|
||||
private static ResourceLocation ID = new ResourceLocation(Create.ID, "packing");
|
||||
private IDrawable icon;
|
||||
private IDrawable background = new EmptyBackground(177, 70);
|
||||
|
||||
public PackingCategory() {
|
||||
icon = new DoubleItemIcon(() -> new ItemStack(AllBlocks.MECHANICAL_PRESS.get()),
|
||||
() -> new ItemStack(AllBlocks.BASIN.get()));
|
||||
press = new AnimatedPress(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDrawable getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getUid() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Class<? extends IRecipe<?>> getRecipeClass() {
|
||||
return (Class<? extends IRecipe<?>>) IRecipe.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return Lang.translate("recipe.packing");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDrawable getBackground() {
|
||||
return background;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIngredients(IRecipe<?> recipe, IIngredients ingredients) {
|
||||
ingredients.setInputIngredients(recipe.getIngredients());
|
||||
ingredients.setOutput(VanillaTypes.ITEM, recipe.getRecipeOutput());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRecipe(IRecipeLayout recipeLayout, IRecipe<?> recipe, IIngredients ingredients) {
|
||||
IGuiItemStackGroup itemStacks = recipeLayout.getItemStacks();
|
||||
int i = 0;
|
||||
|
||||
NonNullList<Ingredient> ingredients2 = recipe.getIngredients();
|
||||
int size = ingredients2.size();
|
||||
int rows = size == 4 ? 2 : 3;
|
||||
while (i < size) {
|
||||
Ingredient ingredient = ingredients2.get(i);
|
||||
itemStacks.init(i, true, (rows == 2 ? 26 : 17) + (i % rows) * 19, 50 - (i / rows) * 19);
|
||||
itemStacks.set(i, Arrays.asList(ingredient.getMatchingStacks()));
|
||||
i++;
|
||||
}
|
||||
|
||||
itemStacks.init(i, false, 141, 50);
|
||||
itemStacks.set(i, recipe.getRecipeOutput());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(IRecipe<?> recipe, double mouseX, double mouseY) {
|
||||
NonNullList<Ingredient> ingredients2 = recipe.getIngredients();
|
||||
int size = ingredients2.size();
|
||||
int rows = size == 4 ? 2 : 3;
|
||||
for (int i = 0; i < size; i++) {
|
||||
ScreenResources.JEI_SLOT.draw((rows == 2 ? 26 : 17) + (i % rows) * 19, 50 - (i / rows) * 19);
|
||||
}
|
||||
ScreenResources.JEI_SLOT.draw(141, 50);
|
||||
ScreenResources.JEI_DOWN_ARROW.draw(136, 32);
|
||||
ScreenResources.JEI_SHADOW.draw(81, 57);
|
||||
press.draw(getBackground().getWidth() / 2 + 20, 8);
|
||||
}
|
||||
|
||||
}
|
|
@ -30,7 +30,7 @@ public class PressingCategory implements IRecipeCategory<PressingRecipe> {
|
|||
public PressingCategory() {
|
||||
icon = new DoubleItemIcon(() -> new ItemStack(AllBlocks.MECHANICAL_PRESS.get()),
|
||||
() -> new ItemStack(AllItems.IRON_SHEET.get()));
|
||||
press = new AnimatedPress();
|
||||
press = new AnimatedPress(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -75,6 +75,8 @@ public class PressingCategory implements IRecipeCategory<PressingRecipe> {
|
|||
itemStacks.init(outputIndex + 1, false, 131 + 19 * outputIndex, 50);
|
||||
itemStacks.set(outputIndex + 1, results.get(outputIndex).getStack());
|
||||
}
|
||||
|
||||
CreateJEI.addStochasticTooltip(itemStacks, results);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -83,8 +85,9 @@ public class PressingCategory implements IRecipeCategory<PressingRecipe> {
|
|||
ScreenResources.JEI_SLOT.draw(131, 50);
|
||||
if (recipe.getRollableResults().size() > 1)
|
||||
ScreenResources.JEI_SLOT.draw(131 + 19, 50);
|
||||
ScreenResources.JEI_SHADOW.draw(61, 41);
|
||||
ScreenResources.JEI_LONG_ARROW.draw(52, 54);
|
||||
press.draw(getBackground().getWidth() / 2, 20);
|
||||
press.draw(getBackground().getWidth() / 2, 8);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
package com.simibubi.create.compat.jei;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.ScreenResources;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
import com.simibubi.create.modules.contraptions.components.saw.CuttingRecipe;
|
||||
import com.simibubi.create.modules.contraptions.processing.StochasticOutput;
|
||||
|
||||
import mezz.jei.api.constants.VanillaTypes;
|
||||
import mezz.jei.api.gui.IRecipeLayout;
|
||||
import mezz.jei.api.gui.drawable.IDrawable;
|
||||
import mezz.jei.api.gui.ingredient.IGuiItemStackGroup;
|
||||
import mezz.jei.api.ingredients.IIngredients;
|
||||
import mezz.jei.api.recipe.category.IRecipeCategory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public class SawingCategory implements IRecipeCategory<CuttingRecipe> {
|
||||
|
||||
private AnimatedSaw saw;
|
||||
private static ResourceLocation ID = new ResourceLocation(Create.ID, "sawing");
|
||||
private IDrawable icon;
|
||||
private IDrawable background = new EmptyBackground(177, 70);
|
||||
|
||||
public SawingCategory() {
|
||||
icon = new DoubleItemIcon(() -> new ItemStack(AllBlocks.SAW.get()), () -> new ItemStack(Items.OAK_LOG));
|
||||
saw = new AnimatedSaw();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDrawable getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getUid() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends CuttingRecipe> getRecipeClass() {
|
||||
return CuttingRecipe.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return Lang.translate("recipe.sawing");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDrawable getBackground() {
|
||||
return background;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIngredients(CuttingRecipe recipe, IIngredients ingredients) {
|
||||
ingredients.setInputIngredients(recipe.getIngredients());
|
||||
ingredients.setOutputs(VanillaTypes.ITEM, recipe.getPossibleOutputs());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRecipe(IRecipeLayout recipeLayout, CuttingRecipe recipe, IIngredients ingredients) {
|
||||
IGuiItemStackGroup itemStacks = recipeLayout.getItemStacks();
|
||||
itemStacks.init(0, true, 43, 4);
|
||||
itemStacks.set(0, Arrays.asList(recipe.getIngredients().get(0).getMatchingStacks()));
|
||||
|
||||
List<StochasticOutput> results = recipe.getRollableResults();
|
||||
for (int outputIndex = 0; outputIndex < results.size(); outputIndex++) {
|
||||
int xOffset = outputIndex % 2 == 0 ? 0 : 19;
|
||||
int yOffset = (outputIndex / 2) * -19;
|
||||
|
||||
itemStacks.init(outputIndex + 1, false, 117 + xOffset, 47 + yOffset);
|
||||
itemStacks.set(outputIndex + 1, results.get(outputIndex).getStack());
|
||||
}
|
||||
|
||||
CreateJEI.addStochasticTooltip(itemStacks, results);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(CuttingRecipe recipe, double mouseX, double mouseY) {
|
||||
ScreenResources.JEI_SLOT.draw(43, 4);
|
||||
int size = recipe.getRollableResults().size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
int xOffset = i % 2 == 0 ? 0 : 19;
|
||||
int yOffset = (i / 2) * -19;
|
||||
ScreenResources.JEI_SLOT.draw(117 + xOffset, 47 + yOffset);
|
||||
}
|
||||
ScreenResources.JEI_DOWN_ARROW.draw(70, 6);
|
||||
ScreenResources.JEI_SHADOW.draw(58, 55);
|
||||
saw.draw(72, 35);
|
||||
}
|
||||
|
||||
}
|
|
@ -23,7 +23,6 @@ import net.minecraft.block.FlowingFluidBlock;
|
|||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.text.TextFormatting;
|
||||
|
||||
public class SplashingCategory extends ProcessingViaFanCategory<SplashingRecipe> {
|
||||
|
||||
|
@ -83,14 +82,7 @@ public class SplashingCategory extends ProcessingViaFanCategory<SplashingRecipe>
|
|||
itemStacks.set(outputIndex + 1, results.get(outputIndex).getStack());
|
||||
}
|
||||
|
||||
itemStacks.addTooltipCallback((slotIndex, input, ingredient, tooltip) -> {
|
||||
if (input)
|
||||
return;
|
||||
StochasticOutput output = results.get(slotIndex - 1);
|
||||
if (output.getChance() != 1)
|
||||
tooltip.add(1, TextFormatting.GOLD
|
||||
+ Lang.translate("recipe.processing.chance", (int) (output.getChance() * 100)));
|
||||
});
|
||||
CreateJEI.addStochasticTooltip(itemStacks, results);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -3,7 +3,12 @@ package com.simibubi.create.foundation.item;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableInt;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
import net.minecraftforge.items.ItemHandlerHelper;
|
||||
|
||||
|
@ -33,7 +38,7 @@ public class ItemHelper {
|
|||
if (stack.getCount() > 0)
|
||||
stacks.add(stack);
|
||||
}
|
||||
|
||||
|
||||
public static boolean isSameInventory(IItemHandler h1, IItemHandler h2) {
|
||||
if (h1 == null || h2 == null)
|
||||
return false;
|
||||
|
@ -46,4 +51,38 @@ public class ItemHelper {
|
|||
return true;
|
||||
}
|
||||
|
||||
public static List<Pair<Ingredient, MutableInt>> condenseIngredients(NonNullList<Ingredient> recipeIngredients) {
|
||||
List<Pair<Ingredient, MutableInt>> actualIngredients = new ArrayList<>();
|
||||
Ingredients: for (Ingredient igd : recipeIngredients) {
|
||||
for (Pair<Ingredient, MutableInt> pair : actualIngredients) {
|
||||
ItemStack[] stacks1 = pair.getKey().getMatchingStacks();
|
||||
ItemStack[] stacks2 = igd.getMatchingStacks();
|
||||
if (stacks1.length == stacks2.length) {
|
||||
for (int i = 0; i <= stacks1.length; i++) {
|
||||
if (i == stacks1.length) {
|
||||
pair.getValue().increment();
|
||||
continue Ingredients;
|
||||
}
|
||||
if (!ItemStack.areItemsEqual(stacks1[i], stacks2[i]))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
actualIngredients.add(Pair.of(igd, new MutableInt(1)));
|
||||
}
|
||||
return actualIngredients;
|
||||
}
|
||||
|
||||
public static boolean matchIngredients(Ingredient i1, Ingredient i2) {
|
||||
ItemStack[] stacks1 = i1.getMatchingStacks();
|
||||
ItemStack[] stacks2 = i2.getMatchingStacks();
|
||||
if (stacks1.length == stacks2.length) {
|
||||
for (int i = 0; i < stacks1.length; i++)
|
||||
if (!ItemStack.areItemsEqual(stacks1[i], stacks2[i]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import java.util.List;
|
|||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
@ -13,7 +12,6 @@ import com.google.common.cache.Cache;
|
|||
import com.google.common.cache.CacheBuilder;
|
||||
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.item.crafting.IRecipeType;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
/**
|
||||
|
@ -26,38 +24,7 @@ import net.minecraft.world.World;
|
|||
*/
|
||||
public class RecipeFinder {
|
||||
|
||||
private static Cache<Object, StartedSearch> cachedSearches = CacheBuilder.newBuilder().build();
|
||||
|
||||
public static class StartedSearch {
|
||||
List<IRecipe<?>> findings;
|
||||
|
||||
public StartedSearch(List<IRecipe<?>> findings) {
|
||||
this.findings = findings;
|
||||
}
|
||||
|
||||
public RecipeStream<IRecipe<?>> search() {
|
||||
return new RecipeStream<>(findings.stream());
|
||||
}
|
||||
|
||||
public static class RecipeStream<R extends IRecipe<?>> {
|
||||
Stream<R> stream;
|
||||
|
||||
public RecipeStream(Stream<R> stream) {
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <X extends IRecipe<?>> RecipeStream<X> assumeType(IRecipeType<X> type) {
|
||||
return (RecipeStream<X>) this;
|
||||
}
|
||||
|
||||
public List<R> filter(Predicate<R> condition) {
|
||||
return stream.filter(condition).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
private static Cache<Object, List<IRecipe<?>>> cachedSearches = CacheBuilder.newBuilder().build();
|
||||
|
||||
/**
|
||||
* Find all IRecipes matching the condition predicate. If this search is made
|
||||
|
@ -69,7 +36,7 @@ public class RecipeFinder {
|
|||
* @param conditions
|
||||
* @return A started search to continue with more specific conditions.
|
||||
*/
|
||||
public static StartedSearch get(@Nullable Object cacheKey, World world, Predicate<IRecipe<?>> conditions) {
|
||||
public static List<IRecipe<?>> get(@Nullable Object cacheKey, World world, Predicate<IRecipe<?>> conditions) {
|
||||
if (cacheKey == null)
|
||||
return startSearch(world, conditions);
|
||||
|
||||
|
@ -79,13 +46,13 @@ public class RecipeFinder {
|
|||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return new StartedSearch(Collections.emptyList());
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static StartedSearch startSearch(World world, Predicate<? super IRecipe<?>> conditions) {
|
||||
private static List<IRecipe<?>> startSearch(World world, Predicate<? super IRecipe<?>> conditions) {
|
||||
List<IRecipe<?>> list = world.getRecipeManager().getRecipes().stream().filter(conditions)
|
||||
.collect(Collectors.toList());
|
||||
return new StartedSearch(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,68 +3,49 @@ package com.simibubi.create.modules.contraptions.components.mixer;
|
|||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.simibubi.create.AllPackets;
|
||||
import com.simibubi.create.AllRecipes;
|
||||
import com.simibubi.create.AllTileEntities;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.modules.contraptions.processing.BasinTileEntity;
|
||||
import com.simibubi.create.modules.contraptions.components.press.MechanicalPressTileEntity;
|
||||
import com.simibubi.create.modules.contraptions.processing.BasinOperatingTileEntity;
|
||||
import com.simibubi.create.modules.contraptions.processing.BasinTileEntity.BasinInventory;
|
||||
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.BucketItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.item.crafting.IRecipeSerializer;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.item.crafting.ShapelessRecipe;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.particles.ItemParticleData;
|
||||
import net.minecraft.particles.ParticleTypes;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.items.CapabilityItemHandler;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
import net.minecraftforge.items.IItemHandlerModifiable;
|
||||
import net.minecraftforge.items.ItemHandlerHelper;
|
||||
|
||||
public class MechanicalMixerTileEntity extends KineticTileEntity {
|
||||
public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
|
||||
|
||||
private static Object shapelessOrMixingRecipesKey = new Object();
|
||||
|
||||
public int runningTicks;
|
||||
public int processingTicks;
|
||||
public boolean running;
|
||||
public boolean checkBasin;
|
||||
public boolean basinRemoved;
|
||||
|
||||
public int minIngredients;
|
||||
public int currentValue;
|
||||
public int lastModified;
|
||||
|
||||
private ShapelessRecipe lastRecipe;
|
||||
private LazyOptional<IItemHandler> basinInv = LazyOptional.empty();
|
||||
private List<ItemStack> inputs;
|
||||
|
||||
public MechanicalMixerTileEntity() {
|
||||
super(AllTileEntities.MECHANICAL_MIXER.type);
|
||||
checkBasin = true;
|
||||
minIngredients = currentValue = 1;
|
||||
lastModified = -1;
|
||||
processingTicks = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeedChanged(float prevSpeed) {
|
||||
super.onSpeedChanged(prevSpeed);
|
||||
checkBasin = true;
|
||||
}
|
||||
|
||||
public float getRenderedHeadOffset(float partialTicks) {
|
||||
int localTick = 0;
|
||||
float offset = 0;
|
||||
|
@ -132,7 +113,6 @@ public class MechanicalMixerTileEntity extends KineticTileEntity {
|
|||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (world.isRemote && lastModified != -1) {
|
||||
if (lastModified++ > 10) {
|
||||
|
@ -141,20 +121,14 @@ public class MechanicalMixerTileEntity extends KineticTileEntity {
|
|||
}
|
||||
}
|
||||
|
||||
if (runningTicks == 40) {
|
||||
super.tick();
|
||||
|
||||
if (runningTicks >= 40) {
|
||||
running = false;
|
||||
runningTicks = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (basinRemoved) {
|
||||
basinRemoved = false;
|
||||
if (running) {
|
||||
runningTicks = 40;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
float speed = Math.abs(getSpeed());
|
||||
if (running) {
|
||||
if (world.isRemote && runningTicks == 20)
|
||||
|
@ -163,58 +137,21 @@ public class MechanicalMixerTileEntity extends KineticTileEntity {
|
|||
if (!world.isRemote && runningTicks == 20) {
|
||||
if (processingTicks < 0) {
|
||||
processingTicks = (MathHelper.log2((int) (8000 / speed))) * 15 + 1;
|
||||
return;
|
||||
}
|
||||
processingTicks--;
|
||||
if (processingTicks == 0) {
|
||||
runningTicks++;
|
||||
processingTicks = -1;
|
||||
applyRecipe();
|
||||
sendData();
|
||||
} else {
|
||||
processingTicks--;
|
||||
if (processingTicks == 0) {
|
||||
runningTicks++;
|
||||
processingTicks = -1;
|
||||
applyBasinRecipe();
|
||||
sendData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (runningTicks != 20)
|
||||
runningTicks++;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isSpeedRequirementFulfilled())
|
||||
return;
|
||||
if (!checkBasin)
|
||||
return;
|
||||
checkBasin = false;
|
||||
TileEntity basinTE = world.getTileEntity(pos.down(2));
|
||||
if (basinTE == null || !(basinTE instanceof BasinTileEntity))
|
||||
return;
|
||||
if (!basinInv.isPresent())
|
||||
basinInv = basinTE.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY);
|
||||
if (!basinInv.isPresent())
|
||||
return;
|
||||
|
||||
if (world.isRemote)
|
||||
return;
|
||||
|
||||
gatherInputs();
|
||||
if (matchRecipe(lastRecipe)) {
|
||||
running = true;
|
||||
runningTicks = 0;
|
||||
sendData();
|
||||
return;
|
||||
}
|
||||
|
||||
List<IRecipe<?>> shapelessRecipe = world.getRecipeManager().getRecipes().parallelStream()
|
||||
.filter(recipe -> recipe.getSerializer() == IRecipeSerializer.CRAFTING_SHAPELESS)
|
||||
.filter(this::matchRecipe).sorted((r1, r2) -> r1.getIngredients().size() - r2.getIngredients().size())
|
||||
.collect(Collectors.toList());
|
||||
if (shapelessRecipe.isEmpty())
|
||||
return;
|
||||
|
||||
running = true;
|
||||
runningTicks = 0;
|
||||
lastRecipe = (ShapelessRecipe) shapelessRecipe.get(0);
|
||||
sendData();
|
||||
}
|
||||
|
||||
public void renderParticles() {
|
||||
|
@ -240,64 +177,20 @@ public class MechanicalMixerTileEntity extends KineticTileEntity {
|
|||
}
|
||||
}
|
||||
|
||||
public void gatherInputs() {
|
||||
BasinInventory inv = (BasinInventory) basinInv.orElse(null);
|
||||
inputs = new ArrayList<>();
|
||||
IItemHandlerModifiable inputHandler = inv.getInputHandler();
|
||||
for (int slot = 0; slot < inputHandler.getSlots(); ++slot) {
|
||||
ItemStack itemstack = inputHandler.extractItem(slot, inputHandler.getSlotLimit(slot), true);
|
||||
if (!itemstack.isEmpty()) {
|
||||
inputs.add(itemstack);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected <C extends IInventory> boolean matchStaticFilters(IRecipe<C> r) {
|
||||
return (r.getSerializer() == IRecipeSerializer.CRAFTING_SHAPELESS || r.getType() == AllRecipes.MIXING.type)
|
||||
&& !MechanicalPressTileEntity.canCompress(r.getIngredients());
|
||||
}
|
||||
|
||||
public void applyRecipe() {
|
||||
if (lastRecipe == null)
|
||||
return;
|
||||
if (!basinInv.isPresent())
|
||||
return;
|
||||
|
||||
BasinInventory inv = (BasinInventory) basinInv.orElse(null);
|
||||
if (inv == null)
|
||||
return;
|
||||
|
||||
IItemHandlerModifiable inputs = inv.getInputHandler();
|
||||
IItemHandlerModifiable outputs = inv.getOutputHandler();
|
||||
int buckets = 0;
|
||||
Ingredients: for (Ingredient ingredient : lastRecipe.getIngredients()) {
|
||||
for (int slot = 0; slot < inputs.getSlots(); slot++) {
|
||||
if (!ingredient.test(inputs.extractItem(slot, 1, true)))
|
||||
continue;
|
||||
ItemStack extracted = inputs.extractItem(slot, 1, false);
|
||||
if (extracted.getItem() instanceof BucketItem)
|
||||
buckets++;
|
||||
continue Ingredients;
|
||||
}
|
||||
// something wasn't found
|
||||
return;
|
||||
}
|
||||
|
||||
ItemHandlerHelper.insertItemStacked(outputs, lastRecipe.getRecipeOutput().copy(), false);
|
||||
if (buckets > 0)
|
||||
ItemHandlerHelper.insertItemStacked(outputs, new ItemStack(Items.BUCKET, buckets), false);
|
||||
|
||||
// Continue mixing
|
||||
gatherInputs();
|
||||
if (matchRecipe(lastRecipe)) {
|
||||
runningTicks = 20;
|
||||
sendData();
|
||||
}
|
||||
}
|
||||
|
||||
public <C extends IInventory> boolean matchRecipe(IRecipe<C> recipe) {
|
||||
if (!(recipe instanceof ShapelessRecipe))
|
||||
@Override
|
||||
protected <C extends IInventory> boolean matchBasinRecipe(IRecipe<C> recipe) {
|
||||
if (recipe == null)
|
||||
return false;
|
||||
if (recipe.getIngredients().size() < minIngredients)
|
||||
return false;
|
||||
|
||||
ShapelessRecipe shapelessRecipe = (ShapelessRecipe) recipe;
|
||||
NonNullList<Ingredient> ingredients = shapelessRecipe.getIngredients();
|
||||
NonNullList<Ingredient> ingredients = recipe.getIngredients();
|
||||
if (!ingredients.stream().allMatch(Ingredient::isSimple))
|
||||
return false;
|
||||
|
||||
|
@ -321,4 +214,33 @@ public class MechanicalMixerTileEntity extends KineticTileEntity {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startProcessingBasin() {
|
||||
if (running)
|
||||
return;
|
||||
super.startProcessingBasin();
|
||||
running = true;
|
||||
runningTicks = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean continueWithPreviousRecipe() {
|
||||
runningTicks = 20;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void basinRemoved() {
|
||||
super.basinRemoved();
|
||||
if (running) {
|
||||
runningTicks = 40;
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object getRecipeCacheKey() {
|
||||
return shapelessOrMixingRecipesKey;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import com.simibubi.create.foundation.block.SyncedTileEntity;
|
|||
import com.simibubi.create.foundation.item.ItemHelper;
|
||||
import com.simibubi.create.foundation.utility.AllShapes;
|
||||
import com.simibubi.create.modules.contraptions.base.HorizontalKineticBlock;
|
||||
import com.simibubi.create.modules.contraptions.components.press.MechanicalPressTileEntity.Mode;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.BeltAttachmentState;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.IBeltAttachment;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock;
|
||||
|
@ -62,7 +63,7 @@ public class MechanicalPressBlock extends HorizontalKineticBlock
|
|||
|
||||
if (worldIn.isBlockPowered(pos)) {
|
||||
if (!te.finished && !te.running && te.getSpeed() != 0)
|
||||
te.start(false);
|
||||
te.start(Mode.WORLD);
|
||||
} else {
|
||||
te.finished = false;
|
||||
}
|
||||
|
@ -139,7 +140,7 @@ public class MechanicalPressBlock extends HorizontalKineticBlock
|
|||
return false;
|
||||
|
||||
state.processingDuration = 1;
|
||||
pressTe.start(true);
|
||||
pressTe.start(Mode.BELT);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -156,6 +157,10 @@ public class MechanicalPressBlock extends HorizontalKineticBlock
|
|||
if (pressTe.running) {
|
||||
if (pressTe.runningTicks == 30) {
|
||||
Optional<PressingRecipe> recipe = pressTe.getRecipe(transportedStack.stack);
|
||||
|
||||
pressTe.pressedItems.clear();
|
||||
pressTe.pressedItems.add(transportedStack.stack);
|
||||
|
||||
if (!recipe.isPresent())
|
||||
return false;
|
||||
ItemStack out = recipe.get().getRecipeOutput().copy();
|
||||
|
@ -167,6 +172,7 @@ public class MechanicalPressBlock extends HorizontalKineticBlock
|
|||
TileEntity controllerTE = te.getWorld().getTileEntity(te.getController());
|
||||
if (controllerTE != null && controllerTE instanceof BeltTileEntity)
|
||||
((SyncedTileEntity) controllerTE).sendData();
|
||||
pressTe.sendData();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,31 +1,43 @@
|
|||
package com.simibubi.create.modules.contraptions.components.press;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.simibubi.create.AllRecipes;
|
||||
import com.simibubi.create.AllTileEntities;
|
||||
import com.simibubi.create.foundation.item.ItemHelper;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.TransportedItemStack;
|
||||
import com.simibubi.create.modules.contraptions.processing.BasinOperatingTileEntity;
|
||||
import com.simibubi.create.modules.contraptions.processing.BasinTileEntity.BasinInventory;
|
||||
import com.simibubi.create.modules.logistics.InWorldProcessing;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.item.ItemEntity;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.ICraftingRecipe;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.ListNBT;
|
||||
import net.minecraft.particles.ItemParticleData;
|
||||
import net.minecraft.particles.ParticleTypes;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.util.SoundEvents;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.common.util.Constants.NBT;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
import net.minecraftforge.items.ItemStackHandler;
|
||||
import net.minecraftforge.items.wrapper.RecipeWrapper;
|
||||
|
||||
public class MechanicalPressTileEntity extends KineticTileEntity {
|
||||
public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
|
||||
|
||||
private static Object compressingRecipesKey = new Object();
|
||||
public List<ItemStack> pressedItems = new ArrayList<>();
|
||||
|
||||
public static class PressingInv extends RecipeWrapper {
|
||||
public PressingInv() {
|
||||
|
@ -33,20 +45,33 @@ public class MechanicalPressTileEntity extends KineticTileEntity {
|
|||
}
|
||||
}
|
||||
|
||||
enum Mode {
|
||||
WORLD(1), BELT(19f / 16f), BASIN(22f / 16f)
|
||||
|
||||
;
|
||||
|
||||
float headOffset;
|
||||
|
||||
private Mode(float headOffset) {
|
||||
this.headOffset = headOffset;
|
||||
}
|
||||
}
|
||||
|
||||
private static PressingInv pressingInv = new PressingInv();
|
||||
public int runningTicks;
|
||||
public boolean running;
|
||||
public boolean beltMode;
|
||||
public Mode mode;
|
||||
public boolean finished;
|
||||
|
||||
public MechanicalPressTileEntity() {
|
||||
super(AllTileEntities.MECHANICAL_PRESS.type);
|
||||
mode = Mode.WORLD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(CompoundNBT compound) {
|
||||
running = compound.getBoolean("Running");
|
||||
beltMode = compound.getBoolean("OnBelt");
|
||||
mode = Mode.values()[compound.getInt("Mode")];
|
||||
finished = compound.getBoolean("Finished");
|
||||
runningTicks = compound.getInt("Ticks");
|
||||
super.read(compound);
|
||||
|
@ -55,37 +80,67 @@ public class MechanicalPressTileEntity extends KineticTileEntity {
|
|||
@Override
|
||||
public CompoundNBT write(CompoundNBT compound) {
|
||||
compound.putBoolean("Running", running);
|
||||
compound.putBoolean("OnBelt", beltMode);
|
||||
compound.putInt("Mode", mode.ordinal());
|
||||
compound.putBoolean("Finished", finished);
|
||||
compound.putInt("Ticks", runningTicks);
|
||||
return super.write(compound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundNBT writeToClient(CompoundNBT tag) {
|
||||
ListNBT particleItems = new ListNBT();
|
||||
pressedItems.forEach(stack -> particleItems.add(stack.serializeNBT()));
|
||||
tag.put("ParticleItems", particleItems);
|
||||
return super.writeToClient(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readClientUpdate(CompoundNBT tag) {
|
||||
super.readClientUpdate(tag);
|
||||
ListNBT particleItems = tag.getList("ParticleItems", NBT.TAG_COMPOUND);
|
||||
particleItems.forEach(nbt -> pressedItems.add(ItemStack.read((CompoundNBT) nbt)));
|
||||
spawnParticles();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AxisAlignedBB getRenderBoundingBox() {
|
||||
return new AxisAlignedBB(pos).expand(0, -1.5, 0);
|
||||
return new AxisAlignedBB(pos).expand(0, -1.5, 0).expand(0, 1, 0);
|
||||
}
|
||||
|
||||
public float getRenderedHeadOffset(float partialTicks) {
|
||||
if (running) {
|
||||
if (runningTicks < 40) {
|
||||
float num = (runningTicks - 1 + partialTicks) / 30f;
|
||||
return MathHelper.clamp(num * num * num, 0, beltMode ? 1 + 3 / 16f : 1);
|
||||
return MathHelper.clamp(num * num * num, 0, mode.headOffset);
|
||||
}
|
||||
if (runningTicks >= 40) {
|
||||
return MathHelper.clamp(((60 - runningTicks) + 1 - partialTicks) / 20f, 0, beltMode ? 1 + 3 / 16f : 1);
|
||||
return MathHelper.clamp(((60 - runningTicks) + 1 - partialTicks) / 20f * mode.headOffset, 0,
|
||||
mode.headOffset);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void start(boolean onBelt) {
|
||||
beltMode = onBelt;
|
||||
public void start(Mode mode) {
|
||||
this.mode = mode;
|
||||
running = true;
|
||||
runningTicks = 0;
|
||||
pressedItems.clear();
|
||||
sendData();
|
||||
}
|
||||
|
||||
public boolean inWorld() {
|
||||
return mode == Mode.WORLD;
|
||||
}
|
||||
|
||||
public boolean onBelt() {
|
||||
return mode == Mode.BELT;
|
||||
}
|
||||
|
||||
public boolean onBasin() {
|
||||
return mode == Mode.BASIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
@ -95,16 +150,18 @@ public class MechanicalPressTileEntity extends KineticTileEntity {
|
|||
|
||||
if (runningTicks == 30) {
|
||||
|
||||
if (!beltMode) {
|
||||
AxisAlignedBB bb = new AxisAlignedBB(pos.down(beltMode ? 2 : 1));
|
||||
if (inWorld()) {
|
||||
AxisAlignedBB bb = new AxisAlignedBB(pos.down(1));
|
||||
pressedItems.clear();
|
||||
for (Entity entity : world.getEntitiesWithinAABBExcludingEntity(null, bb)) {
|
||||
if (!(entity instanceof ItemEntity))
|
||||
continue;
|
||||
|
||||
ItemEntity itemEntity = (ItemEntity) entity;
|
||||
makeParticleEffect(entity.getPositionVec(), itemEntity.getItem());
|
||||
|
||||
if (!world.isRemote) {
|
||||
pressedItems.add(itemEntity.getItem());
|
||||
sendData();
|
||||
Optional<PressingRecipe> recipe = getRecipe(itemEntity.getItem());
|
||||
if (recipe.isPresent())
|
||||
InWorldProcessing.applyRecipeOn(itemEntity, recipe.get());
|
||||
|
@ -112,18 +169,22 @@ public class MechanicalPressTileEntity extends KineticTileEntity {
|
|||
}
|
||||
}
|
||||
|
||||
if (beltMode && world.isRemote) {
|
||||
TileEntity te = world.getTileEntity(pos.down(2));
|
||||
if (te != null && te instanceof BeltTileEntity) {
|
||||
BeltTileEntity beltTE = (BeltTileEntity) te;
|
||||
TileEntity controller = world.getTileEntity(beltTE.getController());
|
||||
if (controller != null && controller instanceof BeltTileEntity) {
|
||||
TransportedItemStack stackAtOffset = ((BeltTileEntity) controller).getInventory()
|
||||
.getStackAtOffset(beltTE.index);
|
||||
if (stackAtOffset != null)
|
||||
makeParticleEffect(VecHelper.getCenterOf(pos.down(2)).add(0, 5 / 16f, 0),
|
||||
stackAtOffset.stack);
|
||||
if (onBasin()) {
|
||||
if (!world.isRemote) {
|
||||
pressedItems.clear();
|
||||
applyBasinRecipe();
|
||||
IItemHandler orElse = basinInv.orElse(null);
|
||||
if (basinInv.isPresent() && orElse instanceof BasinInventory) {
|
||||
BasinInventory inv = (BasinInventory) orElse;
|
||||
|
||||
for (int slot = 0; slot < inv.getInputHandler().getSlots(); slot++) {
|
||||
ItemStack stackInSlot = inv.getStackInSlot(slot);
|
||||
if (stackInSlot.isEmpty())
|
||||
continue;
|
||||
pressedItems.add(stackInSlot);
|
||||
}
|
||||
}
|
||||
sendData();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -136,9 +197,18 @@ public class MechanicalPressTileEntity extends KineticTileEntity {
|
|||
|
||||
if (!world.isRemote && runningTicks > 60) {
|
||||
finished = true;
|
||||
if (!beltMode)
|
||||
if (inWorld())
|
||||
finished = world.isBlockPowered(pos);
|
||||
running = false;
|
||||
|
||||
if (onBasin()) {
|
||||
gatherInputs();
|
||||
if (matchBasinRecipe(lastRecipe)) {
|
||||
startProcessingBasin();
|
||||
}
|
||||
}
|
||||
|
||||
pressedItems.clear();
|
||||
sendData();
|
||||
return;
|
||||
}
|
||||
|
@ -146,12 +216,41 @@ public class MechanicalPressTileEntity extends KineticTileEntity {
|
|||
runningTicks++;
|
||||
}
|
||||
|
||||
public void makeParticleEffect(Vec3d pos, ItemStack stack) {
|
||||
protected void spawnParticles() {
|
||||
if (pressedItems.isEmpty())
|
||||
return;
|
||||
|
||||
if (mode == Mode.BASIN) {
|
||||
pressedItems.forEach(stack -> makeCompactingParticleEffect(VecHelper.getCenterOf(pos.down(2)), stack));
|
||||
}
|
||||
if (mode == Mode.BELT) {
|
||||
pressedItems.forEach(
|
||||
stack -> makePressingParticleEffect(VecHelper.getCenterOf(pos.down(2)).add(0, 8 / 16f, 0), stack));
|
||||
}
|
||||
if (mode == Mode.WORLD) {
|
||||
pressedItems.forEach(
|
||||
stack -> makePressingParticleEffect(VecHelper.getCenterOf(pos.down(1)).add(0, -1 / 4f, 0), stack));
|
||||
}
|
||||
|
||||
pressedItems.clear();
|
||||
}
|
||||
|
||||
public void makePressingParticleEffect(Vec3d pos, ItemStack stack) {
|
||||
if (world.isRemote) {
|
||||
for (int i = 0; i < 20; i++) {
|
||||
Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .25f).mul(1, 0, 1);
|
||||
Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f).mul(1, 0, 1);
|
||||
world.addParticle(new ItemParticleData(ParticleTypes.ITEM, stack), pos.x, pos.y - .25f, pos.z, motion.x,
|
||||
motion.y + .125f, motion.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void makeCompactingParticleEffect(Vec3d pos, ItemStack stack) {
|
||||
if (world.isRemote) {
|
||||
for (int i = 0; i < 20; i++) {
|
||||
Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .175f).mul(1, 0, 1);
|
||||
world.addParticle(new ItemParticleData(ParticleTypes.ITEM, stack), pos.x, pos.y, pos.z, motion.x,
|
||||
motion.y, motion.z);
|
||||
motion.y + .25f, motion.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -163,4 +262,59 @@ public class MechanicalPressTileEntity extends KineticTileEntity {
|
|||
return recipe;
|
||||
}
|
||||
|
||||
public static boolean canCompress(NonNullList<Ingredient> ingredients) {
|
||||
return (ingredients.size() == 4 || ingredients.size() == 9)
|
||||
&& ItemHelper.condenseIngredients(ingredients).size() == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <C extends IInventory> boolean matchStaticFilters(IRecipe<C> recipe) {
|
||||
return recipe instanceof ICraftingRecipe && canCompress(recipe.getIngredients());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <C extends IInventory> boolean matchBasinRecipe(IRecipe<C> recipe) {
|
||||
if (recipe == null)
|
||||
return false;
|
||||
|
||||
NonNullList<Ingredient> ingredients = recipe.getIngredients();
|
||||
if (!ingredients.stream().allMatch(Ingredient::isSimple))
|
||||
return false;
|
||||
|
||||
List<ItemStack> remaining = new ArrayList<>();
|
||||
inputs.forEach(stack -> remaining.add(stack.copy()));
|
||||
|
||||
Ingredients: for (Ingredient ingredient : ingredients) {
|
||||
for (ItemStack stack : remaining) {
|
||||
if (stack.isEmpty())
|
||||
continue;
|
||||
if (ingredient.test(stack)) {
|
||||
stack.shrink(1);
|
||||
continue Ingredients;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object getRecipeCacheKey() {
|
||||
return compressingRecipesKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startProcessingBasin() {
|
||||
if (running)
|
||||
return;
|
||||
super.startProcessingBasin();
|
||||
start(Mode.BASIN);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void basinRemoved() {
|
||||
pressedItems.clear();
|
||||
super.basinRemoved();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ import static com.simibubi.create.modules.contraptions.components.saw.SawBlock.R
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllRecipes;
|
||||
import com.simibubi.create.AllTileEntities;
|
||||
|
@ -16,8 +16,6 @@ import com.simibubi.create.foundation.utility.TreeCutter.Tree;
|
|||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.foundation.utility.recipe.RecipeConditions;
|
||||
import com.simibubi.create.foundation.utility.recipe.RecipeFinder;
|
||||
import com.simibubi.create.foundation.utility.recipe.RecipeFinder.StartedSearch;
|
||||
import com.simibubi.create.foundation.utility.recipe.RecipeFinder.StartedSearch.RecipeStream;
|
||||
import com.simibubi.create.modules.contraptions.components.actors.BlockBreakingKineticTileEntity;
|
||||
import com.simibubi.create.modules.contraptions.processing.ProcessingInventory;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity;
|
||||
|
@ -283,11 +281,11 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity implements IHa
|
|||
}
|
||||
|
||||
private List<? extends IRecipe<?>> getRecipes() {
|
||||
StartedSearch startedSearch = RecipeFinder.get(cuttingRecipesKey, world,
|
||||
List<IRecipe<?>> startedSearch = RecipeFinder.get(cuttingRecipesKey, world,
|
||||
RecipeConditions.isOfType(IRecipeType.STONECUTTING, AllRecipes.Types.CUTTING));
|
||||
RecipeStream<IRecipe<?>> search = startedSearch.search();
|
||||
return search.filter(Predicates.and(RecipeConditions.outputMatchesFilter(filter),
|
||||
RecipeConditions.firstIngredientMatches(inventory.getStackInSlot(0))));
|
||||
return startedSearch.stream().filter(RecipeConditions.outputMatchesFilter(filter))
|
||||
.filter(RecipeConditions.firstIngredientMatches(inventory.getStackInSlot(0)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public void insertItem(ItemEntity entity) {
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
package com.simibubi.create.modules.contraptions.processing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.simibubi.create.foundation.utility.recipe.RecipeFinder;
|
||||
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.modules.contraptions.processing.BasinTileEntity.BasinInventory;
|
||||
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.BucketItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.tileentity.TileEntityType;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.items.CapabilityItemHandler;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
import net.minecraftforge.items.IItemHandlerModifiable;
|
||||
import net.minecraftforge.items.ItemHandlerHelper;
|
||||
|
||||
public abstract class BasinOperatingTileEntity extends KineticTileEntity {
|
||||
|
||||
public boolean checkBasin;
|
||||
public boolean basinRemoved;
|
||||
protected IRecipe<?> lastRecipe;
|
||||
protected LazyOptional<IItemHandler> basinInv = LazyOptional.empty();
|
||||
protected List<ItemStack> inputs;
|
||||
|
||||
public BasinOperatingTileEntity(TileEntityType<?> typeIn) {
|
||||
super(typeIn);
|
||||
checkBasin = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeedChanged(float prevSpeed) {
|
||||
super.onSpeedChanged(prevSpeed);
|
||||
checkBasin = true;
|
||||
}
|
||||
|
||||
public void gatherInputs() {
|
||||
BasinInventory inv = (BasinInventory) basinInv.orElse(null);
|
||||
inputs = new ArrayList<>();
|
||||
IItemHandlerModifiable inputHandler = inv.getInputHandler();
|
||||
for (int slot = 0; slot < inputHandler.getSlots(); ++slot) {
|
||||
ItemStack itemstack = inputHandler.extractItem(slot, inputHandler.getSlotLimit(slot), true);
|
||||
if (!itemstack.isEmpty()) {
|
||||
inputs.add(itemstack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (basinRemoved) {
|
||||
basinRemoved = false;
|
||||
basinRemoved();
|
||||
sendData();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isSpeedRequirementFulfilled())
|
||||
return;
|
||||
if (!isCheckingBasin())
|
||||
return;
|
||||
if (!checkBasin)
|
||||
return;
|
||||
checkBasin = false;
|
||||
TileEntity basinTE = world.getTileEntity(pos.down(2));
|
||||
if (basinTE == null || !(basinTE instanceof BasinTileEntity))
|
||||
return;
|
||||
if (!basinInv.isPresent())
|
||||
basinInv = basinTE.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY);
|
||||
if (!basinInv.isPresent())
|
||||
return;
|
||||
|
||||
if (world.isRemote)
|
||||
return;
|
||||
|
||||
gatherInputs();
|
||||
// if (matchBasinRecipe(lastRecipe)) {
|
||||
// startProcessingBasin();
|
||||
// sendData();
|
||||
// return;
|
||||
// }
|
||||
List<IRecipe<?>> recipes = getMatchingRecipes();
|
||||
if (recipes.isEmpty())
|
||||
return;
|
||||
|
||||
lastRecipe = recipes.get(0);
|
||||
startProcessingBasin();
|
||||
sendData();
|
||||
}
|
||||
|
||||
protected boolean isCheckingBasin() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void startProcessingBasin() {
|
||||
}
|
||||
|
||||
public boolean continueWithPreviousRecipe() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void applyBasinRecipe() {
|
||||
if (lastRecipe == null)
|
||||
return;
|
||||
if (!basinInv.isPresent())
|
||||
return;
|
||||
|
||||
BasinInventory inv = (BasinInventory) basinInv.orElse(null);
|
||||
if (inv == null)
|
||||
return;
|
||||
|
||||
IItemHandlerModifiable inputs = inv.getInputHandler();
|
||||
IItemHandlerModifiable outputs = inv.getOutputHandler();
|
||||
int buckets = 0;
|
||||
Ingredients: for (Ingredient ingredient : lastRecipe.getIngredients()) {
|
||||
for (int slot = 0; slot < inputs.getSlots(); slot++) {
|
||||
if (!ingredient.test(inputs.extractItem(slot, 1, true)))
|
||||
continue;
|
||||
ItemStack extracted = inputs.extractItem(slot, 1, false);
|
||||
if (extracted.getItem() instanceof BucketItem)
|
||||
buckets++;
|
||||
continue Ingredients;
|
||||
}
|
||||
// something wasn't found
|
||||
return;
|
||||
}
|
||||
|
||||
ItemHandlerHelper.insertItemStacked(outputs, lastRecipe.getRecipeOutput().copy(), false);
|
||||
if (buckets > 0)
|
||||
ItemHandlerHelper.insertItemStacked(outputs, new ItemStack(Items.BUCKET, buckets), false);
|
||||
|
||||
// Continue mixing
|
||||
gatherInputs();
|
||||
if (matchBasinRecipe(lastRecipe)) {
|
||||
continueWithPreviousRecipe();
|
||||
sendData();
|
||||
}
|
||||
}
|
||||
|
||||
protected List<IRecipe<?>> getMatchingRecipes() {
|
||||
List<IRecipe<?>> list = RecipeFinder.get(getRecipeCacheKey(), world, this::matchStaticFilters);
|
||||
return list.stream().filter(this::matchBasinRecipe)
|
||||
.sorted((r1, r2) -> -r1.getIngredients().size() + r2.getIngredients().size())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
protected void basinRemoved() {
|
||||
|
||||
}
|
||||
|
||||
protected abstract <C extends IInventory> boolean matchStaticFilters(IRecipe<C> recipe);
|
||||
|
||||
protected abstract <C extends IInventory> boolean matchBasinRecipe(IRecipe<C> recipe);
|
||||
|
||||
protected abstract Object getRecipeCacheKey();
|
||||
|
||||
}
|
|
@ -2,7 +2,6 @@ package com.simibubi.create.modules.contraptions.processing;
|
|||
|
||||
import com.simibubi.create.AllTileEntities;
|
||||
import com.simibubi.create.foundation.block.SyncedTileEntity;
|
||||
import com.simibubi.create.modules.contraptions.components.mixer.MechanicalMixerTileEntity;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
|
@ -27,7 +26,7 @@ public class BasinTileEntity extends SyncedTileEntity implements ITickableTileEn
|
|||
markDirty();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public class BasinInputInventory extends RecipeWrapper {
|
||||
public BasinInputInventory() {
|
||||
super(inputInventory);
|
||||
|
@ -99,15 +98,15 @@ public class BasinTileEntity extends SyncedTileEntity implements ITickableTileEn
|
|||
compound.put("OutputItems", outputInventory.serializeNBT());
|
||||
return compound;
|
||||
}
|
||||
|
||||
|
||||
public void onEmptied() {
|
||||
TileEntity te = world.getTileEntity(pos.up(2));
|
||||
if (te == null)
|
||||
return;
|
||||
if (te instanceof MechanicalMixerTileEntity)
|
||||
((MechanicalMixerTileEntity) te).basinRemoved = true;
|
||||
if (te instanceof BasinOperatingTileEntity)
|
||||
((BasinOperatingTileEntity) te).basinRemoved = true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
onEmptied();
|
||||
|
@ -131,8 +130,8 @@ public class BasinTileEntity extends SyncedTileEntity implements ITickableTileEn
|
|||
TileEntity te = world.getTileEntity(pos.up(2));
|
||||
if (te == null)
|
||||
return;
|
||||
if (te instanceof MechanicalMixerTileEntity)
|
||||
((MechanicalMixerTileEntity) te).checkBasin = true;
|
||||
if (te instanceof BasinOperatingTileEntity)
|
||||
((BasinOperatingTileEntity) te).checkBasin = true;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,9 @@ public class ProcessingRecipeSerializer<T extends ProcessingRecipe<?>>
|
|||
results.add(new StochasticOutput(itemstack, chance));
|
||||
}
|
||||
|
||||
int duration = JSONUtils.getInt(json, "processingTime");
|
||||
int duration = -1;
|
||||
if (JSONUtils.hasField(json, "processingTime"))
|
||||
duration = JSONUtils.getInt(json, "processingTime");
|
||||
|
||||
return this.factory.create(recipeId, s, ingredients, results, duration);
|
||||
}
|
||||
|
|
|
@ -184,7 +184,11 @@
|
|||
"create.recipe.smokingViaFan.fan": "Fan behind Fire",
|
||||
"create.recipe.blastingViaFan": "Bulk Smelting",
|
||||
"create.recipe.blastingViaFan.fan": "Fan behind Lava",
|
||||
"create.recipe.pressing": "Mechanical Press",
|
||||
"create.recipe.pressing": "Pressing",
|
||||
"create.recipe.mixing": "Mixing",
|
||||
"create.recipe.packing": "Compressing",
|
||||
"create.recipe.sawing": "Sawing",
|
||||
"create.recipe.block_cutting": "Block Cutting",
|
||||
"create.recipe.blockzapperUpgrade": "Handheld Blockzapper",
|
||||
"create.recipe.processing.chance": "%1$s%% Chance",
|
||||
|
||||
|
@ -571,7 +575,7 @@
|
|||
"block.create.mechanical_mixer.tooltip.condition1": "When above Basin",
|
||||
"block.create.mechanical_mixer.tooltip.behaviour1": "Starts to mix items in the basin whenever all necessary ingredients are present.",
|
||||
"block.create.mechanical_mixer.tooltip.condition2": "When used with Wrench",
|
||||
"block.create.mechanical_mixer.tooltip.behaviour2": "_Configures_ the minimum amount of _different_ _ingredients_ required before the mixer should begin. Use this option to rule out unwanted recipes with similar but less ingredients.",
|
||||
"block.create.mechanical_mixer.tooltip.behaviour2": "_Configures_ the minimum amount of _total_ _ingredients_ for applied recipes. Use this option to _rule_ _out_ _unwanted_ _recipes_ with similar but less ingredients.",
|
||||
|
||||
"block.create.mechanical_piston.tooltip": "MECHANICAL PISTON",
|
||||
"block.create.mechanical_piston.tooltip.summary": "A more advanced version of the _Piston,_ using _Rotational_ _Force_ to precisely move attached structures. _Piston_ _Extension_ _Poles_ at the rear define the _Range_ of this Device. Without extensions, the piston will not move. Use _Translation_ _Chassis_ to move more than a single line of blocks.",
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"type": "create:mixing",
|
||||
"group": "minecraft:misc",
|
||||
"ingredients": [
|
||||
{
|
||||
"item": "minecraft:andesite"
|
||||
},
|
||||
{
|
||||
"item": "minecraft:iron_nugget"
|
||||
}
|
||||
],
|
||||
"results": [
|
||||
{
|
||||
"item": "create:andesite_alloy_cube",
|
||||
"count": 1
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue