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
e2990fe70ad5d10437a376e70e167d1856277cc1 assets\create\blockstates\rope.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
56b63575c87065bc82eb9410175c501cdf959c66 assets\create\blockstates\saw.json
36592a6542332b35445931e8e9531adf786b63ba assets\create\blockstates\schematicannon.json
@ -324,7 +324,7 @@ c60c3115fd6eeaa3a696428a87a74d184ab7d62d assets\create\blockstates\weathered_lim
7f39521b211441f5c3e06d60c5978cebe16cacfb assets\create\blockstates\zinc_block.json
b7181bcd8182b2f17088e5aa881f374c9c65470c assets\create\blockstates\zinc_ore.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
1930fa3a3c98d53dd19e4ee7f55bc27fd47aa281 assets\create\models\block\acacia_window_pane_noside.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
8fbd865f350c615031ec3f56eb98b51ce3008de3 data\create\loot_tables\blocks\framed_glass.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
1070cba1c0f46cf7ebe31089f35333f5eadda6e4 data\create\loot_tables\blocks\gabbro.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
92fb16606f289ad33860270d098fad2522b24e09 data\create\loot_tables\blocks\limestone_cobblestone_wall.json
371115e5ceb08c07a9ab2371509960c31e0baa8a data\create\loot_tables\blocks\limestone_pillar.json
dac789cf53b00eed34308848b5e267b7ccec090c data\create\loot_tables\blocks\linked_extractor.json
7af5a13c9e10903b11732fbc01ae3299328216f0 data\create\loot_tables\blocks\linked_transposer.json
205f5899101262f31f5c1a88bb7d954918d08d04 data\create\loot_tables\blocks\linked_extractor.json
205f5899101262f31f5c1a88bb7d954918d08d04 data\create\loot_tables\blocks\linked_transposer.json
90ddf7b5c3b61758a4ad12a1e6ef16fe6ebf7794 data\create\loot_tables\blocks\mechanical_bearing.json
e93872a90e4f4642a003539e7db28fdacfdcd114 data\create\loot_tables\blocks\mechanical_crafter.json
b12efeeef5682966016ce6ea2d171eecd33d9667 data\create\loot_tables\blocks\mechanical_mixer.json

View file

