Crafter connectivity

- Ported input connection handler of mechanical crafters
- Added new TE behaviour for interacting with faces/edges between two blocks
This commit is contained in:
simibubi 2020-05-24 15:58:25 +02:00
parent 4e9cd1db49
commit 67f88e666c
21 changed files with 365 additions and 222 deletions

View file

@ -274,7 +274,7 @@ e8b0a401c10d1ba67ed71ba31bd5f9bc28571b65 assets\create\blockstates\powered_toggl
c29213b77ac0c78d8979c5f6188d2b265696f9b9 assets\create\blockstates\redstone_link.json c29213b77ac0c78d8979c5f6188d2b265696f9b9 assets\create\blockstates\redstone_link.json
e2990fe70ad5d10437a376e70e167d1856277cc1 assets\create\blockstates\rope.json e2990fe70ad5d10437a376e70e167d1856277cc1 assets\create\blockstates\rope.json
e14d5f7252105934295b4e156ec0e6d62d3d6b1c assets\create\blockstates\rope_pulley.json e14d5f7252105934295b4e156ec0e6d62d3d6b1c assets\create\blockstates\rope_pulley.json
e069278f8fb93cd4bb6afab3848e6f1560a04303 assets\create\blockstates\rotation_chassis.json d42b4ead9307a83e2a106cfa440572575e8664b2 assets\create\blockstates\rotation_chassis.json
cc4cf3420fa290cb844f9cf4dfdd836aa9b70500 assets\create\blockstates\rotation_speed_controller.json cc4cf3420fa290cb844f9cf4dfdd836aa9b70500 assets\create\blockstates\rotation_speed_controller.json
56b63575c87065bc82eb9410175c501cdf959c66 assets\create\blockstates\saw.json 56b63575c87065bc82eb9410175c501cdf959c66 assets\create\blockstates\saw.json
36592a6542332b35445931e8e9531adf786b63ba assets\create\blockstates\schematicannon.json 36592a6542332b35445931e8e9531adf786b63ba assets\create\blockstates\schematicannon.json
@ -324,7 +324,7 @@ c60c3115fd6eeaa3a696428a87a74d184ab7d62d assets\create\blockstates\weathered_lim
7f39521b211441f5c3e06d60c5978cebe16cacfb assets\create\blockstates\zinc_block.json 7f39521b211441f5c3e06d60c5978cebe16cacfb assets\create\blockstates\zinc_block.json
b7181bcd8182b2f17088e5aa881f374c9c65470c assets\create\blockstates\zinc_ore.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets\create\blockstates\zinc_ore.json
efa942851f247891194d2c6ecdd8724a23b05aa0 assets\create\lang\en_ud.json efa942851f247891194d2c6ecdd8724a23b05aa0 assets\create\lang\en_ud.json
fe4c49a84016a3861a86e116df2c7603d6d4b91f assets\create\lang\en_us.json adb6af4aa68bac360242e78b9f883d94059b1df8 assets\create\lang\en_us.json
846200eb548d3bfa2e77b41039de159b4b6cfb45 assets\create\models\block\acacia_window.json 846200eb548d3bfa2e77b41039de159b4b6cfb45 assets\create\models\block\acacia_window.json
1930fa3a3c98d53dd19e4ee7f55bc27fd47aa281 assets\create\models\block\acacia_window_pane_noside.json 1930fa3a3c98d53dd19e4ee7f55bc27fd47aa281 assets\create\models\block\acacia_window_pane_noside.json
1763ea2c9b981d187f5031ba608f3d5d3be3986a assets\create\models\block\acacia_window_pane_noside_alt.json 1763ea2c9b981d187f5031ba608f3d5d3be3986a assets\create\models\block\acacia_window_pane_noside_alt.json
@ -1369,7 +1369,7 @@ e4d0fe35d3441a5815bd4e1357329b284e63ecd8 data\create\loot_tables\blocks\fancy_we
f37526c092c645045c22674dea6c7b1ec503c9c3 data\create\loot_tables\blocks\flywheel.json f37526c092c645045c22674dea6c7b1ec503c9c3 data\create\loot_tables\blocks\flywheel.json
8fbd865f350c615031ec3f56eb98b51ce3008de3 data\create\loot_tables\blocks\framed_glass.json 8fbd865f350c615031ec3f56eb98b51ce3008de3 data\create\loot_tables\blocks\framed_glass.json
44c8bc7271fa367ff052bef242e1ae26fb435175 data\create\loot_tables\blocks\framed_glass_pane.json 44c8bc7271fa367ff052bef242e1ae26fb435175 data\create\loot_tables\blocks\framed_glass_pane.json
205f5899101262f31f5c1a88bb7d954918d08d04 data\create\loot_tables\blocks\funnel.json ed895ef7dcb97ad9b00d80a4fa9c331229dd532e data\create\loot_tables\blocks\funnel.json
4063880eda871fe63a4eb549a19daecabce849e5 data\create\loot_tables\blocks\furnace_engine.json 4063880eda871fe63a4eb549a19daecabce849e5 data\create\loot_tables\blocks\furnace_engine.json
1070cba1c0f46cf7ebe31089f35333f5eadda6e4 data\create\loot_tables\blocks\gabbro.json 1070cba1c0f46cf7ebe31089f35333f5eadda6e4 data\create\loot_tables\blocks\gabbro.json
0356e003d8890d31b89d0ad98e32aae892da71f9 data\create\loot_tables\blocks\gabbro_bricks.json 0356e003d8890d31b89d0ad98e32aae892da71f9 data\create\loot_tables\blocks\gabbro_bricks.json
@ -1419,8 +1419,8 @@ cb315814960850b5080598b89ee94c833b5048f7 data\create\loot_tables\blocks\limeston
8db1e3f0dac48b91a4839206a7d5a88cef415fdc data\create\loot_tables\blocks\limestone_cobblestone_stairs.json 8db1e3f0dac48b91a4839206a7d5a88cef415fdc data\create\loot_tables\blocks\limestone_cobblestone_stairs.json
92fb16606f289ad33860270d098fad2522b24e09 data\create\loot_tables\blocks\limestone_cobblestone_wall.json 92fb16606f289ad33860270d098fad2522b24e09 data\create\loot_tables\blocks\limestone_cobblestone_wall.json
371115e5ceb08c07a9ab2371509960c31e0baa8a data\create\loot_tables\blocks\limestone_pillar.json 371115e5ceb08c07a9ab2371509960c31e0baa8a data\create\loot_tables\blocks\limestone_pillar.json
dac789cf53b00eed34308848b5e267b7ccec090c data\create\loot_tables\blocks\linked_extractor.json 205f5899101262f31f5c1a88bb7d954918d08d04 data\create\loot_tables\blocks\linked_extractor.json
7af5a13c9e10903b11732fbc01ae3299328216f0 data\create\loot_tables\blocks\linked_transposer.json 205f5899101262f31f5c1a88bb7d954918d08d04 data\create\loot_tables\blocks\linked_transposer.json
90ddf7b5c3b61758a4ad12a1e6ef16fe6ebf7794 data\create\loot_tables\blocks\mechanical_bearing.json 90ddf7b5c3b61758a4ad12a1e6ef16fe6ebf7794 data\create\loot_tables\blocks\mechanical_bearing.json
e93872a90e4f4642a003539e7db28fdacfdcd114 data\create\loot_tables\blocks\mechanical_crafter.json e93872a90e4f4642a003539e7db28fdacfdcd114 data\create\loot_tables\blocks\mechanical_crafter.json
b12efeeef5682966016ce6ea2d171eecd33d9667 data\create\loot_tables\blocks\mechanical_mixer.json b12efeeef5682966016ce6ea2d171eecd33d9667 data\create\loot_tables\blocks\mechanical_mixer.json

