From 53774d64afd71d9b44e68628b4e86dea560c0860 Mon Sep 17 00:00:00 2001 From: reidbhuntley Date: Sat, 28 Aug 2021 20:07:57 -0400 Subject: [PATCH 1/6] Fix infinite source blacklist being ignored --- .../contraptions/fluids/actors/FluidManipulationBehaviour.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FluidManipulationBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FluidManipulationBehaviour.java index d3ecf1394..69f013bc4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FluidManipulationBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FluidManipulationBehaviour.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Set; import java.util.function.BiConsumer; +import com.simibubi.create.AllTags; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.fluid.FluidHelper; import com.simibubi.create.foundation.networking.AllPackets; @@ -205,7 +206,7 @@ public abstract class FluidManipulationBehaviour extends TileEntityBehaviour { } protected boolean canDrainInfinitely(Fluid fluid) { - return maxBlocks() != -1; // && !AllFluidTags.NO_INFINITE_DRAINING.matches(fluid); + return maxBlocks() != -1 && !AllTags.AllFluidTags.NO_INFINITE_DRAINING.matches(fluid); } @Override From b734f73db39374c7b4a81e683f0520cefd8f27ea Mon Sep 17 00:00:00 2001 From: grimmauld Date: Sun, 29 Aug 2021 12:27:33 +0200 Subject: [PATCH 2/6] made armor stands in ponder scenes less likely to break to null worlds --- .../simibubi/create/foundation/ponder/PonderScene.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/simibubi/create/foundation/ponder/PonderScene.java b/src/main/java/com/simibubi/create/foundation/ponder/PonderScene.java index 0befcd501..b91839fd8 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/PonderScene.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/PonderScene.java @@ -52,6 +52,8 @@ import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.vector.Vector3i; import net.minecraft.util.math.vector.Vector4f; +import javax.annotation.Nullable; + public class PonderScene { public static final String TITLE_KEY = "header"; @@ -79,6 +81,7 @@ public class PonderScene { Vector3d pointOfInterest; Vector3d chasingPointOfInterest; WorldSectionElement baseWorldSection; + @Nullable Entity renderViewEntity; int basePlateOffsetX; @@ -112,7 +115,7 @@ public class PonderScene { basePlateSize = getBounds().getXSpan(); info = new SceneRenderInfo(); baseWorldSection = new WorldSectionElement(); - renderViewEntity = new ArmorStandEntity(world, 0, 0, 0); + renderViewEntity = world != null ? new ArmorStandEntity(world, 0, 0, 0) : null; keyframeTimes = new IntArrayList(4); scaleFactor = 1; yOffset = 0; @@ -486,7 +489,8 @@ public class PonderScene { public void updateSceneRVE(float pt) { Vector3d v = screenToScene(width / 2, height / 2, 500, pt); - renderViewEntity.setPos(v.x, v.y, v.z); + if (renderViewEntity != null) + renderViewEntity.setPos(v.x, v.y, v.z); } public Vector3d screenToScene(double x, double y, int depth, float pt) { From aecd98838497a01aae7c75acc817e1841c0e0926 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Tue, 31 Aug 2021 13:46:28 +0200 Subject: [PATCH 3/6] Foliage Machine - Mechanical Harvesters can now be used to gather Leaves - Mechanical Harvesters can now be used to gather Weeping and Twisting Vines - Fixed JEI integration of Basin recipes with multiple and/or stochastic outputs --- .../compat/jei/category/BasinCategory.java | 62 +++++++++++-------- .../actors/HarvesterMovementBehaviour.java | 23 ++++--- 2 files changed, 53 insertions(+), 32 deletions(-) diff --git a/src/main/java/com/simibubi/create/compat/jei/category/BasinCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/BasinCategory.java index 60bd73223..ddbec7c2c 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/BasinCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/BasinCategory.java @@ -6,7 +6,6 @@ import java.util.stream.Collectors; import org.apache.commons.lang3.mutable.MutableInt; -import com.google.common.collect.ImmutableList; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; @@ -73,17 +72,10 @@ public class BasinCategory extends CreateRecipeCategory { IGuiItemStackGroup itemStacks = recipeLayout.getItemStacks(); IGuiFluidStackGroup fluidStacks = recipeLayout.getFluidStacks(); - ItemStack itemOutput = recipe.getRollableResultsAsItemStacks() - .isEmpty() ? ItemStack.EMPTY - : recipe.getRollableResultsAsItemStacks() - .get(0); - FluidStack fluidOutput = recipe.getFluidResults() - .isEmpty() ? FluidStack.EMPTY - : recipe.getFluidResults() - .get(0); - NonNullList fluidIngredients = recipe.getFluidIngredients(); List> ingredients = ItemHelper.condenseIngredients(recipe.getIngredients()); + List itemOutputs = recipe.getRollableResultsAsItemStacks(); + NonNullList fluidOutputs = recipe.getFluidResults(); int size = ingredients.size() + fluidIngredients.size(); int xOffset = size < 3 ? (3 - size) * 19 / 2 : 0; @@ -115,28 +107,41 @@ public class BasinCategory extends CreateRecipeCategory { fluidStacks.set(j, withImprovedVisibility(stacks)); } - if (!itemOutput.isEmpty()) { - itemStacks.init(i, false, 141, 50 + yOffset); - itemStacks.set(i, recipe.getResultItem() - .getStack()); - yOffset -= 19; + int outSize = fluidOutputs.size() + recipe.getRollableResults() + .size(); + int outputIndex = 0; + + if (!itemOutputs.isEmpty()) + addStochasticTooltip(itemStacks, recipe.getRollableResults(), i); + + for (; outputIndex < outSize; outputIndex++) { + int xPosition = 141 - (outSize % 2 != 0 && outputIndex == outSize - 1 ? 0 : outputIndex % 2 == 0 ? 10 : -9); + int yPosition = -19 * (outputIndex / 2) + 50 + yOffset; + + if (itemOutputs.size() > outputIndex) { + itemStacks.init(i, false, xPosition, yPosition + yOffset); + itemStacks.set(i, itemOutputs.get(outputIndex)); + i++; + } else { + fluidStacks.init(j, false, xPosition + 1, yPosition + 1 + yOffset); + fluidStacks.set(j, withImprovedVisibility(fluidOutputs.get(outputIndex - itemOutputs.size()))); + j++; + } + } - if (!fluidOutput.isEmpty()) { - fluidStacks.init(j, false, 142, 51 + yOffset); - fluidStacks.set(j, withImprovedVisibility(fluidOutput)); - } - - addFluidTooltip(fluidStacks, fluidIngredients, ImmutableList.of(fluidOutput)); + addFluidTooltip(fluidStacks, fluidIngredients, fluidOutputs); HeatCondition requiredHeat = recipe.getRequiredHeat(); if (!requiredHeat.testBlazeBurner(HeatLevel.NONE)) { - itemStacks.init(++i, true, 133, 80); + itemStacks.init(i, true, 133, 80); itemStacks.set(i, AllBlocks.BLAZE_BURNER.asStack()); + i++; } if (!requiredHeat.testBlazeBurner(HeatLevel.KINDLED)) { - itemStacks.init(++i, true, 152, 80); + itemStacks.init(i, true, 152, 80); itemStacks.set(i, AllItems.BLAZE_CAKE.asStack()); + i++; } } @@ -146,6 +151,8 @@ public class BasinCategory extends CreateRecipeCategory { int size = actualIngredients.size() + recipe.getFluidIngredients() .size(); + int outSize = recipe.getFluidResults().size() + recipe.getRollableResults().size(); + int xOffset = size < 3 ? (3 - size) * 19 / 2 : 0; HeatCondition requiredHeat = recipe.getRequiredHeat(); int yOffset = 0; @@ -154,8 +161,13 @@ public class BasinCategory extends CreateRecipeCategory { AllGuiTextures.JEI_SLOT.draw(matrixStack, 16 + xOffset + (i % 3) * 19, 50 - (i / 3) * 19 + yOffset); boolean noHeat = requiredHeat == HeatCondition.NONE; - AllGuiTextures.JEI_SLOT.draw(matrixStack, 141, 50 + yOffset); - AllGuiTextures.JEI_DOWN_ARROW.draw(matrixStack, 136, 32 + yOffset); + + int vRows = (1 + outSize) / 2; + for (int i = 0; i < outSize; i++) + AllGuiTextures.JEI_SLOT.draw(matrixStack, + 141 - (outSize % 2 != 0 && i == outSize - 1 ? 0 : i % 2 == 0 ? 10 : -9), -19 * (i / 2) + 50 + yOffset); + if (vRows <= 2) + AllGuiTextures.JEI_DOWN_ARROW.draw(matrixStack, 136, -19 * (vRows - 1) + 32 + yOffset); AllGuiTextures shadow = noHeat ? AllGuiTextures.JEI_SHADOW : AllGuiTextures.JEI_LIGHT; shadow.draw(matrixStack, 81, 58 + (noHeat ? 10 : 30)); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterMovementBehaviour.java index 87eee9790..5b144822e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterMovementBehaviour.java @@ -16,19 +16,20 @@ import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld; +import net.minecraft.block.AbstractPlantBlock; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.CocoaBlock; import net.minecraft.block.CropsBlock; -import net.minecraft.block.KelpBlock; -import net.minecraft.block.KelpTopBlock; import net.minecraft.block.SugarCaneBlock; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; import net.minecraft.state.IntegerProperty; import net.minecraft.state.Property; import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.tags.BlockTags; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; @@ -83,9 +84,17 @@ public class HarvesterMovementBehaviour extends MovementBehaviour { return; } + ItemStack item = ItemStack.EMPTY; + float effectChance = 1; + + if (stateVisited.getBlock().is(BlockTags.LEAVES)) { + item = new ItemStack(Items.SHEARS); + effectChance = .45f; + } + MutableBoolean seedSubtracted = new MutableBoolean(notCropButCuttable); BlockState state = stateVisited; - BlockHelper.destroyBlock(world, pos, 1, stack -> { + BlockHelper.destroyBlockAs(world, pos, null, item, effectChance, stack -> { if (!seedSubtracted.getValue() && stack.sameItem(new ItemStack(state.getBlock()))) { stack.shrink(1); seedSubtracted.setTrue(); @@ -127,12 +136,12 @@ public class HarvesterMovementBehaviour extends MovementBehaviour { return false; if (state.getBlock() instanceof SugarCaneBlock) return true; + if (state.getBlock().is(BlockTags.LEAVES)) + return true; if (state.getCollisionShape(world, pos) .isEmpty() || state.getBlock() instanceof CocoaBlock) { - if (state.getBlock() instanceof KelpBlock) - return true; - if (state.getBlock() instanceof KelpTopBlock) + if (state.getBlock() instanceof AbstractPlantBlock) return true; for (Property property : state.getProperties()) { @@ -160,7 +169,7 @@ public class HarvesterMovementBehaviour extends MovementBehaviour { if (block == Blocks.SWEET_BERRY_BUSH) { return state.setValue(BlockStateProperties.AGE_3, Integer.valueOf(1)); } - if (block == Blocks.SUGAR_CANE || block == Blocks.KELP) { + if (block == Blocks.SUGAR_CANE || block instanceof AbstractPlantBlock) { if (state.getFluidState() .isEmpty()) return Blocks.AIR.defaultBlockState(); From 31c951be65d38443016edade61a3a4d20d3bad9e Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Thu, 2 Sep 2021 23:08:03 +0200 Subject: [PATCH 4/6] Streamline Chromatics - Crafters no longer display item sprites vertically flipped - Crafters now arrange overlapping items less randomly - Chromatic Compound can now absorb light emitting blocks from belts & depots --- .../crafter/MechanicalCrafterRenderer.java | 54 +++++++++++------ .../curiosities/ChromaticCompoundItem.java | 60 +++++++++++++++++-- .../curiosities/RefinedRadianceItem.java | 2 +- 3 files changed, 91 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterRenderer.java index d589cd999..67e38873d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterRenderer.java @@ -17,6 +17,7 @@ import com.simibubi.create.foundation.render.SuperByteBuffer; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.Pointing; import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; @@ -43,14 +44,16 @@ public class MechanicalCrafterRenderer extends SafeTileEntityRenderer { + + ItemStack heldStack = ts.stack; + if (!(heldStack.getItem() instanceof BlockItem)) + return TransportedResult.doNothing(); + + BlockItem blockItem = (BlockItem) heldStack.getItem(); + if (blockItem.getBlock() == null) + return TransportedResult.doNothing(); + + BlockState stateToCheck = blockItem.getBlock() + .defaultBlockState(); + + if (!success.getValue() + && checkLight(stack, entity, world, itemData, positionVec, randomOffset, stateToCheck)) { + success.setTrue(); + if (ts.stack.getCount() == 1) + return TransportedResult.removeItem(); + TransportedItemStack left = ts.copy(); + left.stack.shrink(1); + return TransportedResult.convertTo(left); + } + + return TransportedResult.doNothing(); + + }); + return false; + } + + public boolean checkLight(ItemStack stack, ItemEntity entity, World world, CompoundNBT itemData, + Vector3d positionVec, BlockPos randomOffset, BlockState state) { if (state.getLightValue(world, randomOffset) == 0) return false; if (state.getDestroySpeed(world, randomOffset) == -1) @@ -166,14 +217,12 @@ public class ChromaticCompoundItem extends Item { if (state.getBlock() == Blocks.BEACON) return false; - RayTraceContext context = new RayTraceContext(positionVec, VecHelper.getCenterOf(randomOffset), - BlockMode.COLLIDER, FluidMode.NONE, entity); + RayTraceContext context = new RayTraceContext(positionVec.add(new Vector3d(0, 0.5, 0)), + VecHelper.getCenterOf(randomOffset), BlockMode.COLLIDER, FluidMode.NONE, entity); if (!randomOffset.equals(world.clip(context) .getBlockPos())) return false; - world.destroyBlock(randomOffset, false); - ItemStack newStack = stack.split(1); newStack.getOrCreateTag() .putInt("CollectingLight", itemData.getInt("CollectingLight") + 1); @@ -184,8 +233,7 @@ public class ChromaticCompoundItem extends Item { entity.lifespan = 6000; if (stack.isEmpty()) entity.remove(); - - return false; + return true; } } diff --git a/src/main/java/com/simibubi/create/content/curiosities/RefinedRadianceItem.java b/src/main/java/com/simibubi/create/content/curiosities/RefinedRadianceItem.java index 3cb9584e7..c6aab3c8c 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/RefinedRadianceItem.java +++ b/src/main/java/com/simibubi/create/content/curiosities/RefinedRadianceItem.java @@ -19,7 +19,7 @@ public class RefinedRadianceItem extends NoGravMagicalDohickyItem { protected void onCreated(ItemEntity entity, CompoundNBT persistentData) { super.onCreated(entity, persistentData); entity.setDeltaMovement(entity.getDeltaMovement() - .add(0, .15f, 0)); + .add(0, .25f, 0)); } } From b05506ad4694031ae208884d303851a71eddde47 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Thu, 2 Sep 2021 23:58:38 +0200 Subject: [PATCH 5/6] Mechanicalacinahcem - Added the option to prevent a Mechanical Crafting recipe from matching a vertically flipped arrangement --- src/generated/resources/.cache/cache | 10 ++-- .../mechanical_crafting/crushing_wheel.json | 3 +- .../mechanical_crafting/extendo_grip.json | 3 +- .../recipes/mechanical_crafting/flywheel.json | 3 +- .../mechanical_crafting/furnace_engine.json | 3 +- .../mechanical_crafting/potato_cannon.json | 3 +- .../crafter/MechanicalCraftingRecipe.java | 59 +++++++++++++++++-- .../MechanicalCraftingRecipeBuilder.java | 18 +++++- .../recipe/MechanicalCraftingRecipeGen.java | 6 +- 9 files changed, 88 insertions(+), 20 deletions(-) diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index b0bc41e77..3af0320b7 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -3377,11 +3377,11 @@ bbf64f7eb3868e354756e57348493e2b1ae6b0d9 data/create/recipes/limestone_cobblesto 88fa2b1ab746d5e13a8afd6e7e7d80ad843e0016 data/create/recipes/limestone_cobblestone_wall_from_limestone_cobblestone_stonecutting.json 327bb8a6535b60bb65d0dda9d5205e988bc82526 data/create/recipes/limestone_pillar.json c2e15ac0c9109bad3face6d13efc32d7116b4c25 data/create/recipes/limestone_pillar_from_limestone_stonecutting.json -88173753ceaf121c5430bbf928a40e3c046dbfe0 data/create/recipes/mechanical_crafting/crushing_wheel.json -14e322d4de8fae35d952274376497740bb3d5962 data/create/recipes/mechanical_crafting/extendo_grip.json -de7fea84434753873dfa2b929d9b5f5f86ac6a5c data/create/recipes/mechanical_crafting/flywheel.json -e491fd8a8873308270f9dc2a57ac8f2c70431dcc data/create/recipes/mechanical_crafting/furnace_engine.json -8e5224d22b228f69473ca48ca0d874b34660b573 data/create/recipes/mechanical_crafting/potato_cannon.json +66674d07de63aada0991d2fdff07e22e00450135 data/create/recipes/mechanical_crafting/crushing_wheel.json +599f8b87c24c131350ba7ceb69a0c8b9829c62bc data/create/recipes/mechanical_crafting/extendo_grip.json +f26ed47c10cc63613759b0f8ae4ef349000de60d data/create/recipes/mechanical_crafting/flywheel.json +2dc00d6e4c159e06ab2a705e666e83e4238a7814 data/create/recipes/mechanical_crafting/furnace_engine.json +b77911c169b6205a09001a09ca074eb2234f0d29 data/create/recipes/mechanical_crafting/potato_cannon.json 98f877bf8f3f8a686fc6cf7479a0fba5744248ce data/create/recipes/milling/allium.json 8c7e1cbc87c7ca7df2bf949957e89422fef8ad94 data/create/recipes/milling/aluminum_ore.json bcff4d30ae09a0729bce8b2dbde4ddd6719a998b data/create/recipes/milling/andesite.json diff --git a/src/generated/resources/data/create/recipes/mechanical_crafting/crushing_wheel.json b/src/generated/resources/data/create/recipes/mechanical_crafting/crushing_wheel.json index a8c1170ec..34ad9ea72 100644 --- a/src/generated/resources/data/create/recipes/mechanical_crafting/crushing_wheel.json +++ b/src/generated/resources/data/create/recipes/mechanical_crafting/crushing_wheel.json @@ -21,5 +21,6 @@ "result": { "item": "create:crushing_wheel", "count": 2 - } + }, + "acceptMirrored": false } \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/mechanical_crafting/extendo_grip.json b/src/generated/resources/data/create/recipes/mechanical_crafting/extendo_grip.json index c7fc84b1c..2d69859ee 100644 --- a/src/generated/resources/data/create/recipes/mechanical_crafting/extendo_grip.json +++ b/src/generated/resources/data/create/recipes/mechanical_crafting/extendo_grip.json @@ -23,5 +23,6 @@ }, "result": { "item": "create:extendo_grip" - } + }, + "acceptMirrored": false } \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/mechanical_crafting/flywheel.json b/src/generated/resources/data/create/recipes/mechanical_crafting/flywheel.json index 010b2fbae..dee9cffd7 100644 --- a/src/generated/resources/data/create/recipes/mechanical_crafting/flywheel.json +++ b/src/generated/resources/data/create/recipes/mechanical_crafting/flywheel.json @@ -15,5 +15,6 @@ }, "result": { "item": "create:flywheel" - } + }, + "acceptMirrored": true } \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/mechanical_crafting/furnace_engine.json b/src/generated/resources/data/create/recipes/mechanical_crafting/furnace_engine.json index 45765aebe..3842209f0 100644 --- a/src/generated/resources/data/create/recipes/mechanical_crafting/furnace_engine.json +++ b/src/generated/resources/data/create/recipes/mechanical_crafting/furnace_engine.json @@ -26,5 +26,6 @@ }, "result": { "item": "create:furnace_engine" - } + }, + "acceptMirrored": true } \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/mechanical_crafting/potato_cannon.json b/src/generated/resources/data/create/recipes/mechanical_crafting/potato_cannon.json index fffb05d24..a21d9bd04 100644 --- a/src/generated/resources/data/create/recipes/mechanical_crafting/potato_cannon.json +++ b/src/generated/resources/data/create/recipes/mechanical_crafting/potato_cannon.json @@ -20,5 +20,6 @@ }, "result": { "item": "create:potato_cannon" - } + }, + "acceptMirrored": true } \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCraftingRecipe.java b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCraftingRecipe.java index 2022cccf2..4eef6c570 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCraftingRecipe.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCraftingRecipe.java @@ -10,25 +10,58 @@ import net.minecraft.item.crafting.IRecipeType; import net.minecraft.item.crafting.Ingredient; import net.minecraft.item.crafting.ShapedRecipe; import net.minecraft.network.PacketBuffer; +import net.minecraft.util.JSONUtils; import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; public class MechanicalCraftingRecipe extends ShapedRecipe { + private boolean acceptMirrored; + public MechanicalCraftingRecipe(ResourceLocation idIn, String groupIn, int recipeWidthIn, int recipeHeightIn, - NonNullList recipeItemsIn, ItemStack recipeOutputIn) { + NonNullList recipeItemsIn, ItemStack recipeOutputIn, boolean acceptMirrored) { super(idIn, groupIn, recipeWidthIn, recipeHeightIn, recipeItemsIn, recipeOutputIn); + this.acceptMirrored = acceptMirrored; } - private static MechanicalCraftingRecipe fromShaped(ShapedRecipe recipe) { + private static MechanicalCraftingRecipe fromShaped(ShapedRecipe recipe, boolean acceptMirrored) { return new MechanicalCraftingRecipe(recipe.getId(), recipe.getGroup(), recipe.getWidth(), recipe.getHeight(), - recipe.getIngredients(), recipe.getResultItem()); + recipe.getIngredients(), recipe.getResultItem(), acceptMirrored); } @Override public boolean matches(CraftingInventory inv, World worldIn) { - return inv instanceof MechanicalCraftingInventory && super.matches(inv, worldIn); + if (!(inv instanceof MechanicalCraftingInventory)) + return false; + if (acceptsMirrored()) + return super.matches(inv, worldIn); + + // From ShapedRecipe except the symmetry + for (int i = 0; i <= inv.getWidth() - this.getWidth(); ++i) + for (int j = 0; j <= inv.getHeight() - this.getHeight(); ++j) + if (this.matchesSpecific(inv, i, j)) + return true; + return false; + } + + // From ShapedRecipe + private boolean matchesSpecific(CraftingInventory inv, int p_77573_2_, int p_77573_3_) { + NonNullList ingredients = getIngredients(); + int width = getWidth(); + int height = getHeight(); + for (int i = 0; i < inv.getWidth(); ++i) { + for (int j = 0; j < inv.getHeight(); ++j) { + int k = i - p_77573_2_; + int l = j - p_77573_3_; + Ingredient ingredient = Ingredient.EMPTY; + if (k >= 0 && l >= 0 && k < width && l < height) + ingredient = ingredients.get(k + l * width); + if (!ingredient.test(inv.getItem(i + j * inv.getWidth()))) + return false; + } + } + return true; } @Override @@ -46,16 +79,30 @@ public class MechanicalCraftingRecipe extends ShapedRecipe { return AllRecipeTypes.MECHANICAL_CRAFTING.getSerializer(); } + public boolean acceptsMirrored() { + return acceptMirrored; + } + public static class Serializer extends ShapedRecipe.Serializer { @Override public ShapedRecipe fromJson(ResourceLocation recipeId, JsonObject json) { - return fromShaped(super.fromJson(recipeId, json)); + return fromShaped(super.fromJson(recipeId, json), JSONUtils.getAsBoolean(json, "acceptMirrored", true)); } @Override public ShapedRecipe fromNetwork(ResourceLocation recipeId, PacketBuffer buffer) { - return fromShaped(super.fromNetwork(recipeId, buffer)); + return fromShaped(super.fromNetwork(recipeId, buffer), buffer.readBoolean() && buffer.readBoolean()); + } + + @Override + public void toNetwork(PacketBuffer p_199427_1_, ShapedRecipe p_199427_2_) { + super.toNetwork(p_199427_1_, p_199427_2_); + if (p_199427_2_ instanceof MechanicalCraftingRecipe) { + p_199427_1_.writeBoolean(true); + p_199427_1_.writeBoolean(((MechanicalCraftingRecipe) p_199427_2_).acceptsMirrored()); + } else + p_199427_1_.writeBoolean(false); } } diff --git a/src/main/java/com/simibubi/create/foundation/data/recipe/MechanicalCraftingRecipeBuilder.java b/src/main/java/com/simibubi/create/foundation/data/recipe/MechanicalCraftingRecipeBuilder.java index 3f806faf7..2b75c2f4a 100644 --- a/src/main/java/com/simibubi/create/foundation/data/recipe/MechanicalCraftingRecipeBuilder.java +++ b/src/main/java/com/simibubi/create/foundation/data/recipe/MechanicalCraftingRecipeBuilder.java @@ -30,10 +30,12 @@ public class MechanicalCraftingRecipeBuilder { private final int count; private final List pattern = Lists.newArrayList(); private final Map key = Maps.newLinkedHashMap(); + private boolean acceptMirrored; public MechanicalCraftingRecipeBuilder(IItemProvider p_i48261_1_, int p_i48261_2_) { result = p_i48261_1_.asItem(); count = p_i48261_2_; + acceptMirrored = true; } /** @@ -91,6 +93,14 @@ public class MechanicalCraftingRecipeBuilder { } } + /** + * Prevents the crafters from matching a vertically flipped version of the recipe + */ + public MechanicalCraftingRecipeBuilder disallowMirrored() { + acceptMirrored = false; + return this; + } + /** * Builds this recipe into an {@link IFinishedRecipe}. */ @@ -116,7 +126,8 @@ public class MechanicalCraftingRecipeBuilder { */ public void build(Consumer p_200467_1_, ResourceLocation p_200467_2_) { validate(p_200467_2_); - p_200467_1_.accept(new MechanicalCraftingRecipeBuilder.Result(p_200467_2_, result, count, pattern, key)); + p_200467_1_ + .accept(new MechanicalCraftingRecipeBuilder.Result(p_200467_2_, result, count, pattern, key, acceptMirrored)); } /** @@ -151,14 +162,16 @@ public class MechanicalCraftingRecipeBuilder { private final int count; private final List pattern; private final Map key; + private final boolean acceptMirrored; public Result(ResourceLocation p_i48271_2_, Item p_i48271_3_, int p_i48271_4_, List p_i48271_6_, - Map p_i48271_7_) { + Map p_i48271_7_, boolean asymmetrical) { this.id = p_i48271_2_; this.result = p_i48271_3_; this.count = p_i48271_4_; this.pattern = p_i48271_6_; this.key = p_i48271_7_; + this.acceptMirrored = asymmetrical; } public void serializeRecipeData(JsonObject p_218610_1_) { @@ -180,6 +193,7 @@ public class MechanicalCraftingRecipeBuilder { jsonobject1.addProperty("count", this.count); p_218610_1_.add("result", jsonobject1); + p_218610_1_.addProperty("acceptMirrored", acceptMirrored); } public IRecipeSerializer getType() { diff --git a/src/main/java/com/simibubi/create/foundation/data/recipe/MechanicalCraftingRecipeGen.java b/src/main/java/com/simibubi/create/foundation/data/recipe/MechanicalCraftingRecipeGen.java index d4e5c5eb5..b15d1ac64 100644 --- a/src/main/java/com/simibubi/create/foundation/data/recipe/MechanicalCraftingRecipeGen.java +++ b/src/main/java/com/simibubi/create/foundation/data/recipe/MechanicalCraftingRecipeGen.java @@ -27,7 +27,8 @@ public class MechanicalCraftingRecipeGen extends CreateRecipeProvider { .patternLine("AAPAA") .patternLine("APSPA") .patternLine("AAPAA") - .patternLine(" AAA ")), + .patternLine(" AAA ") + .disallowMirrored()), EXTENDO_GRIP = create(AllItems.EXTENDO_GRIP::get).returns(1) .recipe(b -> b.key('L', Ingredient.of(I.brass())) @@ -38,7 +39,8 @@ public class MechanicalCraftingRecipeGen extends CreateRecipeProvider { .patternLine(" R ") .patternLine("SSS") .patternLine("SSS") - .patternLine(" H ")), + .patternLine(" H ") + .disallowMirrored()), POTATO_CANNON = create(AllItems.POTATO_CANNON::get).returns(1) .recipe(b -> b.key('L', I.andesite()) From aa3d656445680f007895a84977333b3c48a89446 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Fri, 3 Sep 2021 05:12:44 +0200 Subject: [PATCH 6/6] Hot belt replace - The Wrench can now be used to shorten or divide Mechanical Belts - Belt Connectors can now be used to extend or merge Mechanical Belts --- .../contraptions/relays/belt/BeltBlock.java | 57 +-- .../contraptions/relays/belt/BeltHelper.java | 16 +- .../relays/belt/BeltRenderer.java | 4 +- .../contraptions/relays/belt/BeltSlicer.java | 472 ++++++++++++++++++ .../relays/belt/BeltTileEntity.java | 15 +- .../relays/belt/item/BeltConnectorItem.java | 14 +- .../simibubi/create/events/ClientEvents.java | 2 + 7 files changed, 532 insertions(+), 48 deletions(-) create mode 100644 src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltSlicer.java diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltBlock.java index d72e079f6..45a30857e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltBlock.java @@ -13,6 +13,7 @@ import com.simibubi.create.Create; import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.processing.EmptyingByBasin; +import com.simibubi.create.content.contraptions.relays.belt.BeltSlicer.Feedback; import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity.CasingType; import com.simibubi.create.content.contraptions.relays.belt.transport.BeltMovementHandler.TransportedEntityInfo; import com.simibubi.create.content.contraptions.relays.belt.transport.BeltTunnelInteractionHandler; @@ -96,7 +97,8 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE getDrops(BlockState state, net.minecraft.loot.LootContext.Builder builder) { @@ -241,6 +234,9 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE { protected int getPackedLight(BeltTileEntity controller, float beltPos) { int segment = (int) Math.floor(beltPos) * 2; - - if (controller.light == null || segment >= controller.light.length) return 0; + if (controller.light == null || segment >= controller.light.length || segment < 0) + return 0; return (controller.light[segment + 1] << 20) | (controller.light[segment] << 4); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltSlicer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltSlicer.java new file mode 100644 index 000000000..40d842bad --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltSlicer.java @@ -0,0 +1,472 @@ +package com.simibubi.create.content.contraptions.relays.belt; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; +import com.simibubi.create.CreateClient; +import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity.CasingType; +import com.simibubi.create.content.contraptions.relays.belt.item.BeltConnectorItem; +import com.simibubi.create.content.contraptions.relays.belt.transport.BeltInventory; +import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; +import com.simibubi.create.foundation.utility.Lang; +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.client.Minecraft; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.DyeColor; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.Hand; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.SoundEvents; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.util.Constants.BlockFlags; + +public class BeltSlicer { + + public static class Feedback { + int color = 0xffffff; + AxisAlignedBB bb; + String langKey; + TextFormatting formatting = TextFormatting.WHITE; + } + + public static ActionResultType useWrench(BlockState state, World world, BlockPos pos, PlayerEntity player, + Hand handIn, BlockRayTraceResult hit, Feedback feedBack) { + BeltTileEntity controllerTE = BeltHelper.getControllerTE(world, pos); + if (controllerTE == null) + return ActionResultType.PASS; + if (state.getValue(BeltBlock.CASING) && hit.getDirection() != Direction.UP) + return ActionResultType.PASS; + if (state.getValue(BeltBlock.PART) == BeltPart.PULLEY && hit.getDirection() + .getAxis() != Axis.Y) + return ActionResultType.PASS; + + int beltLength = controllerTE.beltLength; + if (beltLength == 2) + return ActionResultType.FAIL; + + BlockPos beltVector = new BlockPos(BeltHelper.getBeltVector(state)); + BeltPart part = state.getValue(BeltBlock.PART); + List beltChain = BeltBlock.getBeltChain(world, controllerTE.getBlockPos()); + boolean creative = player.isCreative(); + + // Shorten from End + if (hoveringEnd(state, hit)) { + if (world.isClientSide) + return ActionResultType.SUCCESS; + + for (BlockPos blockPos : beltChain) { + BeltTileEntity belt = BeltHelper.getSegmentTE(world, blockPos); + if (belt == null) + continue; + belt.detachKinetics(); + belt.invalidateItemHandler(); + belt.beltLength = 0; + } + + BeltInventory inventory = controllerTE.inventory; + BlockPos next = part == BeltPart.END ? pos.subtract(beltVector) : pos.offset(beltVector); + BlockState replacedState = world.getBlockState(next); + BeltTileEntity segmentTE = BeltHelper.getSegmentTE(world, next); + KineticTileEntity.switchToBlockState(world, next, + state.setValue(BeltBlock.CASING, segmentTE != null && segmentTE.casing != CasingType.NONE)); + world.setBlock(pos, Blocks.AIR.defaultBlockState(), 3 | BlockFlags.IS_MOVING); + world.removeBlockEntity(pos); + world.levelEvent(2001, pos, Block.getId(state)); + + if (!creative && AllBlocks.BELT.has(replacedState) + && replacedState.getValue(BeltBlock.PART) == BeltPart.PULLEY) + player.inventory.placeItemBackInInventory(world, AllBlocks.SHAFT.asStack()); + + // Eject overshooting items + if (part == BeltPart.END && inventory != null) { + List toEject = new ArrayList<>(); + for (TransportedItemStack transportedItemStack : inventory.getTransportedItems()) + if (transportedItemStack.beltPosition > beltLength - 1) + toEject.add(transportedItemStack); + toEject.forEach(inventory::eject); + toEject.forEach(inventory.getTransportedItems()::remove); + } + + // Transfer items to new controller + if (part == BeltPart.START && segmentTE != null && inventory != null) { + controllerTE.inventory = null; + segmentTE.inventory = null; + segmentTE.setController(next); + for (TransportedItemStack transportedItemStack : inventory.getTransportedItems()) { + transportedItemStack.beltPosition -= 1; + if (transportedItemStack.beltPosition <= 0) { + ItemEntity entity = new ItemEntity(world, pos.getX() + .5f, pos.getY() + 11 / 16f, + pos.getZ() + .5f, transportedItemStack.stack); + entity.setDeltaMovement(Vector3d.ZERO); + entity.setDefaultPickUpDelay(); + entity.hurtMarked = true; + world.addFreshEntity(entity); + } else + segmentTE.getInventory() + .addItem(transportedItemStack); + } + } + + return ActionResultType.SUCCESS; + } + + BeltTileEntity segmentTE = BeltHelper.getSegmentTE(world, pos); + if (segmentTE == null) + return ActionResultType.PASS; + + // Split in half + int hitSegment = segmentTE.index; + Vector3d centerOf = VecHelper.getCenterOf(hit.getBlockPos()); + Vector3d subtract = hit.getLocation() + .subtract(centerOf); + boolean towardPositive = subtract.dot(Vector3d.atLowerCornerOf(beltVector)) > 0; + BlockPos next = !towardPositive ? pos.subtract(beltVector) : pos.offset(beltVector); + + if (hitSegment == 0 || hitSegment == 1 && !towardPositive) + return ActionResultType.FAIL; + if (hitSegment == controllerTE.beltLength - 1 || hitSegment == controllerTE.beltLength - 2 && towardPositive) + return ActionResultType.FAIL; + + // Look for shafts + if (!creative) { + int requiredShafts = 0; + if (!segmentTE.hasPulley()) + requiredShafts++; + BlockState other = world.getBlockState(next); + if (AllBlocks.BELT.has(other) && other.getValue(BeltBlock.PART) == BeltPart.MIDDLE) + requiredShafts++; + + int amountRetrieved = 0; + Search: while (true) { + for (int i = 0; i < player.inventory.getContainerSize(); ++i) { + if (amountRetrieved == requiredShafts) + break Search; + + ItemStack itemstack = player.inventory.getItem(i); + if (itemstack.isEmpty()) + continue; + int count = itemstack.getCount(); + if (AllBlocks.SHAFT.isIn(itemstack)) { + int taken = Math.min(count, requiredShafts - amountRetrieved); + if (taken == count) + player.inventory.setItem(i, ItemStack.EMPTY); + else + itemstack.shrink(taken); + amountRetrieved += taken; + } + } + + player.inventory.placeItemBackInInventory(world, AllBlocks.SHAFT.asStack(amountRetrieved)); + return ActionResultType.FAIL; + } + } + + if (!world.isClientSide) { + for (BlockPos blockPos : beltChain) { + BeltTileEntity belt = BeltHelper.getSegmentTE(world, blockPos); + if (belt == null) + continue; + belt.detachKinetics(); + belt.invalidateItemHandler(); + belt.beltLength = 0; + } + + BeltInventory inventory = controllerTE.inventory; + KineticTileEntity.switchToBlockState(world, pos, + state.setValue(BeltBlock.PART, towardPositive ? BeltPart.END : BeltPart.START)); + KineticTileEntity.switchToBlockState(world, next, world.getBlockState(next) + .setValue(BeltBlock.PART, towardPositive ? BeltPart.START : BeltPart.END)); + world.playSound(null, pos, SoundEvents.WOOL_HIT, + player == null ? SoundCategory.BLOCKS : SoundCategory.PLAYERS, 0.5F, 2.3F); + + // Transfer items to new controller + BeltTileEntity newController = towardPositive ? BeltHelper.getSegmentTE(world, next) : segmentTE; + if (newController != null && inventory != null) { + newController.inventory = null; + newController.setController(newController.getBlockPos()); + for (Iterator iterator = inventory.getTransportedItems() + .iterator(); iterator.hasNext();) { + TransportedItemStack transportedItemStack = iterator.next(); + float newPosition = transportedItemStack.beltPosition - hitSegment - (towardPositive ? 1 : 0); + if (newPosition <= 0) + continue; + transportedItemStack.beltPosition = newPosition; + iterator.remove(); + newController.getInventory() + .addItem(transportedItemStack); + } + } + } + + return ActionResultType.SUCCESS; + } + + public static ActionResultType useConnector(BlockState state, World world, BlockPos pos, PlayerEntity player, + Hand handIn, BlockRayTraceResult hit, Feedback feedBack) { + BeltTileEntity controllerTE = BeltHelper.getControllerTE(world, pos); + if (controllerTE == null) + return ActionResultType.PASS; + + int beltLength = controllerTE.beltLength; + if (beltLength == BeltConnectorItem.maxLength()) + return ActionResultType.FAIL; + + BlockPos beltVector = new BlockPos(BeltHelper.getBeltVector(state)); + BeltPart part = state.getValue(BeltBlock.PART); + Direction facing = state.getValue(BeltBlock.HORIZONTAL_FACING); + List beltChain = BeltBlock.getBeltChain(world, controllerTE.getBlockPos()); + boolean creative = player.isCreative(); + + if (!hoveringEnd(state, hit)) + return ActionResultType.PASS; + + BlockPos next = part == BeltPart.START ? pos.subtract(beltVector) : pos.offset(beltVector); + BeltTileEntity mergedController = null; + int mergedBeltLength = 0; + + // Merge Belts / Extend at End + BlockState nextState = world.getBlockState(next); + if (!nextState.getMaterial() + .isReplaceable()) { + if (!AllBlocks.BELT.has(nextState)) + return ActionResultType.FAIL; + if (!beltStatesCompatible(state, nextState)) + return ActionResultType.FAIL; + + mergedController = BeltHelper.getControllerTE(world, next); + if (mergedController == null) + return ActionResultType.FAIL; + if (mergedController.beltLength + beltLength > BeltConnectorItem.maxLength()) + return ActionResultType.FAIL; + + mergedBeltLength = mergedController.beltLength; + + if (!world.isClientSide) { + boolean flipBelt = facing != nextState.getValue(BeltBlock.HORIZONTAL_FACING); + Optional color = controllerTE.color; + for (BlockPos blockPos : BeltBlock.getBeltChain(world, mergedController.getBlockPos())) { + BeltTileEntity belt = BeltHelper.getSegmentTE(world, blockPos); + if (belt == null) + continue; + belt.detachKinetics(); + belt.invalidateItemHandler(); + belt.beltLength = 0; + belt.color = color; + if (flipBelt) + world.setBlock(blockPos, flipBelt(world.getBlockState(blockPos)), 3 | BlockFlags.IS_MOVING); + } + + // Reverse items + if (flipBelt && mergedController.inventory != null) { + List transportedItems = mergedController.inventory.getTransportedItems(); + for (TransportedItemStack transportedItemStack : transportedItems) { + transportedItemStack.beltPosition = mergedBeltLength - transportedItemStack.beltPosition; + transportedItemStack.prevBeltPosition = + mergedBeltLength - transportedItemStack.prevBeltPosition; + } + } + } + } + + if (!world.isClientSide) { + for (BlockPos blockPos : beltChain) { + BeltTileEntity belt = BeltHelper.getSegmentTE(world, blockPos); + if (belt == null) + continue; + belt.detachKinetics(); + belt.invalidateItemHandler(); + belt.beltLength = 0; + } + + BeltInventory inventory = controllerTE.inventory; + KineticTileEntity.switchToBlockState(world, pos, state.setValue(BeltBlock.PART, BeltPart.MIDDLE)); + + if (mergedController == null) { + // Attach at end + world.setBlock(next, state.setValue(BeltBlock.CASING, false), 3 | BlockFlags.IS_MOVING); + BeltTileEntity segmentTE = BeltHelper.getSegmentTE(world, next); + if (segmentTE != null) + segmentTE.color = controllerTE.color; + world.playSound(null, pos, SoundEvents.WOOL_PLACE, + player == null ? SoundCategory.BLOCKS : SoundCategory.PLAYERS, 0.5F, 1F); + + // Transfer items to new controller + if (part == BeltPart.START && segmentTE != null && inventory != null) { + segmentTE.setController(next); + for (TransportedItemStack transportedItemStack : inventory.getTransportedItems()) { + transportedItemStack.beltPosition += 1; + segmentTE.getInventory() + .addItem(transportedItemStack); + } + } + + } else { + // Merge with other + BeltInventory mergedInventory = mergedController.inventory; + world.playSound(null, pos, SoundEvents.WOOL_HIT, + player == null ? SoundCategory.BLOCKS : SoundCategory.PLAYERS, 0.5F, 1.3F); + BeltTileEntity segmentTE = BeltHelper.getSegmentTE(world, next); + KineticTileEntity.switchToBlockState(world, next, + state.setValue(BeltBlock.CASING, segmentTE != null && segmentTE.casing != CasingType.NONE) + .setValue(BeltBlock.PART, BeltPart.MIDDLE)); + + if (!creative) + player.inventory.placeItemBackInInventory(world, AllBlocks.SHAFT.asStack(2)); + + // Transfer items to other controller + BlockPos search = controllerTE.getBlockPos(); + for (int i = 0; i < 10000; i++) { + BlockState blockState = world.getBlockState(search); + if (!AllBlocks.BELT.has(blockState)) + break; + if (blockState.getValue(BeltBlock.PART) != BeltPart.START) { + search = search.subtract(beltVector); + continue; + } + + BeltTileEntity newController = BeltHelper.getSegmentTE(world, search); + + if (newController != controllerTE && inventory != null) { + newController.setController(search); + controllerTE.inventory = null; + for (TransportedItemStack transportedItemStack : inventory.getTransportedItems()) { + transportedItemStack.beltPosition += mergedBeltLength; + newController.getInventory() + .addItem(transportedItemStack); + } + } + + if (newController != mergedController && mergedInventory != null) { + newController.setController(search); + mergedController.inventory = null; + for (TransportedItemStack transportedItemStack : mergedInventory.getTransportedItems()) { + if (newController == controllerTE) + transportedItemStack.beltPosition += beltLength; + newController.getInventory() + .addItem(transportedItemStack); + } + } + + break; + } + } + } + return ActionResultType.SUCCESS; + } + + static boolean beltStatesCompatible(BlockState state, BlockState nextState) { + Direction facing1 = state.getValue(BeltBlock.HORIZONTAL_FACING); + BeltSlope slope1 = state.getValue(BeltBlock.SLOPE); + Direction facing2 = nextState.getValue(BeltBlock.HORIZONTAL_FACING); + BeltSlope slope2 = nextState.getValue(BeltBlock.SLOPE); + + switch (slope1) { + case UPWARD: + if (slope2 == BeltSlope.DOWNWARD) + return facing1 == facing2.getOpposite(); + return slope2 == slope1 && facing1 == facing2; + case DOWNWARD: + if (slope2 == BeltSlope.UPWARD) + return facing1 == facing2.getOpposite(); + return slope2 == slope1 && facing1 == facing2; + default: + return slope2 == slope1 && facing2.getAxis() == facing1.getAxis(); + } + } + + static BlockState flipBelt(BlockState state) { + Direction facing = state.getValue(BeltBlock.HORIZONTAL_FACING); + BeltSlope slope = state.getValue(BeltBlock.SLOPE); + BeltPart part = state.getValue(BeltBlock.PART); + + if (slope == BeltSlope.UPWARD) + state = state.setValue(BeltBlock.SLOPE, BeltSlope.DOWNWARD); + else if (slope == BeltSlope.DOWNWARD) + state = state.setValue(BeltBlock.SLOPE, BeltSlope.UPWARD); + + if (part == BeltPart.END) + state = state.setValue(BeltBlock.PART, BeltPart.START); + else if (part == BeltPart.START) + state = state.setValue(BeltBlock.PART, BeltPart.END); + + return state.setValue(BeltBlock.HORIZONTAL_FACING, facing.getOpposite()); + } + + static boolean hoveringEnd(BlockState state, BlockRayTraceResult hit) { + BeltPart part = state.getValue(BeltBlock.PART); + if (part == BeltPart.MIDDLE || part == BeltPart.PULLEY) + return false; + + Vector3d beltVector = BeltHelper.getBeltVector(state); + Vector3d centerOf = VecHelper.getCenterOf(hit.getBlockPos()); + Vector3d subtract = hit.getLocation() + .subtract(centerOf); + + return subtract.dot(beltVector) > 0 == (part == BeltPart.END); + } + + @OnlyIn(Dist.CLIENT) + public static void tickHoveringInformation() { + Minecraft mc = Minecraft.getInstance(); + RayTraceResult target = mc.hitResult; + if (target == null || !(target instanceof BlockRayTraceResult)) + return; + + BlockRayTraceResult result = (BlockRayTraceResult) target; + ClientWorld world = mc.level; + BlockPos pos = result.getBlockPos(); + BlockState state = world.getBlockState(pos); + ItemStack held = mc.player.getItemInHand(Hand.MAIN_HAND); + ItemStack heldOffHand = mc.player.getItemInHand(Hand.OFF_HAND); + + if (mc.player.isShiftKeyDown()) + return; + if (!AllBlocks.BELT.has(state)) + return; + + Feedback feedback = new Feedback(); + + // TODO: Populate feedback in the methods for clientside + if (AllItems.WRENCH.isIn(held) || AllItems.WRENCH.isIn(heldOffHand)) + useWrench(state, world, pos, mc.player, Hand.MAIN_HAND, result, feedback); + else if (AllItems.BELT_CONNECTOR.isIn(held) || AllItems.BELT_CONNECTOR.isIn(heldOffHand)) + useConnector(state, world, pos, mc.player, Hand.MAIN_HAND, result, feedback); + else + return; + + if (feedback.langKey != null) + mc.player.displayClientMessage(Lang.translate(feedback.langKey) + .withStyle(feedback.formatting), true); + else + mc.player.displayClientMessage(new StringTextComponent(""), true); + + if (feedback.bb != null) + CreateClient.OUTLINER.chaseAABB("BeltSlicer", feedback.bb) + .lineWidth(1 / 16f) + .colored(feedback.color); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java index 30ac4da87..a9a3d4c98 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java @@ -223,8 +223,15 @@ public class BeltTileEntity extends KineticTileEntity implements ILightUpdateLis if (!isController()) controller = NBTUtil.readBlockPos(compound.getCompound("Controller")); trackerUpdateTag = compound; - beltLength = compound.getInt("Length"); index = compound.getInt("Index"); + int length = compound.getInt("Length"); + if (beltLength != length) { + beltLength = length; + if (level != null) + initializeLight(); + else + light = null; + } } if (isController()) @@ -516,6 +523,10 @@ public class BeltTileEntity extends KineticTileEntity implements ILightUpdateLis return getController().equals(((BeltTileEntity) target).getController()) ? 1 : 0; return 0; } + + public void invalidateItemHandler() { + itemHandler.invalidate(); + } @Override public boolean shouldRenderNormally() { @@ -524,7 +535,7 @@ public class BeltTileEntity extends KineticTileEntity implements ILightUpdateLis BlockState state = getBlockState(); return state != null && state.hasProperty(BeltBlock.PART) && state.getValue(BeltBlock.PART) == BeltPart.START; } - + @Override public boolean onLightUpdate(IBlockDisplayReader world, LightType type, GridAlignedBB changed) { if (this.remove) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/item/BeltConnectorItem.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/item/BeltConnectorItem.java index e9f63918c..45507b9fd 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/item/BeltConnectorItem.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/item/BeltConnectorItem.java @@ -15,6 +15,7 @@ import com.simibubi.create.content.contraptions.relays.elementary.AbstractShaftB import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; @@ -31,6 +32,8 @@ import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.AxisDirection; import net.minecraft.util.NonNullList; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.SoundEvents; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -118,6 +121,8 @@ public class BeltConnectorItem extends BlockItem { } public static void createBelts(World world, BlockPos start, BlockPos end) { + world.playSound(null, new BlockPos(VecHelper.getCenterOf(start.offset(end)) + .scale(.5f)), SoundEvents.WOOL_PLACE, SoundCategory.BLOCKS, 0.5F, 1F); BeltSlope slope = getSlopeBetween(start, end); Direction facing = getFacingFromTo(start, end); @@ -152,8 +157,8 @@ public class BeltConnectorItem extends BlockItem { if (diff.getX() == 0 && diff.getZ() == 0) axisDirection = diff.getY() > 0 ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE; else - axisDirection = beltAxis.choose(diff.getX(), 0, diff.getZ()) > 0 ? AxisDirection.POSITIVE - : AxisDirection.NEGATIVE; + axisDirection = + beltAxis.choose(diff.getX(), 0, diff.getZ()) > 0 ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE; return Direction.get(axisDirection, beltAxis); } @@ -169,7 +174,8 @@ public class BeltConnectorItem extends BlockItem { return BeltSlope.HORIZONTAL; } - private static List getBeltChainBetween(BlockPos start, BlockPos end, BeltSlope slope, Direction direction) { + private static List getBeltChainBetween(BlockPos start, BlockPos end, BeltSlope slope, + Direction direction) { List positions = new LinkedList<>(); int limit = 1000; BlockPos current = start; @@ -249,7 +255,7 @@ public class BeltConnectorItem extends BlockItem { } - protected static Integer maxLength() { + public static Integer maxLength() { return AllConfigs.SERVER.kinetics.maxBeltLength.get(); } diff --git a/src/main/java/com/simibubi/create/events/ClientEvents.java b/src/main/java/com/simibubi/create/events/ClientEvents.java index 8e666c35b..c25d99b98 100644 --- a/src/main/java/com/simibubi/create/events/ClientEvents.java +++ b/src/main/java/com/simibubi/create/events/ClientEvents.java @@ -24,6 +24,7 @@ import com.simibubi.create.content.contraptions.components.turntable.TurntableHa import com.simibubi.create.content.contraptions.goggles.GoggleOverlayRenderer; import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; import com.simibubi.create.content.contraptions.itemAssembly.SequencedAssemblyRecipe; +import com.simibubi.create.content.contraptions.relays.belt.BeltSlicer; import com.simibubi.create.content.contraptions.relays.belt.item.BeltConnectorHandler; import com.simibubi.create.content.curiosities.armor.CopperBacktankArmorLayer; import com.simibubi.create.content.curiosities.tools.BlueprintOverlayRenderer; @@ -125,6 +126,7 @@ public class ClientEvents { // ScreenOpener.tick(); ServerSpeedProvider.clientTick(); BeltConnectorHandler.tick(); + BeltSlicer.tickHoveringInformation(); FilteringRenderer.tick(); LinkRenderer.tick(); ScrollValueRenderer.tick();