@ -6,7 +6,7 @@
"entries": [
{
"type": "minecraft:item",
"name": "minecraft:air"
"name": "create:funnel"
}
],
"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.PortableStorageInterfaceBlock;
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.crank.HandCrankBlock;
import com.simibubi.create.content.contraptions.components.crusher.CrushingWheelBlock;
@ -553,6 +554,7 @@ public class AllBlocks {
.initialProperties(SharedProperties::softMetal)
.blockstate(BlockStateGen.horizontalBlockProvider(true))
.transform(StressConfigDefaults.setImpact(2.0))
.transform(CreateRegistrate.connectedTextures(new CrafterCTBehaviour()))
.addLayer(() -> RenderType::getCutoutMipped)
.item()
.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.SpriteShifter;
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.linked.LinkRenderer;
import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueRenderer;
@ -92,6 +93,7 @@ public class CreateClient {
LinkRenderer.tick();
ScrollValueRenderer.tick();
ChassisRangeDisplay.tick();
EdgeInteractionRenderer.tick();
outliner.tickOutlines();
}

View file

@ -12,117 +12,40 @@ import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Predicates;
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.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.tileentity.TileEntity;
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.world.World;
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.IItemHandlerModifiable;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.items.wrapper.CombinedInvWrapper;
@EventBusSubscriber
public class ConnectedInputHandler {
@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;
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);
public static boolean shouldConnect(World world, BlockPos pos, Direction face, Direction direction) {
BlockState refState = world.getBlockState(pos);
if (!refState.has(HORIZONTAL_FACING))
return false;
Direction refDirection = refState.get(HORIZONTAL_FACING);
Vec3d faceOffset = new Vec3d(face.getDirectionVec()).scale(.5).add(VecHelper.getCenterOf(BlockPos.ZERO));
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;
if (direction.getAxis() == refDirection.getAxis())
continue;
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;
if (direction.getAxis() == refDirection.getAxis())
return false;
if (face == refDirection)
return false;
BlockState neighbour = world.getBlockState(pos.offset(direction));
if (!AllBlocks.MECHANICAL_CRAFTER.has(neighbour))
return false;
if (refDirection != neighbour.get(HORIZONTAL_FACING))
return false;
return true;
}
public static void toggleConnection(World world, BlockPos pos, BlockPos pos2) {
@ -132,14 +55,17 @@ public class ConnectedInputHandler {
if (crafter1 == null || crafter2 == null)
return;
BlockPos controllerPos1 = crafter1.getPos().add(crafter1.input.data.get(0));
BlockPos controllerPos2 = crafter2.getPos().add(crafter2.input.data.get(0));
BlockPos controllerPos1 = crafter1.getPos()
.add(crafter1.input.data.get(0));
BlockPos controllerPos2 = crafter2.getPos()
.add(crafter2.input.data.get(0));
if (controllerPos1.equals(controllerPos2)) {
MechanicalCrafterTileEntity controller = CrafterHelper.getCrafter(world, controllerPos1);
Set<BlockPos> positions =
controller.input.data.stream().map(l -> controllerPos1.add(l)).collect(Collectors.toSet());
Set<BlockPos> positions = controller.input.data.stream()
.map(l -> controllerPos1.add(l))
.collect(Collectors.toSet());
List<BlockPos> frontier = new LinkedList<>();
List<BlockPos> splitGroup = new ArrayList<>();
@ -195,17 +121,20 @@ public class ConnectedInputHandler {
}
public static void connectControllers(World world, MechanicalCrafterTileEntity crafter1,
MechanicalCrafterTileEntity crafter2) {
MechanicalCrafterTileEntity crafter2) {
crafter1.input.data.forEach(offset -> {
BlockPos connectedPos = crafter1.getPos().add(offset);
modifyAndUpdate(world, connectedPos, input -> {});
BlockPos connectedPos = crafter1.getPos()
.add(offset);
modifyAndUpdate(world, connectedPos, input -> {
});
});
crafter2.input.data.forEach(offset -> {
if (offset.equals(BlockPos.ZERO))
return;
BlockPos connectedPos = crafter2.getPos().add(offset);
BlockPos connectedPos = crafter2.getPos()
.add(offset);
modifyAndUpdate(world, connectedPos, input -> {
input.attachTo(crafter1.getPos(), connectedPos);
crafter1.input.data.add(BlockPos.ZERO.subtract(input.data.get(0)));
@ -251,8 +180,11 @@ public class ConnectedInputHandler {
return input.getItemHandler(world, controllerPos);
}
List<IItemHandlerModifiable> list = data.stream().map(l -> CrafterHelper.getCrafter(world, pos.add(l)))
.filter(Predicates.notNull()).map(crafter -> crafter.inventory).collect(Collectors.toList());
List<IItemHandlerModifiable> list = data.stream()
.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));
}
@ -266,7 +198,8 @@ public class ConnectedInputHandler {
public void read(CompoundNBT nbt) {
isController = nbt.getBoolean("Controller");
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 com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
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.relays.belt.BeltTileEntity;
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.InventoryManagementBehaviour.Attachments;
import com.simibubi.create.foundation.utility.VecHelper;
@ -81,6 +83,7 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
protected GroupedItems groupedItemsBeforeCraft; // for rendering on client
private InsertingBehaviour inserting;
private EdgeInteractionBehaviour connectivity;
public MechanicalCrafterTileEntity() {
super(AllTileEntities.MECHANICAL_CRAFTER.type);
@ -93,7 +96,11 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
super.addBehaviours(behaviours);
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(connectivity);
}
public void blockChanged() {
@ -153,7 +160,8 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
groupedItemsBeforeCraft = before;
if (phaseBefore == Phase.EXPORTING && phase == Phase.WAITING) {
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());
vec = vec.add(new Vec3d(targetDirection.getDirectionVec()).scale(1));
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;
String name = compound.getString("Phase");
for (Phase phase : Phase.values())
if (phase.name().equals(name))
if (phase.name()
.equals(name))
this.phase = phase;
countDown = compound.getInt("CountDown");
covered = compound.getBoolean("Cover");
@ -211,10 +220,12 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
if (result != null) {
List<ItemStack> containers = new ArrayList<>();
groupedItems.grid.values().forEach(stack -> {
if (stack.hasContainerItem())
containers.add(stack.getContainerItem().copy());
});
groupedItems.grid.values()
.forEach(stack -> {
if (stack.hasContainerItem())
containers.add(stack.getContainerItem()
.copy());
});
groupedItems = new GroupedItems(result);
for (int i = 0; i < containers.size(); i++) {
@ -266,9 +277,13 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
Direction facing = getBlockState().get(MechanicalCrafterBlock.HORIZONTAL_FACING);
float progress = countDown / 2000f;
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)
.mul(VecHelper.planeByNormal(facingVec)).normalize().scale(progress * .5f).add(vec);
.mul(VecHelper.planeByNormal(facingVec))
.normalize()
.scale(progress * .5f)
.add(vec);
if (progress > .5f)
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++) {
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);
randVec = randVec.scale(.35f);
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() {
BlockState blockState = getBlockState();
boolean present = AllBlocks.MECHANICAL_CRAFTER.has(blockState);
Vec3d vec = present ? new Vec3d(blockState.get(HORIZONTAL_FACING).getDirectionVec()).scale(.75f) : Vec3d.ZERO;
Vec3d ejectPos = VecHelper.getCenterOf(pos).add(vec);
Vec3d vec = present ? new Vec3d(blockState.get(HORIZONTAL_FACING)
.getDirectionVec()).scale(.75f) : Vec3d.ZERO;
Vec3d ejectPos = VecHelper.getCenterOf(pos)
.add(vec);
groupedItems.grid.forEach((pair, stack) -> dropItem(ejectPos, stack));
if (!inventory.getStackInSlot(0).isEmpty())
if (!inventory.getStackInSlot(0)
.isEmpty())
dropItem(ejectPos, inventory.getStackInSlot(0));
phase = Phase.IDLE;
groupedItems = new GroupedItems();
@ -391,7 +411,8 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
}
public boolean craftingItemPresent() {
return !inventory.getStackInSlot(0).isEmpty() || covered;
return !inventory.getStackInSlot(0)
.isEmpty() || covered;
}
protected void checkCompletedRecipe() {
@ -410,7 +431,8 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
phase = Phase.ACCEPTING;
groupedItems = new GroupedItems(inventory.getStackInSlot(0));
inventory.setStackInSlot(0, ItemStack.EMPTY);
if (RecipeGridHandler.getPrecedingCrafters(this).isEmpty()) {
if (RecipeGridHandler.getPrecedingCrafters(this)
.isEmpty()) {
phase = Phase.ASSEMBLING;
countDown = 500;
}

View file

@ -13,7 +13,7 @@ import net.minecraft.util.math.Vec3d;
public class DeployerFilterSlot extends ValueBoxTransform {
@Override
protected Vec3d getLocation(BlockState state) {
protected Vec3d getLocalOffset(BlockState state) {
Direction facing = state.get(DeployerBlock.FACING);
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 {
@Override
protected Vec3d getLocation(BlockState state) {
protected Vec3d getLocalOffset(BlockState state) {
if (state.get(SawBlock.FACING) != Direction.UP)
return null;
Vec3d x = VecHelper.voxelSpace(8f, 12.5f, 12.25f);

View file

@ -19,8 +19,8 @@ public class DirectionalExtenderScrollOptionSlot extends CenteredSideValueBoxTra
}
@Override
protected Vec3d getLocation(BlockState state) {
return super.getLocation(state)
protected Vec3d getLocalOffset(BlockState state) {
return super.getLocalOffset(state)
.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);
@Override
protected Vec3d getLocation(BlockState state) {
protected Vec3d getLocalOffset(BlockState state) {
return rotateHorizontally(state, position);
}

View file

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

View file

@ -22,7 +22,7 @@ public class ExtractorSlots {
Vec3d offsetForDownward = VecHelper.voxelSpace(8f, 1.85f, 3.5f);
@Override
protected Vec3d getLocation(BlockState state) {
protected Vec3d getLocalOffset(BlockState state) {
Vec3d location = offsetForHorizontal;
if (state.getBlock() instanceof TransposerBlock)
location = location.add(0, 2 / 16f, 0);
@ -52,7 +52,7 @@ public class ExtractorSlots {
Vec3d offsetForDownward = VecHelper.voxelSpace(10f, 2f, 11.5f);
@Override
protected Vec3d getLocation(BlockState state) {
protected Vec3d getLocalOffset(BlockState state) {
Vec3d location = offsetForHorizontal;
if (state.getBlock() instanceof TransposerBlock)
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);
@Override
protected Vec3d getLocation(BlockState state) {
protected Vec3d getLocalOffset(BlockState state) {
Vec3d vec = offsetForHorizontal;
float yRot = AngleHelper.horizontalAngle(state.get(ExtractorBlock.HORIZONTAL_FACING));
if (AttachedLogisticalBlock.isVertical(state))

View file

@ -94,7 +94,7 @@ public class CreativeCrateTileEntity extends CrateTileEntity {
}
@Override
protected Vec3d getLocation(BlockState state) {
protected Vec3d getLocalOffset(BlockState state) {
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);
@Override
protected Vec3d getLocation(BlockState state) {
protected Vec3d getLocalOffset(BlockState state) {
Direction facing = state.get(RedstoneLinkBlock.FACING);
Vec3d location = vertical;

View file

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

View file

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