Logistical enhancements and fixes

- Arms can no longer insert into powered brass funnels
- Slight ArmInteractionPoint refactor
- Arms can now interact with Millstones, Basins, Jukeboxes, Crushing Wheels and the Mechanical Saw
- Fixed crash when logging into a world with a running mixer
- Arms now start to dance when one of their in or outputs is a running jukebox
- Arms can now be mounted on the ceiling
- Arms now always prefer the interaction points that were selected first
- Fixed belt funnels not updating their blockstate properly when transitioning from other funnel types
- Vertical funnels next to the end of a belt will now stall the belt when unable to collect incoming items
- Minor model & texture touch ups
- Arm no longer cancels player interaction when its empty handed
- Fixed chutes not vertically interacting with andesite funnels
This commit is contained in:
simibubi 2020-07-10 19:48:04 +02:00
parent 3902569cbd
commit 367296e6c1
44 changed files with 574 additions and 139 deletions

View file

@ -179,7 +179,7 @@ b7506b862d13b3f915c60d38bb7a20afc935f70a assets\create\blockstates\limestone_pil
69790737767e06f000c7824749c46664a123160e assets\create\blockstates\linear_chassis.json
c793ab3aa6cf09d8d6d4136757629689f0365771 assets\create\blockstates\linked_extractor.json
c5422866667331f1d5cf6753c0889747ee02762b assets\create\blockstates\linked_transposer.json
e82e69ae4c7a784ef89fc5d954b2b01946746d48 assets\create\blockstates\mechanical_arm.json
3b3250d6e209403a93d025604a8081087965016e assets\create\blockstates\mechanical_arm.json
ddcf4bb281e046fbb1026b8f46a2cf12448598df assets\create\blockstates\mechanical_bearing.json
5586beef2d9183dc34d8e8d2723620c0569592ae assets\create\blockstates\mechanical_crafter.json
044db7d50e19008bae8bf3325eac2ed0eb1ea6d2 assets\create\blockstates\mechanical_drill.json
@ -338,16 +338,16 @@ c77b46d8b459e5c7cc495393546f3fcca8a1fa1d assets\create\blockstates\weathered_lim
7f39521b211441f5c3e06d60c5978cebe16cacfb assets\create\blockstates\zinc_block.json
b7181bcd8182b2f17088e5aa881f374c9c65470c assets\create\blockstates\zinc_ore.json
541831ab0cf2f0222f0b7e42ec6c4b0ae636168d assets\create\lang\en_ud.json
fe44adfde38a1084754fe46b632811f90dcfcd7f assets\create\lang\en_us.json
143b76ed828949330ef0e338fb6709c28561ac2d assets\create\lang\unfinished\de_de.json
95bf7693b162141c2c76617ed4e04bec474e2def assets\create\lang\unfinished\fr_fr.json
b3bf60afc7d0dea72a9d7d01df36d34affd6a296 assets\create\lang\unfinished\it_it.json
ef336e01a8e3ed3f8c2713c66476bcc708e3e3b0 assets\create\lang\unfinished\ja_jp.json
66c84c388e552ee8259eca2ab1009493456fc4d3 assets\create\lang\unfinished\ko_kr.json
66b3140ef158b51208a191e6a90473fba5bb1749 assets\create\lang\unfinished\nl_nl.json
775702e0f3fbdab7ef8b1714e3cff69da56bd500 assets\create\lang\unfinished\pt_br.json
7c4c4e7a00456f893538a6baa35d726a8786bf93 assets\create\lang\unfinished\ru_ru.json
ce16074d9dc5d504f2a91b164258f0059163260b assets\create\lang\unfinished\zh_cn.json
fd57d2d8144286e26033a087a501f45f2df9ea34 assets\create\lang\en_us.json
87c28254c2acb462fe6a994f688a19e31a4c7a9d assets\create\lang\unfinished\de_de.json
6cd93a72126063c634f49db190d4da545e5a6c43 assets\create\lang\unfinished\fr_fr.json
401d0b295988cfa31af1a94f8c50d86eb54cad0d assets\create\lang\unfinished\it_it.json
30f1189e1963d0a87a9505bfdac9b663ff9d09d1 assets\create\lang\unfinished\ja_jp.json
a56d5b51d410821b7993bdbfd1b141e51be11b54 assets\create\lang\unfinished\ko_kr.json
e8a39cb4afc7668f2690bcacda1f06afd9c82579 assets\create\lang\unfinished\nl_nl.json
3876e40fbc9c6e8561cc761949a6fb9565a03fce assets\create\lang\unfinished\pt_br.json
cc2c01ee69a5a394c9d6dc87f77e08f05adf38a7 assets\create\lang\unfinished\ru_ru.json
7a8b2739021d2e1d2b563f2bed3a201bd3f1b00f assets\create\lang\unfinished\zh_cn.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
@ -1365,10 +1365,12 @@ e4e3c1bd7ecf501b40cffc26d8ad145ab4e89118 data\create\advancements\deployer.json
62f3610188f7dbd3900ab305edc2d06282705a38 data\create\advancements\goggles.json
7e12b7ccb198ef0db7964b8cbef152d8347e333c data\create\advancements\its_alive.json
3d0fc63191ef507a018ef996ebf9406a523f3976 data\create\advancements\lava_wheel.json
90393cdb6b699c9c0fd4dd9400159c3aa6911a6b data\create\advancements\mechanical_arm.json
786c2058805ceca3cd3970cc6e918560b54747f5 data\create\advancements\mechanical_drill.json
41444ae151ce90d2d68dcda0ed3565f98509c594 data\create\advancements\mechanical_saw.json
9c7f0c2484a84ccf42166704475fafcb1f232ce6 data\create\advancements\millstone.json
704c7fc0ed357b1a116ffdc0b6c64fe64e337a5a data\create\advancements\mixer.json
8085b46ca0dd8c511841cabd88e51bff4baceefd data\create\advancements\musical_arm.json
a135eec618e448f440d9f42cc7a3e6c63fc45a71 data\create\advancements\overstressed.json
72025d8bf73ab8096c29f12d0c8d9a346f09cd64 data\create\advancements\polished_rose_quartz.json
1e3cd82e36fd4bcd053d652a0eead4458ed7f315 data\create\advancements\press.json

View file