View file

@ -6,7 +6,7 @@
"entries": [ "entries": [
{ {
"type": "minecraft:item", "type": "minecraft:item",
"name": "minecraft:air" "name": "create:funnel"
} }
], ],
"conditions": [ "conditions": [

View file

@ -13,6 +13,7 @@ import com.simibubi.create.content.contraptions.components.actors.HarvesterBlock
import com.simibubi.create.content.contraptions.components.actors.PloughBlock; import com.simibubi.create.content.contraptions.components.actors.PloughBlock;
import com.simibubi.create.content.contraptions.components.actors.PortableStorageInterfaceBlock; import com.simibubi.create.content.contraptions.components.actors.PortableStorageInterfaceBlock;
import com.simibubi.create.content.contraptions.components.clock.CuckooClockBlock; import com.simibubi.create.content.contraptions.components.clock.CuckooClockBlock;
import com.simibubi.create.content.contraptions.components.crafter.CrafterCTBehaviour;
import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterBlock; import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterBlock;
import com.simibubi.create.content.contraptions.components.crank.HandCrankBlock; import com.simibubi.create.content.contraptions.components.crank.HandCrankBlock;
import com.simibubi.create.content.contraptions.components.crusher.CrushingWheelBlock; import com.simibubi.create.content.contraptions.components.crusher.CrushingWheelBlock;
@ -553,6 +554,7 @@ public class AllBlocks {
.initialProperties(SharedProperties::softMetal) .initialProperties(SharedProperties::softMetal)
.blockstate(BlockStateGen.horizontalBlockProvider(true)) .blockstate(BlockStateGen.horizontalBlockProvider(true))
.transform(StressConfigDefaults.setImpact(2.0)) .transform(StressConfigDefaults.setImpact(2.0))
.transform(CreateRegistrate.connectedTextures(new CrafterCTBehaviour()))
.addLayer(() -> RenderType::getCutoutMipped) .addLayer(() -> RenderType::getCutoutMipped)
.item() .item()
.transform(customItemModel()) .transform(customItemModel())

View file

@ -15,6 +15,7 @@ import com.simibubi.create.foundation.ResourceReloadHandler;
import com.simibubi.create.foundation.block.render.CustomBlockModels; import com.simibubi.create.foundation.block.render.CustomBlockModels;
import com.simibubi.create.foundation.block.render.SpriteShifter; import com.simibubi.create.foundation.block.render.SpriteShifter;
import com.simibubi.create.foundation.item.IHaveCustomItemModel; import com.simibubi.create.foundation.item.IHaveCustomItemModel;
import com.simibubi.create.foundation.tileEntity.behaviour.edgeInteraction.EdgeInteractionRenderer;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringRenderer; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringRenderer;
import com.simibubi.create.foundation.tileEntity.behaviour.linked.LinkRenderer; import com.simibubi.create.foundation.tileEntity.behaviour.linked.LinkRenderer;
import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueRenderer; import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueRenderer;
@ -92,6 +93,7 @@ public class CreateClient {
LinkRenderer.tick(); LinkRenderer.tick();
ScrollValueRenderer.tick(); ScrollValueRenderer.tick();
ChassisRangeDisplay.tick(); ChassisRangeDisplay.tick();
EdgeInteractionRenderer.tick();
outliner.tickOutlines(); outliner.tickOutlines();
} }

View file

@ -12,117 +12,40 @@ import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems;
import com.simibubi.create.foundation.utility.RaycastHelper;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT; import net.minecraft.nbt.ListNBT;
import net.minecraft.nbt.NBTUtil; import net.minecraft.nbt.NBTUtil;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
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.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.common.util.Constants.NBT;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.ItemStackHandler; import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.items.wrapper.CombinedInvWrapper; import net.minecraftforge.items.wrapper.CombinedInvWrapper;
@EventBusSubscriber
public class ConnectedInputHandler { public class ConnectedInputHandler {
@SubscribeEvent public static boolean shouldConnect(World world, BlockPos pos, Direction face, Direction direction) {
public static void onBlockActivated(PlayerInteractEvent.RightClickBlock event) {
World world = event.getWorld();
BlockPos pos = event.getPos();
PlayerEntity player = event.getPlayer();
Hand hand = event.getHand();
ItemStack heldItem = player.getHeldItem(hand);
if (player.isSneaking())
return;
if (!AllItems.WRENCH.typeOf(heldItem))
return;
BlockState blockState = world.getBlockState(pos);
if (!AllBlocks.MECHANICAL_CRAFTER.has(blockState))
return;
BlockRayTraceResult ray = RaycastHelper.rayTraceRange(world, player, 10);
if (ray == null)
return;
if (ray.getFace() == blockState.get(MechanicalCrafterBlock.HORIZONTAL_FACING))
return;
Direction activatedDirection = getActivatedDirection(world, pos, ray.getFace(), ray.getHitVec());
if (activatedDirection != null) {
if (event.getSide() != LogicalSide.CLIENT)
toggleConnection(world, pos, pos.offset(activatedDirection));
event.setCanceled(true);
event.setCancellationResult(ActionResultType.SUCCESS);
world.playSound(null, pos, SoundEvents.ENTITY_ITEM_FRAME_ADD_ITEM, SoundCategory.BLOCKS, .25f, .1f);
}
}
public static List<Pair<Direction, Vec3d>> getConnectiveSides(World world, BlockPos pos, Direction face) {
List<Pair<Direction, Vec3d>> sides = new ArrayList<>(6);
BlockState refState = world.getBlockState(pos); BlockState refState = world.getBlockState(pos);
if (!refState.has(HORIZONTAL_FACING))
return false;
Direction refDirection = refState.get(HORIZONTAL_FACING); Direction refDirection = refState.get(HORIZONTAL_FACING);
Vec3d faceOffset = new Vec3d(face.getDirectionVec()).scale(.5).add(VecHelper.getCenterOf(BlockPos.ZERO)); if (direction.getAxis() == refDirection.getAxis())
return false;
if (Block.hasSolidSide(world.getBlockState(pos.offset(face)), world, pos.offset(face), face.getOpposite())) if (face == refDirection)
return sides; return false;
BlockState neighbour = world.getBlockState(pos.offset(direction));
for (Direction direction : Direction.values()) { if (!AllBlocks.MECHANICAL_CRAFTER.has(neighbour))
if (direction.getAxis() == face.getAxis()) return false;
continue; if (refDirection != neighbour.get(HORIZONTAL_FACING))
if (direction.getAxis() == refDirection.getAxis()) return false;
continue; return true;
BlockPos neighbourPos = pos.offset(direction);
BlockState neighbour = world.getBlockState(neighbourPos);
if (!AllBlocks.MECHANICAL_CRAFTER.has(neighbour))
continue;
if (refDirection != neighbour.get(HORIZONTAL_FACING))
continue;
if (Block.hasSolidSide(world.getBlockState(neighbourPos.offset(face)), world, neighbourPos.offset(face),
face.getOpposite()))
continue;
Vec3d bbPos = new Vec3d(direction.getDirectionVec()).scale(.5).add(faceOffset);
sides.add(Pair.of(direction, bbPos));
}
return sides;
}
public static Direction getActivatedDirection(World world, BlockPos pos, Direction face, Vec3d hit) {
Vec3d localHit = hit.subtract(pos.getX(), pos.getY(), pos.getZ());
for (Pair<Direction, Vec3d> pair : getConnectiveSides(world, pos, face)) {
Vec3d bbPos = pair.getRight();
AxisAlignedBB bb = new AxisAlignedBB(bbPos, bbPos).grow(1 / 6f);
if (bb.contains(localHit))
return pair.getKey();
}
return null;
} }
public static void toggleConnection(World world, BlockPos pos, BlockPos pos2) { public static void toggleConnection(World world, BlockPos pos, BlockPos pos2) {
@ -132,14 +55,17 @@ public class ConnectedInputHandler {
if (crafter1 == null || crafter2 == null) if (crafter1 == null || crafter2 == null)
return; return;
BlockPos controllerPos1 = crafter1.getPos().add(crafter1.input.data.get(0)); BlockPos controllerPos1 = crafter1.getPos()
BlockPos controllerPos2 = crafter2.getPos().add(crafter2.input.data.get(0)); .add(crafter1.input.data.get(0));
BlockPos controllerPos2 = crafter2.getPos()
.add(crafter2.input.data.get(0));
if (controllerPos1.equals(controllerPos2)) { if (controllerPos1.equals(controllerPos2)) {
MechanicalCrafterTileEntity controller = CrafterHelper.getCrafter(world, controllerPos1); MechanicalCrafterTileEntity controller = CrafterHelper.getCrafter(world, controllerPos1);
Set<BlockPos> positions = Set<BlockPos> positions = controller.input.data.stream()
controller.input.data.stream().map(l -> controllerPos1.add(l)).collect(Collectors.toSet()); .map(l -> controllerPos1.add(l))
.collect(Collectors.toSet());
List<BlockPos> frontier = new LinkedList<>(); List<BlockPos> frontier = new LinkedList<>();
List<BlockPos> splitGroup = new ArrayList<>(); List<BlockPos> splitGroup = new ArrayList<>();
@ -195,17 +121,20 @@ public class ConnectedInputHandler {
} }
public static void connectControllers(World world, MechanicalCrafterTileEntity crafter1, public static void connectControllers(World world, MechanicalCrafterTileEntity crafter1,
MechanicalCrafterTileEntity crafter2) { MechanicalCrafterTileEntity crafter2) {
crafter1.input.data.forEach(offset -> { crafter1.input.data.forEach(offset -> {
BlockPos connectedPos = crafter1.getPos().add(offset); BlockPos connectedPos = crafter1.getPos()
modifyAndUpdate(world, connectedPos, input -> {}); .add(offset);
modifyAndUpdate(world, connectedPos, input -> {
});
}); });
crafter2.input.data.forEach(offset -> { crafter2.input.data.forEach(offset -> {
if (offset.equals(BlockPos.ZERO)) if (offset.equals(BlockPos.ZERO))
return; return;
BlockPos connectedPos = crafter2.getPos().add(offset); BlockPos connectedPos = crafter2.getPos()
.add(offset);
modifyAndUpdate(world, connectedPos, input -> { modifyAndUpdate(world, connectedPos, input -> {
input.attachTo(crafter1.getPos(), connectedPos); input.attachTo(crafter1.getPos(), connectedPos);
crafter1.input.data.add(BlockPos.ZERO.subtract(input.data.get(0))); crafter1.input.data.add(BlockPos.ZERO.subtract(input.data.get(0)));
@ -251,8 +180,11 @@ public class ConnectedInputHandler {
return input.getItemHandler(world, controllerPos); return input.getItemHandler(world, controllerPos);
} }
List<IItemHandlerModifiable> list = data.stream().map(l -> CrafterHelper.getCrafter(world, pos.add(l))) List<IItemHandlerModifiable> list = data.stream()
.filter(Predicates.notNull()).map(crafter -> crafter.inventory).collect(Collectors.toList()); .map(l -> CrafterHelper.getCrafter(world, pos.add(l)))
.filter(Predicates.notNull())
.map(crafter -> crafter.inventory)
.collect(Collectors.toList());
return new CombinedInvWrapper(Arrays.copyOf(list.toArray(), list.size(), IItemHandlerModifiable[].class)); return new CombinedInvWrapper(Arrays.copyOf(list.toArray(), list.size(), IItemHandlerModifiable[].class));
} }
@ -266,7 +198,8 @@ public class ConnectedInputHandler {
public void read(CompoundNBT nbt) { public void read(CompoundNBT nbt) {
isController = nbt.getBoolean("Controller"); isController = nbt.getBoolean("Controller");
data.clear(); data.clear();
nbt.getList("Data", NBT.TAG_COMPOUND).forEach(inbt -> data.add(NBTUtil.readBlockPos((CompoundNBT) inbt))); nbt.getList("Data", NBT.TAG_COMPOUND)
.forEach(inbt -> data.add(NBTUtil.readBlockPos((CompoundNBT) inbt)));
} }
} }

View file

@ -1,80 +0,0 @@
package com.simibubi.create.content.contraptions.components.crafter;
import org.apache.commons.lang3.tuple.Pair;
import com.mojang.blaze3d.systems.RenderSystem;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.TessellatorHelper;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.RayTraceResult.Type;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.DrawHighlightEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
@EventBusSubscriber(value = Dist.CLIENT)
public class ConnectedInputRenderer {
@SubscribeEvent
public static void renderHighlight(DrawHighlightEvent event) {
RayTraceResult target = event.getTarget();
if (!(target instanceof BlockRayTraceResult))
return;
BlockRayTraceResult result = (BlockRayTraceResult) target;
ClientWorld world = Minecraft.getInstance().world;
BlockPos pos = result.getPos();
BlockState blockState = world.getBlockState(pos);
PlayerEntity player = Minecraft.getInstance().player;
ItemStack heldItem = player.getHeldItem(Hand.MAIN_HAND);
Direction face = result.getFace();
if (player.isSneaking())
return;
if (!AllItems.WRENCH.typeOf(heldItem))
return;
if (!AllBlocks.MECHANICAL_CRAFTER.has(blockState))
return;
if (target.getType() != Type.BLOCK)
return;
if (face == blockState.get(MechanicalCrafterBlock.HORIZONTAL_FACING))
return;
TessellatorHelper.prepareForDrawing();
RenderSystem.translated(pos.getX(), pos.getY(), pos.getZ());
Direction activatedDirection = ConnectedInputHandler.getActivatedDirection(world, pos, face,
result.getHitVec());
for (Pair<Direction, Vec3d> pair : ConnectedInputHandler.getConnectiveSides(world, pos, face)) {
int zRot = face == Direction.UP ? 90 : face == Direction.DOWN ? 270 : 0;
float yRot = AngleHelper.horizontalAngle(face.getOpposite());
Vec3d rotation = new Vec3d(0, yRot, zRot);
//
// GlHelper.renderTransformed(pair.getValue(), rotation, .5f, () -> {
//
// String label = "Connect / Disconnect";// Lang.translate("crafter.connect");
// AxisAlignedBB bb = new AxisAlignedBB(Vec3d.ZERO, Vec3d.ZERO).grow(1/3f);
// ValueBox box = new ValueBox(label, bb, pos);
// box.withColors(0x018383, 0x42e6a4).offsetLabel(new Vec3d(10, 0, 0));
// ValueBoxRenderer.renderBox(box, activatedDirection == pair.getKey());
// });
}
TessellatorHelper.cleanUpAfterDrawing();
}
}

View file

@ -9,6 +9,7 @@ import java.util.List;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems;
import com.simibubi.create.AllTileEntities; import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.components.crafter.ConnectedInputHandler.ConnectedInput; import com.simibubi.create.content.contraptions.components.crafter.ConnectedInputHandler.ConnectedInput;
@ -16,6 +17,7 @@ import com.simibubi.create.content.contraptions.components.crafter.MechanicalCra
import com.simibubi.create.content.contraptions.components.crafter.RecipeGridHandler.GroupedItems; import com.simibubi.create.content.contraptions.components.crafter.RecipeGridHandler.GroupedItems;
import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.edgeInteraction.EdgeInteractionBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InsertingBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InsertingBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InventoryManagementBehaviour.Attachments; import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InventoryManagementBehaviour.Attachments;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
@ -81,6 +83,7 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
protected GroupedItems groupedItemsBeforeCraft; // for rendering on client protected GroupedItems groupedItemsBeforeCraft; // for rendering on client
private InsertingBehaviour inserting; private InsertingBehaviour inserting;
private EdgeInteractionBehaviour connectivity;
public MechanicalCrafterTileEntity() { public MechanicalCrafterTileEntity() {
super(AllTileEntities.MECHANICAL_CRAFTER.type); super(AllTileEntities.MECHANICAL_CRAFTER.type);
@ -93,7 +96,11 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
public void addBehaviours(List<TileEntityBehaviour> behaviours) { public void addBehaviours(List<TileEntityBehaviour> behaviours) {
super.addBehaviours(behaviours); super.addBehaviours(behaviours);
inserting = new InsertingBehaviour(this, Attachments.toward(this::getTargetFacing)); inserting = new InsertingBehaviour(this, Attachments.toward(this::getTargetFacing));
connectivity = new EdgeInteractionBehaviour(this, ConnectedInputHandler::toggleConnection)
.connectivity(ConnectedInputHandler::shouldConnect)
.require(AllItems.WRENCH.get());
behaviours.add(inserting); behaviours.add(inserting);
behaviours.add(connectivity);
} }
public void blockChanged() { public void blockChanged() {
@ -153,7 +160,8 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
groupedItemsBeforeCraft = before; groupedItemsBeforeCraft = before;
if (phaseBefore == Phase.EXPORTING && phase == Phase.WAITING) { if (phaseBefore == Phase.EXPORTING && phase == Phase.WAITING) {
Direction facing = getBlockState().get(MechanicalCrafterBlock.HORIZONTAL_FACING); Direction facing = getBlockState().get(MechanicalCrafterBlock.HORIZONTAL_FACING);
Vec3d vec = new Vec3d(facing.getDirectionVec()).scale(.75).add(VecHelper.getCenterOf(pos)); Vec3d vec = new Vec3d(facing.getDirectionVec()).scale(.75)
.add(VecHelper.getCenterOf(pos));
Direction targetDirection = MechanicalCrafterBlock.getTargetDirection(getBlockState()); Direction targetDirection = MechanicalCrafterBlock.getTargetDirection(getBlockState());
vec = vec.add(new Vec3d(targetDirection.getDirectionVec()).scale(1)); vec = vec.add(new Vec3d(targetDirection.getDirectionVec()).scale(1));
world.addParticle(ParticleTypes.CRIT, vec.x, vec.y, vec.z, 0, 0, 0); world.addParticle(ParticleTypes.CRIT, vec.x, vec.y, vec.z, 0, 0, 0);
@ -169,7 +177,8 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
phase = Phase.IDLE; phase = Phase.IDLE;
String name = compound.getString("Phase"); String name = compound.getString("Phase");
for (Phase phase : Phase.values()) for (Phase phase : Phase.values())
if (phase.name().equals(name)) if (phase.name()
.equals(name))
this.phase = phase; this.phase = phase;
countDown = compound.getInt("CountDown"); countDown = compound.getInt("CountDown");
covered = compound.getBoolean("Cover"); covered = compound.getBoolean("Cover");
@ -211,10 +220,12 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
if (result != null) { if (result != null) {
List<ItemStack> containers = new ArrayList<>(); List<ItemStack> containers = new ArrayList<>();
groupedItems.grid.values().forEach(stack -> { groupedItems.grid.values()
if (stack.hasContainerItem()) .forEach(stack -> {
containers.add(stack.getContainerItem().copy()); if (stack.hasContainerItem())
}); containers.add(stack.getContainerItem()
.copy());
});
groupedItems = new GroupedItems(result); groupedItems = new GroupedItems(result);
for (int i = 0; i < containers.size(); i++) { for (int i = 0; i < containers.size(); i++) {
@ -266,9 +277,13 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
Direction facing = getBlockState().get(MechanicalCrafterBlock.HORIZONTAL_FACING); Direction facing = getBlockState().get(MechanicalCrafterBlock.HORIZONTAL_FACING);
float progress = countDown / 2000f; float progress = countDown / 2000f;
Vec3d facingVec = new Vec3d(facing.getDirectionVec()); Vec3d facingVec = new Vec3d(facing.getDirectionVec());
Vec3d vec = facingVec.scale(.65).add(VecHelper.getCenterOf(pos)); Vec3d vec = facingVec.scale(.65)
.add(VecHelper.getCenterOf(pos));
Vec3d offset = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f) Vec3d offset = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f)
.mul(VecHelper.planeByNormal(facingVec)).normalize().scale(progress * .5f).add(vec); .mul(VecHelper.planeByNormal(facingVec))
.normalize()
.scale(progress * .5f)
.add(vec);
if (progress > .5f) if (progress > .5f)
world.addParticle(ParticleTypes.CRIT, offset.x, offset.y, offset.z, 0, 0, 0); world.addParticle(ParticleTypes.CRIT, offset.x, offset.y, offset.z, 0, 0, 0);
@ -279,11 +294,13 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
Vec3d randVec = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f) Vec3d randVec = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f)
.mul(VecHelper.planeByNormal(facingVec)).normalize().scale(.25f); .mul(VecHelper.planeByNormal(facingVec))
.normalize()
.scale(.25f);
Vec3d offset2 = randVec.add(vec); Vec3d offset2 = randVec.add(vec);
randVec = randVec.scale(.35f); randVec = randVec.scale(.35f);
world.addParticle(new ItemParticleData(ParticleTypes.ITEM, stack), offset2.x, offset2.y, world.addParticle(new ItemParticleData(ParticleTypes.ITEM, stack), offset2.x, offset2.y,
offset2.z, randVec.x, randVec.y, randVec.z); offset2.z, randVec.x, randVec.y, randVec.z);
} }
} }
} }
@ -362,10 +379,13 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
public void eject() { public void eject() {
BlockState blockState = getBlockState(); BlockState blockState = getBlockState();
boolean present = AllBlocks.MECHANICAL_CRAFTER.has(blockState); boolean present = AllBlocks.MECHANICAL_CRAFTER.has(blockState);
Vec3d vec = present ? new Vec3d(blockState.get(HORIZONTAL_FACING).getDirectionVec()).scale(.75f) : Vec3d.ZERO; Vec3d vec = present ? new Vec3d(blockState.get(HORIZONTAL_FACING)
Vec3d ejectPos = VecHelper.getCenterOf(pos).add(vec); .getDirectionVec()).scale(.75f) : Vec3d.ZERO;
Vec3d ejectPos = VecHelper.getCenterOf(pos)
.add(vec);
groupedItems.grid.forEach((pair, stack) -> dropItem(ejectPos, stack)); groupedItems.grid.forEach((pair, stack) -> dropItem(ejectPos, stack));
if (!inventory.getStackInSlot(0).isEmpty()) if (!inventory.getStackInSlot(0)
.isEmpty())
dropItem(ejectPos, inventory.getStackInSlot(0)); dropItem(ejectPos, inventory.getStackInSlot(0));
phase = Phase.IDLE; phase = Phase.IDLE;
groupedItems = new GroupedItems(); groupedItems = new GroupedItems();
@ -391,7 +411,8 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
} }
public boolean craftingItemPresent() { public boolean craftingItemPresent() {
return !inventory.getStackInSlot(0).isEmpty() || covered; return !inventory.getStackInSlot(0)
.isEmpty() || covered;
} }
protected void checkCompletedRecipe() { protected void checkCompletedRecipe() {
@ -410,7 +431,8 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
phase = Phase.ACCEPTING; phase = Phase.ACCEPTING;
groupedItems = new GroupedItems(inventory.getStackInSlot(0)); groupedItems = new GroupedItems(inventory.getStackInSlot(0));
inventory.setStackInSlot(0, ItemStack.EMPTY); inventory.setStackInSlot(0, ItemStack.EMPTY);
if (RecipeGridHandler.getPrecedingCrafters(this).isEmpty()) { if (RecipeGridHandler.getPrecedingCrafters(this)
.isEmpty()) {
phase = Phase.ASSEMBLING; phase = Phase.ASSEMBLING;
countDown = 500; countDown = 500;
} }

View file

@ -13,7 +13,7 @@ import net.minecraft.util.math.Vec3d;
public class DeployerFilterSlot extends ValueBoxTransform { public class DeployerFilterSlot extends ValueBoxTransform {
@Override @Override
protected Vec3d getLocation(BlockState state) { protected Vec3d getLocalOffset(BlockState state) {
Direction facing = state.get(DeployerBlock.FACING); Direction facing = state.get(DeployerBlock.FACING);
Vec3d vec = VecHelper.voxelSpace(8f, 13.5f, 11.5f); Vec3d vec = VecHelper.voxelSpace(8f, 13.5f, 11.5f);

View file

@ -11,7 +11,7 @@ import net.minecraft.util.math.Vec3d;
public class SawFilterSlot extends ValueBoxTransform { public class SawFilterSlot extends ValueBoxTransform {
@Override @Override
protected Vec3d getLocation(BlockState state) { protected Vec3d getLocalOffset(BlockState state) {
if (state.get(SawBlock.FACING) != Direction.UP) if (state.get(SawBlock.FACING) != Direction.UP)
return null; return null;
Vec3d x = VecHelper.voxelSpace(8f, 12.5f, 12.25f); Vec3d x = VecHelper.voxelSpace(8f, 12.5f, 12.25f);

View file

@ -19,8 +19,8 @@ public class DirectionalExtenderScrollOptionSlot extends CenteredSideValueBoxTra
} }
@Override @Override
protected Vec3d getLocation(BlockState state) { protected Vec3d getLocalOffset(BlockState state) {
return super.getLocation(state) return super.getLocalOffset(state)
.add(new Vec3d(state.get(BlockStateProperties.FACING).getDirectionVec()).scale(-2 / 16f)); .add(new Vec3d(state.get(BlockStateProperties.FACING).getDirectionVec()).scale(-2 / 16f));
} }

View file

@ -14,7 +14,7 @@ public class BeltObserverFilterSlot extends ValueBoxTransform {
Vec3d position = VecHelper.voxelSpace(8f, 14.5f, 16f); Vec3d position = VecHelper.voxelSpace(8f, 14.5f, 16f);
@Override @Override
protected Vec3d getLocation(BlockState state) { protected Vec3d getLocalOffset(BlockState state) {
return rotateHorizontally(state, position); return rotateHorizontally(state, position);
} }

View file

@ -12,7 +12,7 @@ import net.minecraft.util.math.Vec3d;
public class AdjustableRepeaterScrollSlot extends ValueBoxTransform { public class AdjustableRepeaterScrollSlot extends ValueBoxTransform {
@Override @Override
protected Vec3d getLocation(BlockState state) { protected Vec3d getLocalOffset(BlockState state) {
return VecHelper.voxelSpace(8, 3f, 8); return VecHelper.voxelSpace(8, 3f, 8);
} }

View file

@ -22,7 +22,7 @@ public class ExtractorSlots {
Vec3d offsetForDownward = VecHelper.voxelSpace(8f, 1.85f, 3.5f); Vec3d offsetForDownward = VecHelper.voxelSpace(8f, 1.85f, 3.5f);
@Override @Override
protected Vec3d getLocation(BlockState state) { protected Vec3d getLocalOffset(BlockState state) {
Vec3d location = offsetForHorizontal; Vec3d location = offsetForHorizontal;
if (state.getBlock() instanceof TransposerBlock) if (state.getBlock() instanceof TransposerBlock)
location = location.add(0, 2 / 16f, 0); location = location.add(0, 2 / 16f, 0);
@ -52,7 +52,7 @@ public class ExtractorSlots {
Vec3d offsetForDownward = VecHelper.voxelSpace(10f, 2f, 11.5f); Vec3d offsetForDownward = VecHelper.voxelSpace(10f, 2f, 11.5f);
@Override @Override
protected Vec3d getLocation(BlockState state) { protected Vec3d getLocalOffset(BlockState state) {
Vec3d location = offsetForHorizontal; Vec3d location = offsetForHorizontal;
if (state.getBlock() instanceof TransposerBlock) if (state.getBlock() instanceof TransposerBlock)
location = location.add(0, 2 / 16f, 0); location = location.add(0, 2 / 16f, 0);

View file

@ -20,7 +20,7 @@ public class FunnelFilterSlot extends ValueBoxTransform {
Vec3d offsetForDownward = VecHelper.voxelSpace(8f, 2.5f, 2f); Vec3d offsetForDownward = VecHelper.voxelSpace(8f, 2.5f, 2f);
@Override @Override
protected Vec3d getLocation(BlockState state) { protected Vec3d getLocalOffset(BlockState state) {
Vec3d vec = offsetForHorizontal; Vec3d vec = offsetForHorizontal;
float yRot = AngleHelper.horizontalAngle(state.get(ExtractorBlock.HORIZONTAL_FACING)); float yRot = AngleHelper.horizontalAngle(state.get(ExtractorBlock.HORIZONTAL_FACING));
if (AttachedLogisticalBlock.isVertical(state)) if (AttachedLogisticalBlock.isVertical(state))

View file

@ -94,7 +94,7 @@ public class CreativeCrateTileEntity extends CrateTileEntity {
} }
@Override @Override
protected Vec3d getLocation(BlockState state) { protected Vec3d getLocalOffset(BlockState state) {
return new Vec3d(0.5, 13 / 16d, 0.5); return new Vec3d(0.5, 13 / 16d, 0.5);
} }

View file

@ -20,7 +20,7 @@ public class RedstoneLinkFrequencySlot extends ValueBoxTransform.Dual {
Vec3d vertical = VecHelper.voxelSpace(10f, 2.5f, 5.5f); Vec3d vertical = VecHelper.voxelSpace(10f, 2.5f, 5.5f);
@Override @Override
protected Vec3d getLocation(BlockState state) { protected Vec3d getLocalOffset(BlockState state) {
Direction facing = state.get(RedstoneLinkBlock.FACING); Direction facing = state.get(RedstoneLinkBlock.FACING);
Vec3d location = vertical; Vec3d location = vertical;

View file

@ -73,21 +73,23 @@ public class ValueBox extends ChasingAABBOutline {
@Override @Override
public void render(MatrixStack ms, IRenderTypeBuffer buffer) { public void render(MatrixStack ms, IRenderTypeBuffer buffer) {
boolean hasTransform = transform != null;
if (transform instanceof Sided && params.getHighlightedFace() != null) if (transform instanceof Sided && params.getHighlightedFace() != null)
((Sided) transform).fromSide(params.getHighlightedFace()); ((Sided) transform).fromSide(params.getHighlightedFace());
if (!transform.shouldRender(blockState)) if (hasTransform && !transform.shouldRender(blockState))
return; return;
ms.push(); ms.push();
ms.translate(pos.getX(), pos.getY(), pos.getZ()); ms.translate(pos.getX(), pos.getY(), pos.getZ());
transform.transform(blockState, ms); if (hasTransform)
transform.transform(blockState, ms);
transformNormals = ms.peek() transformNormals = ms.peek()
.getNormal() .getNormal()
.copy(); .copy();
params.colored(isPassive ? passiveColor : highlightColor); params.colored(isPassive ? passiveColor : highlightColor);
super.render(ms, buffer); super.render(ms, buffer);
float fontScale = -1 / 64f; float fontScale = hasTransform ? -transform.getFontScale() : -1 / 64f;
ms.scale(fontScale, fontScale, fontScale); ms.scale(fontScale, fontScale, fontScale);
ms.push(); ms.push();

View file

@ -19,19 +19,19 @@ public abstract class ValueBoxTransform {
protected float scale = getScale(); protected float scale = getScale();
protected abstract Vec3d getLocation(BlockState state); protected abstract Vec3d getLocalOffset(BlockState state);
protected abstract void rotate(BlockState state, MatrixStack ms); protected abstract void rotate(BlockState state, MatrixStack ms);
public boolean testHit(BlockState state, Vec3d localHit) { public boolean testHit(BlockState state, Vec3d localHit) {
Vec3d offset = getLocation(state); Vec3d offset = getLocalOffset(state);
if (offset == null) if (offset == null)
return false; return false;
return localHit.distanceTo(offset) < scale / 2; return localHit.distanceTo(offset) < scale / 2;
} }
public void transform(BlockState state, MatrixStack ms) { public void transform(BlockState state, MatrixStack ms) {
Vec3d position = getLocation(state); Vec3d position = getLocalOffset(state);
if (position == null) if (position == null)
return; return;
ms.translate(position.x, position.y, position.z); ms.translate(position.x, position.y, position.z);
@ -40,7 +40,7 @@ public abstract class ValueBoxTransform {
} }
public boolean shouldRender(BlockState state) { public boolean shouldRender(BlockState state) {
return state.getMaterial() != Material.AIR && getLocation(state) != null; return state.getMaterial() != Material.AIR && getLocalOffset(state) != null;
} }
protected Vec3d rotateHorizontally(BlockState state, Vec3d vec) { protected Vec3d rotateHorizontally(BlockState state, Vec3d vec) {
@ -56,6 +56,10 @@ public abstract class ValueBoxTransform {
return .4f; return .4f;
} }
protected float getFontScale() {
return 1 / 64f;
}
public static abstract class Dual extends ValueBoxTransform { public static abstract class Dual extends ValueBoxTransform {
protected boolean first; protected boolean first;
@ -73,7 +77,7 @@ public abstract class ValueBoxTransform {
} }
public boolean testHit(BlockState state, Vec3d localHit) { public boolean testHit(BlockState state, Vec3d localHit) {
Vec3d offset = getLocation(state); Vec3d offset = getLocalOffset(state);
if (offset == null) if (offset == null)
return false; return false;
return localHit.distanceTo(offset) < scale / 3.5f; return localHit.distanceTo(offset) < scale / 3.5f;
@ -91,7 +95,7 @@ public abstract class ValueBoxTransform {
} }
@Override @Override
protected Vec3d getLocation(BlockState state) { protected Vec3d getLocalOffset(BlockState state) {
Vec3d location = getSouthLocation(); Vec3d location = getSouthLocation();
location = VecHelper.rotateCentered(location, AngleHelper.horizontalAngle(direction), Axis.Y); location = VecHelper.rotateCentered(location, AngleHelper.horizontalAngle(direction), Axis.Y);
location = VecHelper.rotateCentered(location, AngleHelper.verticalAngle(direction), Axis.Z); location = VecHelper.rotateCentered(location, AngleHelper.verticalAngle(direction), Axis.Z);

View file

@ -0,0 +1,55 @@
package com.simibubi.create.foundation.tileEntity.behaviour.edgeInteraction;
import java.util.Optional;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.IBehaviourType;
import net.minecraft.item.Item;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class EdgeInteractionBehaviour extends TileEntityBehaviour {
public static IBehaviourType<EdgeInteractionBehaviour> TYPE = new IBehaviourType<EdgeInteractionBehaviour>() {
};
ConnectionCallback connectionCallback;
ConnectivityPredicate connectivityPredicate;
Optional<Item> requiredItem;
public EdgeInteractionBehaviour(SmartTileEntity te, ConnectionCallback callback) {
super(te);
this.connectionCallback = callback;
requiredItem = Optional.empty();
connectivityPredicate = (world, pos, face, face2) -> true;
}
public EdgeInteractionBehaviour connectivity(ConnectivityPredicate pred) {
this.connectivityPredicate = pred;
return this;
}
public EdgeInteractionBehaviour require(Item item) {
this.requiredItem = Optional.of(item);
return this;
}
@Override
public IBehaviourType<?> getType() {
return TYPE;
}
@FunctionalInterface
public interface ConnectionCallback {
public void apply(World world, BlockPos clicked, BlockPos neighbour);
}
@FunctionalInterface
public interface ConnectivityPredicate {
public boolean test(World world, BlockPos pos, Direction selectedFace, Direction connectedFace);
}
}

View file

@ -0,0 +1,110 @@
package com.simibubi.create.foundation.tileEntity.behaviour.edgeInteraction;
import java.util.ArrayList;
import java.util.List;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.utility.RaycastHelper;
import net.minecraft.block.Block;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction;
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.Vec3d;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.World;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
@EventBusSubscriber
public class EdgeInteractionHandler {
@SubscribeEvent
public static void onBlockActivated(PlayerInteractEvent.RightClickBlock event) {
World world = event.getWorld();
BlockPos pos = event.getPos();
PlayerEntity player = event.getPlayer();
Hand hand = event.getHand();
ItemStack heldItem = player.getHeldItem(hand);
if (player.isSneaking())
return;
EdgeInteractionBehaviour behaviour = TileEntityBehaviour.get(world, pos, EdgeInteractionBehaviour.TYPE);
if (behaviour == null)
return;
BlockRayTraceResult ray = RaycastHelper.rayTraceRange(world, player, 10);
if (ray == null)
return;
if (behaviour.requiredItem.orElse(heldItem.getItem()) != heldItem.getItem())
return;
Direction activatedDirection = getActivatedDirection(world, pos, ray.getFace(), ray.getHitVec(), behaviour);
if (activatedDirection == null)
return;
if (event.getSide() != LogicalSide.CLIENT)
behaviour.connectionCallback.apply(world, pos, pos.offset(activatedDirection));
event.setCanceled(true);
event.setCancellationResult(ActionResultType.SUCCESS);
world.playSound(null, pos, SoundEvents.ENTITY_ITEM_FRAME_ADD_ITEM, SoundCategory.BLOCKS, .25f, .1f);
}
public static List<Direction> getConnectiveSides(World world, BlockPos pos, Direction face,
EdgeInteractionBehaviour behaviour) {
List<Direction> sides = new ArrayList<>(6);
if (Block.hasSolidSide(world.getBlockState(pos.offset(face)), world, pos.offset(face), face.getOpposite()))
return sides;
for (Direction direction : Direction.values()) {
if (direction.getAxis() == face.getAxis())
continue;
BlockPos neighbourPos = pos.offset(direction);
if (Block.hasSolidSide(world.getBlockState(neighbourPos.offset(face)), world, neighbourPos.offset(face),
face.getOpposite()))
continue;
if (!behaviour.connectivityPredicate.test(world, pos, face, direction))
continue;
sides.add(direction);
}
return sides;
}
public static Direction getActivatedDirection(World world, BlockPos pos, Direction face, Vec3d hit,
EdgeInteractionBehaviour behaviour) {
for (Direction facing : getConnectiveSides(world, pos, face, behaviour)) {
AxisAlignedBB bb = getBB(pos, facing);
if (bb.contains(hit))
return facing;
}
return null;
}
static AxisAlignedBB getBB(BlockPos pos, Direction direction) {
AxisAlignedBB bb = new AxisAlignedBB(pos);
Vec3i vec = direction.getDirectionVec();
int x = vec.getX();
int y = vec.getY();
int z = vec.getZ();
double margin = 12 / 16f;
double absX = Math.abs(x) * margin;
double absY = Math.abs(y) * margin;
double absZ = Math.abs(z) * margin;
bb = bb.contract(absX, absY, absZ);
bb = bb.offset(absX / 2d, absY / 2d, absZ / 2d);
bb = bb.offset(x / 2d, y / 2d, z / 2d);
bb = bb.grow(1 / 256f);
return bb;
}
}

View file

@ -0,0 +1,93 @@
package com.simibubi.create.foundation.tileEntity.behaviour.edgeInteraction;
import java.util.List;
import com.simibubi.create.AllSpecialTextures;
import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBox;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.AxisDirection;
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.Vec3d;
public class EdgeInteractionRenderer {
public static void tick() {
Minecraft mc = Minecraft.getInstance();
RayTraceResult target = mc.objectMouseOver;
if (target == null || !(target instanceof BlockRayTraceResult))
return;
BlockRayTraceResult result = (BlockRayTraceResult) target;
ClientWorld world = mc.world;
BlockPos pos = result.getPos();
PlayerEntity player = mc.player;
ItemStack heldItem = player.getHeldItemMainhand();
if (player.isSneaking())
return;
EdgeInteractionBehaviour behaviour = TileEntityBehaviour.get(world, pos, EdgeInteractionBehaviour.TYPE);
if (behaviour == null)
return;
if (behaviour.requiredItem.orElse(heldItem.getItem()) != heldItem.getItem())
return;
Direction face = result.getFace();
List<Direction> connectiveSides = EdgeInteractionHandler.getConnectiveSides(world, pos, face, behaviour);
if (connectiveSides.isEmpty())
return;
Direction closestEdge = connectiveSides.get(0);
double bestDistance = Double.MAX_VALUE;
Vec3d center = VecHelper.getCenterOf(pos);
for (Direction direction : connectiveSides) {
double distance = new Vec3d(direction.getDirectionVec()).subtract(target.getHitVec()
.subtract(center))
.length();
if (distance > bestDistance)
continue;
bestDistance = distance;
closestEdge = direction;
}
AxisAlignedBB bb = EdgeInteractionHandler.getBB(pos, closestEdge);
boolean hit = bb.contains(target.getHitVec());
ValueBox box = new ValueBox("", bb.offset(-pos.getX(), -pos.getY(), -pos.getZ()), pos);
Vec3d textOffset = Vec3d.ZERO;
boolean positive = closestEdge.getAxisDirection() == AxisDirection.POSITIVE;
if (positive) {
if (face.getAxis()
.isHorizontal()) {
if (closestEdge.getAxis()
.isVertical())
textOffset = textOffset.add(0, -128, 0);
else
textOffset = textOffset.add(-128, 0, 0);
} else
textOffset = textOffset.add(-128, 0, 0);
}
box.offsetLabel(textOffset)
.withColors(0x7A6A2C, 0xB79D64)
.passive(!hit);
CreateClient.outliner.showValueBox("edge", box)
.lineWidth(1 / 64f)
.withFaceTexture(hit ? AllSpecialTextures.THIN_CHECKERED : null)
.highlightFace(face);
}
}