@ -1,7 +1,11 @@
{
"variants": {
"": {
"ceiling=false": {
"model": "create:block/mechanical_arm/block"
},
"ceiling=true": {
"model": "create:block/mechanical_arm/block",
"x": 180
}
}
}

View file

@ -457,6 +457,10 @@
"advancement.create.crafter.desc": "Place and power some Mechanical Crafters",
"advancement.create.deployer": "Poke, Place, and Attack",
"advancement.create.deployer.desc": "Place and power a Deployer, the perfect reflection of yourself.",
"advancement.create.mechanical_arm": "Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "Pound It, Bro!",
"advancement.create.fist_bump.desc": "Make two Deployers fist-bump.",
"advancement.create.crushing_wheel": "A Pair of Giants",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 777",
"_": "Missing Localizations: 781",
"_": "->------------------------] Game Elements [------------------------<-",
@ -458,6 +458,10 @@
"advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters",
"advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack",
"advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.",
"advancement.create.mechanical_arm": "UNLOCALIZED: Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "UNLOCALIZED: Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "UNLOCALIZED: Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "UNLOCALIZED: Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!",
"advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.",
"advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 380",
"_": "Missing Localizations: 384",
"_": "->------------------------] Game Elements [------------------------<-",
@ -458,6 +458,10 @@
"advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters",
"advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack",
"advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.",
"advancement.create.mechanical_arm": "UNLOCALIZED: Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "UNLOCALIZED: Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "UNLOCALIZED: Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "UNLOCALIZED: Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!",
"advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.",
"advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 364",
"_": "Missing Localizations: 368",
"_": "->------------------------] Game Elements [------------------------<-",
@ -458,6 +458,10 @@
"advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters",
"advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack",
"advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.",
"advancement.create.mechanical_arm": "UNLOCALIZED: Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "UNLOCALIZED: Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "UNLOCALIZED: Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "UNLOCALIZED: Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!",
"advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.",
"advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 359",
"_": "Missing Localizations: 363",
"_": "->------------------------] Game Elements [------------------------<-",
@ -458,6 +458,10 @@
"advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters",
"advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack",
"advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.",
"advancement.create.mechanical_arm": "UNLOCALIZED: Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "UNLOCALIZED: Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "UNLOCALIZED: Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "UNLOCALIZED: Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!",
"advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.",
"advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 364",
"_": "Missing Localizations: 368",
"_": "->------------------------] Game Elements [------------------------<-",
@ -458,6 +458,10 @@
"advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters",
"advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack",
"advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.",
"advancement.create.mechanical_arm": "UNLOCALIZED: Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "UNLOCALIZED: Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "UNLOCALIZED: Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "UNLOCALIZED: Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!",
"advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.",
"advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 714",
"_": "Missing Localizations: 718",
"_": "->------------------------] Game Elements [------------------------<-",
@ -458,6 +458,10 @@
"advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters",
"advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack",
"advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.",
"advancement.create.mechanical_arm": "UNLOCALIZED: Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "UNLOCALIZED: Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "UNLOCALIZED: Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "UNLOCALIZED: Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!",
"advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.",
"advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 784",
"_": "Missing Localizations: 788",
"_": "->------------------------] Game Elements [------------------------<-",
@ -458,6 +458,10 @@
"advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters",
"advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack",
"advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.",
"advancement.create.mechanical_arm": "UNLOCALIZED: Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "UNLOCALIZED: Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "UNLOCALIZED: Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "UNLOCALIZED: Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!",
"advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.",
"advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 778",
"_": "Missing Localizations: 782",
"_": "->------------------------] Game Elements [------------------------<-",
@ -458,6 +458,10 @@
"advancement.create.crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters",
"advancement.create.deployer": "UNLOCALIZED: Poke, Place, and Attack",
"advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself.",
"advancement.create.mechanical_arm": "UNLOCALIZED: Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "UNLOCALIZED: Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "UNLOCALIZED: Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "UNLOCALIZED: Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!",
"advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump.",
"advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 40",
"_": "Missing Localizations: 44",
"_": "->------------------------] Game Elements [------------------------<-",
@ -458,6 +458,10 @@
"advancement.create.crafter.desc": "放置一些机械合成台并且为其供能",
"advancement.create.deployer": "我就指着你了咋地?",
"advancement.create.deployer.desc": "放置并且功能一个机械手。这可是你右手的完美复制品",
"advancement.create.mechanical_arm": "UNLOCALIZED: Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "UNLOCALIZED: Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "UNLOCALIZED: Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "UNLOCALIZED: Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "来碰个拳,哥们~",
"advancement.create.fist_bump.desc": "使两个机械臂互相碰拳",
"advancement.create.crushing_wheel": "一对大家伙",

View file

@ -0,0 +1,46 @@
{
"parent": "create:brass_casing",
"display": {
"icon": {
"item": "create:mechanical_arm"
},
"title": {
"translate": "advancement.create.mechanical_arm"
},
"description": {
"translate": "advancement.create.mechanical_arm.desc"
},
"frame": "goal",
"show_toast": true,
"announce_to_chat": true,
"hidden": false
},
"criteria": {
"0": {
"trigger": "minecraft:placed_block",
"conditions": {
"block": "create:mechanical_arm"
}
},
"1": {
"trigger": "create:kinetic_block",
"conditions": {
"block": "create:mechanical_arm"
}
},
"2": {
"trigger": "create:mechanical_arm"
}
},
"requirements": [
[
"0"
],
[
"1"
],
[
"2"
]
]
}

View file

@ -0,0 +1,46 @@
{
"parent": "create:mechanical_arm",
"display": {
"icon": {
"item": "minecraft:music_disc_13"
},
"title": {
"translate": "advancement.create.musical_arm"
},
"description": {
"translate": "advancement.create.musical_arm.desc"
},
"frame": "task",
"show_toast": true,
"announce_to_chat": true,
"hidden": false
},
"criteria": {
"0": {
"trigger": "minecraft:placed_block",
"conditions": {
"block": "create:mechanical_arm"
}
},
"1": {
"trigger": "create:kinetic_block",
"conditions": {
"block": "create:mechanical_arm"
}
},
"2": {
"trigger": "create:musical_arm"
}
},
"requirements": [
[
"0"
],
[
"1"
],
[
"2"
]
]
}

View file

@ -700,7 +700,11 @@ public class AllBlocks {
public static final BlockEntry<ArmBlock> MECHANICAL_ARM = REGISTRATE.block("mechanical_arm", ArmBlock::new)
.initialProperties(SharedProperties::softMetal)
.blockstate((c, p) -> p.simpleBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p)))
.blockstate((c, p) -> p.getVariantBuilder(c.get())
.forAllStates(s -> ConfiguredModel.builder()
.modelFile(AssetLookup.partialBaseModel(c, p))
.rotationX(s.get(ArmBlock.CEILING) ? 180 : 0)
.build()))
.transform(StressConfigDefaults.setImpact(8.0))
.item(ArmItem::new)
.transform(customItemModel())

View file

@ -135,6 +135,8 @@ public class AllShapes {
.build(),
MECHANICAL_ARM = shape(2, 0, 2, 14, 10, 14).add(3, 0, 3, 13, 14, 13)
.build(),
MECHANICAL_ARM_CEILING = shape(2, 6, 2, 14, 16, 14).add(3, 2, 3, 13, 16, 13)
.build(),
CHUTE = shape(1, 8, 1, 15, 16, 15).add(2, 0, 2, 14, 8, 14)
.build(),
TANK = shape(1, 0, 1, 15, 16, 15).build(), TANK_TOP = shape(TANK_TOP_LID).add(TANK)

View file

@ -118,6 +118,13 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
return super.write(compound);
}
@Override
public void lazyTick() {
super.lazyTick();
if (world.isRemote && running && !basinItemInv.isPresent())
updateBasin();
}
@Override
public void tick() {
super.tick();
@ -156,6 +163,8 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
public void renderParticles() {
IItemHandler itemHandler = basinItemInv.orElse(null);
BasinInventory inv = (BasinInventory) itemHandler;
if (inv == null)
return;
for (int slot = 0; slot < inv.getInputHandler()
.getSlots(); slot++) {

View file

@ -1,6 +1,11 @@
package com.simibubi.create.content.contraptions.fluids;
import net.minecraft.fluid.Fluid;
import java.util.Arrays;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javax.annotation.Nonnull;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.util.math.MathHelper;
@ -8,11 +13,6 @@ import net.minecraftforge.common.util.NonNullConsumer;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import javax.annotation.Nonnull;
import java.util.Arrays;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class CombinedFluidHandler implements IFluidHandler {
private final int capacity;
private final FluidStack[] tanks;

View file

@ -147,8 +147,8 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
return false;
BlockState stateBelow = world.getBlockState(pos.down());
if (AllBlocks.BRASS_FUNNEL.has(stateBelow)) {
if (stateBelow.get(BrassFunnelBlock.POWERED))
if (stateBelow.getBlock() instanceof FunnelBlock) {
if (stateBelow.has(BrassFunnelBlock.POWERED) && stateBelow.get(BrassFunnelBlock.POWERED))
return false;
if (stateBelow.get(BrassFunnelBlock.FACING) != Direction.UP)
return false;
@ -187,9 +187,9 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
private boolean handleUpwardOutput(boolean simulate) {
BlockState stateAbove = world.getBlockState(pos.up());
if (AllBlocks.BRASS_FUNNEL.has(stateAbove)) {
if (!stateAbove.get(BrassFunnelBlock.POWERED)
&& stateAbove.get(BrassFunnelBlock.FACING) == Direction.DOWN) {
if (stateAbove.getBlock() instanceof FunnelBlock) {
boolean powered = stateAbove.has(BrassFunnelBlock.POWERED) && stateAbove.get(BrassFunnelBlock.POWERED);
if (!powered && stateAbove.get(BrassFunnelBlock.FACING) == Direction.DOWN) {
ItemStack remainder = FunnelBlock.tryInsert(world, pos.up(), item, simulate);
if (remainder.isEmpty()) {
if (!simulate)

View file

@ -4,6 +4,8 @@ import com.simibubi.create.AllBlocks;
import net.minecraft.block.BlockState;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
public class AndesiteFunnelBlock extends FunnelBlock {
@ -12,14 +14,14 @@ public class AndesiteFunnelBlock extends FunnelBlock {
}
@Override
public BlockState getEquivalentBeltFunnel(BlockState state) {
public BlockState getEquivalentBeltFunnel(IBlockReader world, BlockPos pos, BlockState state) {
Direction facing = state.get(FACING);
return AllBlocks.ANDESITE_BELT_FUNNEL.getDefaultState()
.with(BeltFunnelBlock.HORIZONTAL_FACING, facing);
}
@Override
public BlockState getEquivalentChuteFunnel(BlockState state) {
public BlockState getEquivalentChuteFunnel(IBlockReader world, BlockPos pos, BlockState state) {
Direction facing = state.get(FACING);
return AllBlocks.ANDESITE_CHUTE_FUNNEL.getDefaultState()
.with(ChuteFunnelBlock.HORIZONTAL_FACING, facing);

View file

@ -23,7 +23,6 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.ILightReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
@ -55,9 +54,12 @@ public abstract class BeltFunnelBlock extends HorizontalInteractionFunnelBlock {
@Override
public BlockState getStateForPlacement(BlockItemUseContext ctx) {
BlockState state = super.getStateForPlacement(ctx);
World world = ctx.getWorld();
BlockPos posBelow = ctx.getPos()
.down();
return getStateForPosition(ctx.getWorld(), ctx.getPos(), state, ctx.getFace());
}
public BlockState getStateForPosition(World world, BlockPos pos, BlockState defaultState, Direction facing) {
BlockState state = defaultState.with(HORIZONTAL_FACING, facing);
BlockPos posBelow = pos.down();
BlockState stateBelow = world.getBlockState(posBelow);
if (!AllBlocks.BELT.has(stateBelow))
return state;
@ -68,8 +70,7 @@ public abstract class BeltFunnelBlock extends HorizontalInteractionFunnelBlock {
if (beltTileEntity.getSpeed() == 0)
return state;
Direction movementFacing = beltTileEntity.getMovementFacing();
Direction funnelFacing = ctx.getFace();
return state.with(PUSHING, movementFacing == funnelFacing);
return state.with(PUSHING, movementFacing == facing);
}
@Override
@ -107,7 +108,7 @@ public abstract class BeltFunnelBlock extends HorizontalInteractionFunnelBlock {
return true;
}
public static BlockState updateShape(BlockState state, ILightReader world, BlockPos pos) {
public static BlockState updateShape(BlockState state, IBlockReader world, BlockPos pos) {
state = state.with(SHAPE, Shape.RETRACTED);
BlockState neighbour = world.getBlockState(pos.offset(state.get(HORIZONTAL_FACING)));
if (canConnectTo(state, neighbour))

View file

@ -10,6 +10,7 @@ import net.minecraft.state.StateContainer.Builder;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
public class BrassFunnelBlock extends FunnelBlock {
@ -48,7 +49,7 @@ public class BrassFunnelBlock extends FunnelBlock {
}
@Override
public BlockState getEquivalentBeltFunnel(BlockState state) {
public BlockState getEquivalentBeltFunnel(IBlockReader world, BlockPos pos, BlockState state) {
Direction facing = state.get(FACING);
return AllBlocks.BRASS_BELT_FUNNEL.getDefaultState()
.with(BeltFunnelBlock.HORIZONTAL_FACING, facing)
@ -56,7 +57,7 @@ public class BrassFunnelBlock extends FunnelBlock {
}
@Override
public BlockState getEquivalentChuteFunnel(BlockState state) {
public BlockState getEquivalentChuteFunnel(IBlockReader world, BlockPos pos, BlockState state) {
Direction facing = state.get(FACING);
return AllBlocks.BRASS_CHUTE_FUNNEL.getDefaultState()
.with(ChuteFunnelBlock.HORIZONTAL_FACING, facing)

View file

@ -61,7 +61,7 @@ public abstract class FunnelBlock extends ProperDirectionalBlock implements ITE<
BlockRayTraceResult hit) {
ItemStack heldItem = player.getHeldItem(handIn);
boolean shouldntInsertItem = AllBlocks.MECHANICAL_ARM.isIn(heldItem);
boolean shouldntInsertItem = AllBlocks.MECHANICAL_ARM.isIn(heldItem) || !canInsertIntoFunnel(state);
if (hit.getFace() == getFunnelFacing(state) && !shouldntInsertItem) {
if (!worldIn.isRemote)
@ -144,17 +144,17 @@ public abstract class FunnelBlock extends ProperDirectionalBlock implements ITE<
if (facing.getAxis()
.isHorizontal()) {
if (direction == Direction.DOWN) {
BlockState equivalentFunnel = getEquivalentBeltFunnel(state);
BlockState equivalentFunnel = getEquivalentBeltFunnel(null, null, state);
if (BeltFunnelBlock.isOnValidBelt(equivalentFunnel, world, pos))
return equivalentFunnel;
return BeltFunnelBlock.updateShape(equivalentFunnel, world, pos);
}
if (direction == facing) {
BlockState equivalentFunnel = getEquivalentChuteFunnel(state);
BlockState equivalentFunnel = getEquivalentChuteFunnel(null, null, state);
if (ChuteFunnelBlock.isOnValidChute(equivalentFunnel, world, pos))
return equivalentFunnel;
}
if (direction == facing.getOpposite()) {
BlockState equivalentFunnel = getEquivalentChuteFunnel(state);
BlockState equivalentFunnel = getEquivalentChuteFunnel(null, null, state);
if (ChuteFunnelBlock.isOnValidChute(equivalentFunnel, world, pos))
return equivalentFunnel;
}
@ -162,9 +162,9 @@ public abstract class FunnelBlock extends ProperDirectionalBlock implements ITE<
return state;
}
public abstract BlockState getEquivalentChuteFunnel(BlockState state);
public abstract BlockState getEquivalentChuteFunnel(IBlockReader world, BlockPos pos, BlockState state);
public abstract BlockState getEquivalentBeltFunnel(BlockState state);
public abstract BlockState getEquivalentBeltFunnel(IBlockReader world, BlockPos pos, BlockState state);
@Override
public boolean isValidPosition(BlockState state, IWorldReader world, BlockPos pos) {

View file

@ -29,6 +29,8 @@ public class FunnelItem extends BlockItem {
@Override
protected BlockState getStateForPlacement(BlockItemUseContext ctx) {
World world = ctx.getWorld();
BlockPos pos = ctx.getPos();
BlockState state = super.getStateForPlacement(ctx);
if (state == null)
return state;
@ -40,9 +42,9 @@ public class FunnelItem extends BlockItem {
return state;
FunnelBlock block = (FunnelBlock) getBlock();
Block beltFunnelBlock = block.getEquivalentBeltFunnel(state)
Block beltFunnelBlock = block.getEquivalentBeltFunnel(world, pos, state)
.getBlock();
Block chuteFunnelBlock = block.getEquivalentChuteFunnel(state)
Block chuteFunnelBlock = block.getEquivalentChuteFunnel(world, pos, state)
.getBlock();
BlockState equivalentBeltFunnel = beltFunnelBlock.getStateForPlacement(ctx)
@ -52,8 +54,6 @@ public class FunnelItem extends BlockItem {
BlockState reversedChuteFunnel = equivalentChuteFunnel.rotate(Rotation.CLOCKWISE_180)
.cycle(ChuteFunnelBlock.PUSHING);
World world = ctx.getWorld();
BlockPos pos = ctx.getPos();
if (BeltFunnelBlock.isOnValidBelt(equivalentBeltFunnel, world, pos))
return BeltFunnelBlock.updateShape(equivalentBeltFunnel, world, pos);
if (ChuteFunnelBlock.isOnValidChute(equivalentChuteFunnel, world, pos))

View file

@ -34,6 +34,7 @@ public class FunnelTileEntity extends SmartTileEntity {
private FilteringBehaviour filtering;
private InsertingBehaviour inserting;
private ExtractingBehaviour extracting;
private DirectBeltInputBehaviour beltInputBehaviour;
int sendFlap;
InterpolatedChasingValue flap;
@ -183,6 +184,15 @@ public class FunnelTileEntity extends SmartTileEntity {
filtering.onlyActiveWhen(this::supportsFiltering);
behaviours.add(filtering);
beltInputBehaviour = new DirectBeltInputBehaviour(this).onlyInsertWhen(this::supportsDirectBeltInput)
.setInsertionHandler(this::handleDirectBeltInput);
behaviours.add(beltInputBehaviour);
}
private boolean supportsDirectBeltInput(Direction side) {
BlockState blockState = getBlockState();
return blockState != null && blockState.getBlock() instanceof FunnelBlock
&& blockState.get(FunnelBlock.FACING) == Direction.UP;
}
private boolean supportsFiltering() {
@ -190,6 +200,15 @@ public class FunnelTileEntity extends SmartTileEntity {
return blockState != null && blockState.has(BlockStateProperties.POWERED);
}
private ItemStack handleDirectBeltInput(TransportedItemStack stack, Direction side, boolean simulate) {
ItemStack inserted = stack.stack;
if (!filtering.test(inserted))
return inserted;
if (determineCurrentMode() == Mode.PAUSED)
return inserted;
return inserting.insert(inserted, simulate);
}
public void flap(boolean inward) {
sendFlap = inward ? 1 : -1;
sendData();

View file

@ -86,9 +86,12 @@ public abstract class HorizontalInteractionFunnelBlock extends HorizontalBlock i
@Override
public BlockState updatePostPlacement(BlockState state, Direction direction, BlockState neighbour, IWorld world,
BlockPos pos, BlockPos p_196271_6_) {
if (!canStillInteract(state, world, pos))
return parent.getDefaultState()
.with(FunnelBlock.FACING, state.get(HORIZONTAL_FACING));
if (!canStillInteract(state, world, pos)) {
BlockState parentState = parent.getDefaultState();
if (state.has(POWERED) && state.get(POWERED))
parentState = parentState.with(POWERED, true);
return parentState.with(FunnelBlock.FACING, state.get(HORIZONTAL_FACING));
}
return state;
}

View file

@ -35,7 +35,7 @@ public class CreativeCrateInventory implements IItemHandler {
public ItemStack extractItem(int slot, int amount, boolean simulate) {
ItemStack filter = te.filter.getFilter().copy();
if (!filter.isEmpty())
filter.setCount(amount);
filter.setCount(Math.min(filter.getMaxStackSize(), amount));
return filter;
}

View file

@ -24,10 +24,13 @@ public class ArmAngleTarget {
headAngle = -15;
}
public ArmAngleTarget(BlockPos armPos, Vec3d pointTarget, Direction clawFacing) {
public ArmAngleTarget(BlockPos armPos, Vec3d pointTarget, Direction clawFacing, boolean ceiling) {
// if (ceiling)
// clawFacing = clawFacing.getOpposite();
Vec3d target = pointTarget;
Vec3d origin = VecHelper.getCenterOf(armPos)
.add(0, 4 / 16f, 0);
.add(0, ceiling ? -4 / 16f : 4 / 16f, 0);
Vec3d clawTarget = target;
target = target.add(new Vec3d(clawFacing.getOpposite()
.getDirectionVec()).scale(.5f));
@ -37,6 +40,11 @@ public class ArmAngleTarget {
.length();
float baseAngle = AngleHelper.deg(MathHelper.atan2(diff.x, diff.z)) + 180;
if (ceiling) {
diff = diff.mul(1, -1, 1);
baseAngle = 180 - baseAngle;
}
float alphaOffset = AngleHelper.deg(MathHelper.atan2(diff.y, horizontalDistance));
float a = 18 / 16f; // lower arm length
@ -61,8 +69,13 @@ public class ArmAngleTarget {
headPos = VecHelper.rotate(headPos.add(0, b, 0), beta + 180, Axis.X);
headPos = VecHelper.rotate(headPos.add(0, a, 0), alpha - 90, Axis.X);
headPos = VecHelper.rotate(headPos, baseAngle, Axis.Y);
headPos = VecHelper.rotate(headPos, ceiling ? 180 : 0, Axis.X);
headPos = headPos.add(origin);
Vec3d headDiff = clawTarget.subtract(headPos);
if (ceiling)
headDiff = headDiff.mul(1, -1, 1);
float horizontalHeadDistance = (float) headDiff.mul(1, 0, 1)
.length();
float headAngle =

View file

@ -1,17 +1,24 @@
package com.simibubi.create.content.logistics.block.mechanicalArm;
import org.apache.commons.lang3.mutable.MutableBoolean;
import com.simibubi.create.AllShapes;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.base.KineticBlock;
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmTileEntity.Phase;
import com.simibubi.create.foundation.block.ITE;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.InventoryHelper;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer.Builder;
import net.minecraft.tileentity.TileEntity;
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.math.BlockPos;
@ -24,8 +31,21 @@ import net.minecraft.world.World;
public class ArmBlock extends KineticBlock implements ITE<ArmTileEntity> {
public static final BooleanProperty CEILING = BooleanProperty.create("ceiling");
public ArmBlock(Properties properties) {
super(properties);
setDefaultState(getDefaultState().with(CEILING, false));
}
@Override
protected void fillStateContainer(Builder<Block, BlockState> p_206840_1_) {
super.fillStateContainer(p_206840_1_.add(CEILING));
}
@Override
public BlockState getStateForPlacement(BlockItemUseContext ctx) {
return getDefaultState().with(CEILING, ctx.getFace() == Direction.DOWN);
}
@Override
@ -34,9 +54,9 @@ public class ArmBlock extends KineticBlock implements ITE<ArmTileEntity> {
}
@Override
public VoxelShape getShape(BlockState p_220053_1_, IBlockReader p_220053_2_, BlockPos p_220053_3_,
public VoxelShape getShape(BlockState state, IBlockReader p_220053_2_, BlockPos p_220053_3_,
ISelectionContext p_220053_4_) {
return AllShapes.MECHANICAL_ARM;
return state.get(CEILING) ? AllShapes.MECHANICAL_ARM_CEILING : AllShapes.MECHANICAL_ARM;
}
@Override
@ -70,18 +90,21 @@ public class ArmBlock extends KineticBlock implements ITE<ArmTileEntity> {
@Override
public ActionResultType onUse(BlockState p_225533_1_, World world, BlockPos pos, PlayerEntity player,
Hand p_225533_5_, BlockRayTraceResult p_225533_6_) {
if (world.isRemote)
return ActionResultType.SUCCESS;
MutableBoolean success = new MutableBoolean(false);
withTileEntityDo(world, pos, te -> {
if (te.heldItem.isEmpty())
return;
success.setTrue();
if (world.isRemote)
return;
player.inventory.placeItemBackInInventory(world, te.heldItem);
te.heldItem = ItemStack.EMPTY;
te.phase = Phase.SEARCH_INPUTS;
te.markDirty();
te.sendData();
});
return ActionResultType.SUCCESS;
return success.booleanValue() ? ActionResultType.SUCCESS : ActionResultType.PASS;
}
}

View file

@ -1,12 +1,17 @@
package com.simibubi.create.content.logistics.block.mechanicalArm;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import com.google.common.collect.ImmutableMap;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.components.saw.SawBlock;
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock;
import com.simibubi.create.content.logistics.block.funnel.FunnelBlock;
import com.simibubi.create.foundation.advancement.AllTriggers;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InsertingBehaviour;
@ -14,9 +19,14 @@ import com.simibubi.create.foundation.utility.NBTHelper;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.BlockState;
import net.minecraft.block.JukeboxBlock;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.JukeboxTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
@ -43,6 +53,19 @@ public abstract class ArmInteractionPoint {
private LazyOptional<IItemHandler> cachedHandler;
private ArmAngleTarget cachedAngles;
private static ImmutableMap<ArmInteractionPoint, Supplier<ArmInteractionPoint>> POINTS =
ImmutableMap.<ArmInteractionPoint, Supplier<ArmInteractionPoint>>builder()
.put(new Belt(), Belt::new)
.put(new Depot(), Depot::new)
.put(new Saw(), Saw::new)
.put(new Chute(), Chute::new)
.put(new Jukebox(), Jukebox::new)
.put(new Basin(), Basin::new)
.put(new Millstone(), Millstone::new)
.put(new Funnel(), Funnel::new)
.put(new CrushingWheels(), CrushingWheels::new)
.build();
public ArmInteractionPoint() {
cachedHandler = LazyOptional.empty();
}
@ -66,16 +89,19 @@ public abstract class ArmInteractionPoint {
return Direction.DOWN;
}
abstract boolean isValid(BlockState state);
abstract boolean isValid(IBlockReader reader, BlockPos pos, BlockState state);
static boolean isInteractable(BlockState state) {
return AllBlocks.DEPOT.has(state) || AllBlocks.BELT.has(state) || AllBlocks.CHUTE.has(state)
|| state.getBlock() instanceof FunnelBlock;
static boolean isInteractable(IBlockReader reader, BlockPos pos, BlockState state) {
for (ArmInteractionPoint armInteractionPoint : POINTS.keySet())
if (armInteractionPoint.isValid(reader, pos, state))
return true;
return false;
}
ArmAngleTarget getTargetAngles(BlockPos armPos) {
ArmAngleTarget getTargetAngles(BlockPos armPos, boolean ceiling) {
if (cachedAngles == null)
cachedAngles = new ArmAngleTarget(armPos, getInteractionPositionVector(), getInteractionDirection());
cachedAngles =
new ArmAngleTarget(armPos, getInteractionPositionVector(), getInteractionDirection(), ceiling);
return cachedAngles;
}
@ -120,15 +146,10 @@ public abstract class ArmInteractionPoint {
BlockState state = world.getBlockState(pos);
ArmInteractionPoint point = null;
if (AllBlocks.DEPOT.has(state))
point = new Depot();
if (AllBlocks.BELT.has(state) && !(world.getBlockState(pos.up())
.getBlock() instanceof BeltTunnelBlock))
point = new Belt();
if (AllBlocks.CHUTE.has(state))
point = new Chute();
if (state.getBlock() instanceof FunnelBlock)
point = new Funnel();
for (ArmInteractionPoint armInteractionPoint : POINTS.keySet())
if (armInteractionPoint.isValid(world, pos, state))
point = POINTS.get(armInteractionPoint)
.get();
if (point != null) {
point.state = state;
@ -155,6 +176,15 @@ public abstract class ArmInteractionPoint {
return interactionPoint;
}
static abstract class TopFaceArmInteractionPoint extends ArmInteractionPoint {
@Override
Vec3d getInteractionPositionVector() {
return new Vec3d(pos).add(.5f, 1, .5f);
}
}
static class Depot extends ArmInteractionPoint {
@Override
@ -163,29 +193,117 @@ public abstract class ArmInteractionPoint {
}
@Override
boolean isValid(BlockState state) {
boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) {
return AllBlocks.DEPOT.has(state);
}
}
static class Saw extends Depot {
@Override
boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) {
return AllBlocks.MECHANICAL_SAW.has(state) && state.get(SawBlock.RUNNING)
&& state.get(SawBlock.FACING) == Direction.UP;
}
}
static class Millstone extends ArmInteractionPoint {
@Override
boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) {
return AllBlocks.MILLSTONE.has(state);
}
}
static class CrushingWheels extends TopFaceArmInteractionPoint {
@Override
boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) {
return AllBlocks.CRUSHING_WHEEL_CONTROLLER.has(state);
}
}
static class Basin extends ArmInteractionPoint {
@Override
boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) {
return AllBlocks.BASIN.has(state);
}
}
static class Jukebox extends TopFaceArmInteractionPoint {
@Override
boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) {
return state.getBlock() instanceof JukeboxBlock;
}
@Override
int getSlotCount(World world) {
return 1;
}
@Override
ItemStack insert(World world, ItemStack stack, boolean simulate) {
TileEntity tileEntity = world.getTileEntity(pos);
if (!(tileEntity instanceof JukeboxTileEntity))
return stack;
if (!(state.getBlock() instanceof JukeboxBlock))
return stack;
JukeboxBlock jukeboxBlock = (JukeboxBlock) state.getBlock();
JukeboxTileEntity jukeboxTE = (JukeboxTileEntity) tileEntity;
if (!jukeboxTE.getRecord()
.isEmpty())
return stack;
ItemStack remainder = stack.copy();
ItemStack toInsert = remainder.split(1);
if (!simulate && !world.isRemote) {
jukeboxBlock.insertRecord(world, pos, state, toInsert);
world.playEvent((PlayerEntity) null, 1010, pos, Item.getIdFromItem(toInsert.getItem()));
AllTriggers.triggerForNearbyPlayers(AllTriggers.MUSICAL_ARM, world, pos, 10);
}
return remainder;
}
@Override
ItemStack extract(World world, int slot, int amount, boolean simulate) {
TileEntity tileEntity = world.getTileEntity(pos);
if (!(tileEntity instanceof JukeboxTileEntity))
return ItemStack.EMPTY;
if (!(state.getBlock() instanceof JukeboxBlock))
return ItemStack.EMPTY;
JukeboxTileEntity jukeboxTE = (JukeboxTileEntity) tileEntity;
ItemStack itemstack = jukeboxTE.getRecord();
if (itemstack.isEmpty())
return ItemStack.EMPTY;
if (!simulate && !world.isRemote) {
world.playEvent(1010, pos, 0);
jukeboxTE.clear();
world.setBlockState(pos, state.with(JukeboxBlock.HAS_RECORD, false), 2);
}
return itemstack;
}
}
static class Belt extends Depot {
@Override
boolean isValid(BlockState state) {
return AllBlocks.BELT.has(state);
boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) {
return AllBlocks.BELT.has(state) && !(reader.getBlockState(pos.up())
.getBlock() instanceof BeltTunnelBlock);
}
}
static class Chute extends ArmInteractionPoint {
static class Chute extends TopFaceArmInteractionPoint {
@Override
Vec3d getInteractionPositionVector() {
return new Vec3d(pos).add(.5f, 1, .5f);
}
@Override
boolean isValid(BlockState state) {
boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) {
return AllBlocks.CHUTE.has(state);
}
}
@ -219,6 +337,9 @@ public abstract class ArmInteractionPoint {
ItemStack insert(World world, ItemStack stack, boolean simulate) {
FilteringBehaviour filtering = TileEntityBehaviour.get(world, pos, FilteringBehaviour.TYPE);
InsertingBehaviour inserter = TileEntityBehaviour.get(world, pos, InsertingBehaviour.TYPE);
BlockState state = world.getBlockState(pos);
if (state.has(BlockStateProperties.POWERED) && state.get(BlockStateProperties.POWERED))
return stack;
if (inserter == null)
return stack;
if (filtering != null && !filtering.test(stack))
@ -227,7 +348,7 @@ public abstract class ArmInteractionPoint {
}
@Override
boolean isValid(BlockState state) {
boolean isValid(IBlockReader reader, BlockPos pos, BlockState state) {
return state.getBlock() instanceof FunnelBlock;
}

View file

@ -1,9 +1,9 @@
package com.simibubi.create.content.logistics.block.mechanicalArm;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.List;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems;
@ -30,7 +30,7 @@ import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
@EventBusSubscriber(value = Dist.CLIENT)
public class ArmInteractionPointHandler {
static Map<BlockPos, ArmInteractionPoint> currentSelection = new HashMap<>();
static List<ArmInteractionPoint> currentSelection = new ArrayList<>();
static ItemStack currentItem;
static long lastBlockPos = -1;
@ -44,15 +44,17 @@ public class ArmInteractionPointHandler {
if (!world.isRemote)
return;
if (!currentSelection.containsKey(pos)) {
ArmInteractionPoint selected = getSelected(pos);
if (selected == null) {
ArmInteractionPoint point = ArmInteractionPoint.createAt(world, pos);
if (point == null)
return;
currentSelection.put(pos, point);
selected = point;
put(point);
}
currentSelection.get(pos)
.cycleMode();
selected.cycleMode();
event.setCanceled(true);
event.setCancellationResult(ActionResultType.SUCCESS);
}
@ -64,7 +66,7 @@ public class ArmInteractionPointHandler {
if (!event.getWorld().isRemote)
return;
BlockPos pos = event.getPos();
if (currentSelection.remove(pos) != null) {
if (remove(pos) != null) {
event.setCanceled(true);
event.setCancellationResult(ActionResultType.SUCCESS);
}
@ -73,7 +75,7 @@ public class ArmInteractionPointHandler {
public static void flushSettings(BlockPos pos) {
if (currentItem == null)
return;
AllPackets.channel.sendToServer(new ArmPlacementPacket(currentSelection.values(), pos));
AllPackets.channel.sendToServer(new ArmPlacementPacket(currentSelection, pos));
currentSelection.clear();
currentItem = null;
}
@ -122,8 +124,8 @@ public class ArmInteractionPointHandler {
if (lastBlockPos == -1 || lastBlockPos != pos.toLong()) {
currentSelection.clear();
ArmTileEntity arm = (ArmTileEntity) te;
arm.inputs.forEach(point -> currentSelection.put(point.pos, point));
arm.outputs.forEach(point -> currentSelection.put(point.pos, point));
arm.inputs.forEach(ArmInteractionPointHandler::put);
arm.outputs.forEach(ArmInteractionPointHandler::put);
lastBlockPos = pos.toLong();
}
@ -132,16 +134,14 @@ public class ArmInteractionPointHandler {
}
}
private static void drawOutlines(Map<BlockPos, ArmInteractionPoint> selection) {
private static void drawOutlines(Collection<ArmInteractionPoint> selection) {
World world = Minecraft.getInstance().world;
for (Iterator<Entry<BlockPos, ArmInteractionPoint>> iterator = selection.entrySet()
.iterator(); iterator.hasNext();) {
Entry<BlockPos, ArmInteractionPoint> entry = iterator.next();
BlockPos pos = entry.getKey();
for (Iterator<ArmInteractionPoint> iterator = selection.iterator(); iterator.hasNext();) {
ArmInteractionPoint point = iterator.next();
BlockPos pos = point.pos;
BlockState state = world.getBlockState(pos);
ArmInteractionPoint point = entry.getValue();
if (!point.isValid(state)) {
if (!point.isValid(world, pos, state)) {
iterator.remove();
continue;
}
@ -158,4 +158,23 @@ public class ArmInteractionPointHandler {
}
}
private static void put(ArmInteractionPoint point) {
currentSelection.add(point);
}
private static ArmInteractionPoint remove(BlockPos pos) {
ArmInteractionPoint result = getSelected(pos);
if (result != null)
currentSelection.remove(result);
return result;
}
private static ArmInteractionPoint getSelected(BlockPos pos) {
for (ArmInteractionPoint point : currentSelection) {
if (point.pos.equals(pos))
return point;
}
return null;
}
}

View file

@ -22,8 +22,9 @@ public class ArmItem extends BlockItem {
@Override
public ActionResultType onItemUse(ItemUseContext ctx) {
if (ArmInteractionPoint.isInteractable(ctx.getWorld()
.getBlockState(ctx.getPos())))
World world = ctx.getWorld();
BlockPos pos = ctx.getPos();
if (ArmInteractionPoint.isInteractable(world, pos, world.getBlockState(pos)))
return ActionResultType.SUCCESS;
return super.onItemUse(ctx);
}
@ -37,9 +38,9 @@ public class ArmItem extends BlockItem {
}
@Override
public boolean canPlayerBreakBlockWhileHolding(BlockState state, World p_195938_2_, BlockPos p_195938_3_,
public boolean canPlayerBreakBlockWhileHolding(BlockState state, World world, BlockPos pos,
PlayerEntity p_195938_4_) {
return !ArmInteractionPoint.isInteractable(state);
return !ArmInteractionPoint.isInteractable(world, pos, state);
}
}

View file

@ -5,6 +5,9 @@ import com.mojang.blaze3d.vertex.IVertexBuilder;
import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmTileEntity.Phase;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.ColorHelper;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.MatrixStacker;
import com.simibubi.create.foundation.utility.SuperByteBuffer;
@ -18,6 +21,7 @@ import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.MathHelper;
public class ArmRenderer extends KineticTileEntityRenderer {
@ -35,6 +39,21 @@ public class ArmRenderer extends KineticTileEntityRenderer {
MatrixStacker msr = MatrixStacker.of(ms);
int color = 0xFFFFFF;
float baseAngle = arm.baseAngle.get(pt);
float lowerArmAngle = arm.lowerArmAngle.get(pt) - 135;
float upperArmAngle = arm.upperArmAngle.get(pt) - 90;
float headAngle = arm.headAngle.get(pt);
boolean rave = te instanceof ArmTileEntity && ((ArmTileEntity) te).phase == Phase.DANCING;
float renderTick = AnimationTickHolder.getRenderTick() + (te.hashCode() % 64);
if (rave) {
baseAngle = (renderTick * 10) % 360;
lowerArmAngle = MathHelper.lerp((MathHelper.sin(renderTick / 4) + 1) / 2, -45, 15);
upperArmAngle = MathHelper.lerp((MathHelper.sin(renderTick / 8) + 1) / 4, -45, 95);
headAngle = -lowerArmAngle;
color = ColorHelper.rainbowColor(AnimationTickHolder.ticks * 100);
}
ms.push();
SuperByteBuffer base = AllBlockPartials.ARM_BASE.renderOn(blockState).light(light);
@ -46,23 +65,26 @@ public class ArmRenderer extends KineticTileEntityRenderer {
msr.centre();
if (blockState.get(ArmBlock.CEILING))
msr.rotateX(180);
ms.translate(0, 4 / 16d, 0);
msr.rotateY(arm.baseAngle.get(pt));
msr.rotateY(baseAngle);
base.renderInto(ms, builder);
ms.translate(0, 1 / 16d, -2 / 16d);
msr.rotateX(arm.lowerArmAngle.get(pt) - 135);
msr.rotateX(lowerArmAngle);
ms.translate(0, -1 / 16d, 0);
lowerBody.color(color)
.renderInto(ms, builder);
ms.translate(0, 12 / 16d, 12 / 16d);
msr.rotateX(arm.upperArmAngle.get(pt) - 90);
msr.rotateX(upperArmAngle);
upperBody.color(color)
.renderInto(ms, builder);
ms.translate(0, 11 / 16d, -11 / 16d);
msr.rotateX(arm.headAngle.get(pt));
msr.rotateX(headAngle);
head.renderInto(ms, builder);
ms.translate(0, 0, -4 / 16d);

View file

@ -6,11 +6,15 @@ import java.util.List;
import javax.annotation.Nullable;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Jukebox;
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Mode;
import com.simibubi.create.foundation.advancement.AllTriggers;
import com.simibubi.create.foundation.gui.widgets.InterpolatedAngle;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.NBTHelper;
import net.minecraft.block.BlockState;
import net.minecraft.block.JukeboxBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.INBT;
@ -43,7 +47,7 @@ public class ArmTileEntity extends KineticTileEntity {
boolean updateInteractionPoints;
enum Phase {
SEARCH_INPUTS, MOVE_TO_INPUT, SEARCH_OUTPUTS, MOVE_TO_OUTPUT, IDLE
SEARCH_INPUTS, MOVE_TO_INPUT, SEARCH_OUTPUTS, MOVE_TO_OUTPUT, DANCING
}
public ArmTileEntity(TileEntityType<?> typeIn) {
@ -86,12 +90,34 @@ public class ArmTileEntity extends KineticTileEntity {
return;
if (chasedPointProgress < .5f)
return;
if (phase == Phase.SEARCH_INPUTS)
if (phase == Phase.SEARCH_INPUTS || phase == Phase.DANCING) {
checkForMusic();
searchForItem();
}
if (phase == Phase.SEARCH_OUTPUTS)
searchForDestination();
}
private void checkForMusic() {
boolean hasMusic = checkForMusicAmong(inputs) || checkForMusicAmong(outputs);
if (hasMusic != (phase == Phase.DANCING)) {
phase = hasMusic ? Phase.DANCING : Phase.SEARCH_INPUTS;
markDirty();
sendData();
}
}
private boolean checkForMusicAmong(List<ArmInteractionPoint> list) {
for (ArmInteractionPoint armInteractionPoint : list) {
if (!(armInteractionPoint instanceof Jukebox))
continue;
BlockState state = world.getBlockState(armInteractionPoint.pos);
if (state.has(JukeboxBlock.HAS_RECORD) && state.get(JukeboxBlock.HAS_RECORD))
return true;
}
return false;
}
private void tickMovementProgress() {
chasedPointProgress += Math.min(256, Math.abs(getSpeed())) / 1024f;
if (chasedPointProgress > 1)
@ -101,8 +127,8 @@ public class ArmTileEntity extends KineticTileEntity {
ArmInteractionPoint targetedInteractionPoint = getTargetedInteractionPoint();
ArmAngleTarget previousTarget = this.previousTarget;
ArmAngleTarget target =
targetedInteractionPoint == null ? ArmAngleTarget.NO_TARGET : targetedInteractionPoint.getTargetAngles(pos);
ArmAngleTarget target = targetedInteractionPoint == null ? ArmAngleTarget.NO_TARGET
: targetedInteractionPoint.getTargetAngles(pos, isOnCeiling());
baseAngle.set(AngleHelper.angleLerp(chasedPointProgress, previousBaseAngle,
target == ArmAngleTarget.NO_TARGET ? previousBaseAngle : target.baseAngle));
@ -116,7 +142,13 @@ public class ArmTileEntity extends KineticTileEntity {
lowerArmAngle.set(MathHelper.lerp(progress, previousTarget.lowerArmAngle, target.lowerArmAngle));
upperArmAngle.set(MathHelper.lerp(progress, previousTarget.upperArmAngle, target.upperArmAngle));
headAngle.set(AngleHelper.angleLerp(progress, previousTarget.headAngle, target.headAngle));
headAngle.set(AngleHelper.angleLerp(progress, previousTarget.headAngle % 360, target.headAngle % 360));
}
protected boolean isOnCeiling() {
BlockState state = getBlockState();
return hasWorld() && state != null && state.has(ArmBlock.CEILING) && state.get(ArmBlock.CEILING);
}
@Nullable
@ -182,6 +214,9 @@ public class ArmTileEntity extends KineticTileEntity {
chasedPointIndex = -1;
sendData();
markDirty();
if (!world.isRemote)
AllTriggers.triggerForNearbyPlayers(AllTriggers.MECHANICAL_ARM, world, pos, 10);
}
protected void collectItem() {
@ -277,9 +312,9 @@ public class ArmTileEntity extends KineticTileEntity {
int previousIndex = chasedPointIndex;
Phase previousPhase = phase;
ListNBT interactionPointTagBefore = interactionPointTag;
super.readClientUpdate(tag);
boolean ceiling = isOnCeiling();
if (interactionPointTagBefore == null || interactionPointTagBefore.size() != interactionPointTag.size())
updateInteractionPoints = true;
if (previousIndex != chasedPointIndex || (previousPhase != phase)) {
@ -288,9 +323,10 @@ public class ArmTileEntity extends KineticTileEntity {
previousPoint = inputs.get(previousIndex);
if (previousPhase == Phase.MOVE_TO_OUTPUT && previousIndex < outputs.size())
previousPoint = outputs.get(previousIndex);
previousTarget = previousPoint == null ? ArmAngleTarget.NO_TARGET : previousPoint.getTargetAngles(pos);
previousTarget =
previousPoint == null ? ArmAngleTarget.NO_TARGET : previousPoint.getTargetAngles(pos, ceiling);
if (previousPoint != null)
previousBaseAngle = previousPoint.getTargetAngles(pos).baseAngle;
previousBaseAngle = previousPoint.getTargetAngles(pos, ceiling).baseAngle;
}
}

View file

@ -80,8 +80,8 @@ public class AllAdvancements implements IDataProvider {
andesiteExpertLane(t, andesite_casing);
Advancement drill =
kinecticAdvancement("mechanical_drill", AllBlocks.MECHANICAL_DRILL.get(), TaskType.NORMAL).withParent(andesite_casing)
Advancement drill = kinecticAdvancement("mechanical_drill", AllBlocks.MECHANICAL_DRILL.get(), TaskType.NORMAL)
.withParent(andesite_casing)
.register(t, id + ":mechanical_drill");
Advancement press =
@ -98,7 +98,8 @@ public class AllAdvancements implements IDataProvider {
itemAdvancement("electron_tube", AllItems.ELECTRON_TUBE, TaskType.NORMAL).withParent(rose_quartz)
.register(t, id + ":electron_tube");
Advancement saw = kinecticAdvancement("mechanical_saw", AllBlocks.MECHANICAL_SAW.get(), TaskType.NORMAL).withParent(press)
Advancement saw =
kinecticAdvancement("mechanical_saw", AllBlocks.MECHANICAL_SAW.get(), TaskType.NORMAL).withParent(press)
.register(t, id + ":mechanical_saw");
Advancement basin = advancement("basin", AllBlocks.BASIN.get(), TaskType.NORMAL).withParent(press)
@ -196,6 +197,20 @@ public class AllAdvancements implements IDataProvider {
.withCriterion("0", AllTriggers.GIGA_EXTENDO.instance())
.register(t, id + ":dual_extendo_grip");
Advancement mechanical_arm = advancement("mechanical_arm", AllBlocks.MECHANICAL_ARM.get(), TaskType.GOAL)
.withCriterion("0", placeBlock(AllBlocks.MECHANICAL_ARM.get()))
.withCriterion("1", isPowered(AllBlocks.MECHANICAL_ARM.get()))
.withCriterion("2", AllTriggers.MECHANICAL_ARM.instance())
.withParent(brass_casing)
.register(t, id + ":mechanical_arm");
Advancement musical_arm = advancement("musical_arm", Items.MUSIC_DISC_13, TaskType.MILESTONE)
.withCriterion("0", placeBlock(AllBlocks.MECHANICAL_ARM.get()))
.withCriterion("1", isPowered(AllBlocks.MECHANICAL_ARM.get()))
.withCriterion("2", AllTriggers.MUSICAL_ARM.instance())
.withParent(mechanical_arm)
.register(t, id + ":musical_arm");
Advancement deployer =
kinecticAdvancement("deployer", AllBlocks.DEPLOYER.get(), TaskType.GOAL).withParent(brass_casing)
.register(t, id + ":deployer");

View file

@ -33,6 +33,8 @@ public class AllTriggers {
UPGRADED_ZAPPER = simple("upgraded_zapper"),
EXTENDO = simple("extendo"),
GIGA_EXTENDO = simple("giga_extendo"),
MECHANICAL_ARM = simple("mechanical_arm"),
MUSICAL_ARM = simple("musical_arm"),
MIXER_MIX = simple("mixer");
private static SimpleTrigger simple(String id) {

View file

@ -61,6 +61,10 @@
"advancement.create.crafter.desc": "Place and power some Mechanical Crafters",
"advancement.create.deployer": "Poke, Place, and Attack",
"advancement.create.deployer.desc": "Place and power a Deployer, the perfect reflection of yourself.",
"advancement.create.mechanical_arm": "Mechanical Grab'n'Drop",
"advancement.create.mechanical_arm.desc": "Craft a Mechanical Arm, select in- and outputs, place it down and give it power; then watch it do all the work for you.",
"advancement.create.musical_arm": "Play me my Theme Tune!",
"advancement.create.musical_arm.desc": "Watch a Mechanical Arm operate your Jukebox.",
"advancement.create.fist_bump": "Pound It, Bro!",
"advancement.create.fist_bump.desc": "Make two Deployers fist-bump.",
"advancement.create.crushing_wheel": "A Pair of Giants",

View file

@ -121,8 +121,8 @@
},
{
"name": "Back",
"from": [3, -2, 3],
"to": [13, 2, 13],
"from": [3.1, -1.9, 3.1],
"to": [12.9, 2, 12.9],
"faces": {
"north": {"uv": [9.5, 9, 14.5, 11], "texture": "#4"},
"east": {"uv": [9.5, 9, 14.5, 11], "texture": "#4"},

Binary file not shown.

Before

Width:  |  Height:  |  Size: 978 B

After

Width:  |  Height:  |  Size: 984 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 297 B

After

Width:  |  Height:  |  Size: 297 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 948 B

After

Width:  |  Height:  |  Size: 952 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB