From f820e2be273bfc2949e70ae740e4506bad61edae Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Wed, 1 Jul 2020 22:02:00 +0200 Subject: [PATCH] Mechanical Arm Implementation - The arm blockitem can now be used to select inputs & outputs - Arms now transfer items between inputs and outputs - Arm support for Belts, Depots and Funnels - Some safety checks in net code - Minor refactor to NBTHelper --- .../com/simibubi/create/AllBlockPartials.java | 7 +- .../java/com/simibubi/create/AllBlocks.java | 3 +- .../com/simibubi/create/ClientEvents.java | 1 - .../com/simibubi/create/CreateClient.java | 2 + .../components/clock/CuckooClockRenderer.java | 2 +- .../clock/CuckooClockTileEntity.java | 19 +- .../deployer/DeployerMovementBehaviour.java | 2 +- .../components/deployer/DeployerRenderer.java | 2 +- .../deployer/DeployerTileEntity.java | 8 +- .../CancelPlayerFallPacket.java | 2 + .../bearing/ClockworkContraption.java | 4 +- .../mounted/MountedContraption.java | 4 +- .../advanced/sequencer/Instruction.java | 8 +- .../relays/belt/transport/BeltInventory.java | 4 +- .../tools/ExtendoGripInteractionPacket.java | 2 + .../zapper/blockzapper/BlockzapperItem.java | 7 +- .../zapper/terrainzapper/WorldshaperItem.java | 8 +- .../WorldshaperRenderHandler.java | 4 +- .../terrainzapper/WorldshaperScreen.java | 55 ++-- .../logistics/block/depot/DepotRenderer.java | 6 +- .../block/depot/DepotTileEntity.java | 7 + .../block/mechanicalArm/ArmAngleTarget.java | 77 +++++ .../block/mechanicalArm/ArmBlock.java | 13 - .../mechanicalArm/ArmInteractionPoint.java | 234 ++++++++++++++ .../ArmInteractionPointHandler.java | 115 +++++++ .../block/mechanicalArm/ArmItem.java | 45 +++ .../mechanicalArm/ArmPlacementPacket.java | 70 +++++ .../block/mechanicalArm/ArmRenderer.java | 66 ++-- .../block/mechanicalArm/ArmTileEntity.java | 290 ++++++++++++++++-- .../item/filter/FilterScreenPacket.java | 4 +- .../packet/ConfigureSchematicannonPacket.java | 2 + .../packet/SchematicPlacePacket.java | 2 + .../packet/SchematicUploadPacket.java | 2 + .../gui/widgets/InterpolatedAngle.java | 11 + .../gui/widgets/InterpolatedChasingAngle.java | 4 + .../foundation/networking/AllPackets.java | 2 + .../foundation/networking/NbtPacket.java | 2 + .../TileEntityConfigurationPacket.java | 2 + .../create/foundation/utility/NBTHelper.java | 11 +- .../block/mechanical_arm/flag/long_in.json | 31 ++ .../block/mechanical_arm/flag/long_out.json | 31 ++ .../block/mechanical_arm/flag/short_in.json | 31 ++ .../block/mechanical_arm/flag/short_out.json | 31 ++ .../create/textures/block/marker_flag.png | Bin 0 -> 324 bytes 44 files changed, 1104 insertions(+), 129 deletions(-) create mode 100644 src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmAngleTarget.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPoint.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPointHandler.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmItem.java create mode 100644 src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmPlacementPacket.java create mode 100644 src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedAngle.java create mode 100644 src/main/resources/assets/create/models/block/mechanical_arm/flag/long_in.json create mode 100644 src/main/resources/assets/create/models/block/mechanical_arm/flag/long_out.json create mode 100644 src/main/resources/assets/create/models/block/mechanical_arm/flag/short_in.json create mode 100644 src/main/resources/assets/create/models/block/mechanical_arm/flag/short_out.json create mode 100644 src/main/resources/assets/create/textures/block/marker_flag.png diff --git a/src/main/java/com/simibubi/create/AllBlockPartials.java b/src/main/java/com/simibubi/create/AllBlockPartials.java index f707e021b..b2ad31f85 100644 --- a/src/main/java/com/simibubi/create/AllBlockPartials.java +++ b/src/main/java/com/simibubi/create/AllBlockPartials.java @@ -29,7 +29,7 @@ public class AllBlockPartials { private static List all = new ArrayList<>(); public static final AllBlockPartials - SCHEMATICANNON_CONNECTOR = get("schematicannon/connector"), + SCHEMATICANNON_CONNECTOR = get("schematicannon/connector"), SCHEMATICANNON_PIPE = get("schematicannon/pipe"), SHAFTLESS_COGWHEEL = get("cogwheel_shaftless"), @@ -92,6 +92,11 @@ public class AllBlockPartials { ARM_CLAW_BASE = get("mechanical_arm/claw_base"), ARM_CLAW_GRIP = get("mechanical_arm/claw_grip"), + FLAG_SHORT_IN = get("mechanical_arm/flag/short_in"), + FLAG_SHORT_OUT = get("mechanical_arm/flag/short_out"), + FLAG_LONG_IN = get("mechanical_arm/flag/long_in"), + FLAG_LONG_OUT = get("mechanical_arm/flag/long_out"), + MECHANICAL_PUMP_ARROW = get("mechanical_pump/arrow"), MECHANICAL_PUMP_COG = get("mechanical_pump/cog"), FLUID_PIPE_CASING = get("fluid_pipe/casing"); diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java index cbfd936ee..b21f000bd 100644 --- a/src/main/java/com/simibubi/create/AllBlocks.java +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -96,6 +96,7 @@ import com.simibubi.create.content.logistics.block.funnel.VerticalFunnelGenerato import com.simibubi.create.content.logistics.block.inventories.AdjustableCrateBlock; import com.simibubi.create.content.logistics.block.inventories.CreativeCrateBlock; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmBlock; +import com.simibubi.create.content.logistics.block.mechanicalArm.ArmItem; import com.simibubi.create.content.logistics.block.packager.PackagerBlock; import com.simibubi.create.content.logistics.block.realityFunnel.BeltFunnelBlock; import com.simibubi.create.content.logistics.block.realityFunnel.BeltFunnelGenerator; @@ -781,7 +782,7 @@ public class AllBlocks { .initialProperties(SharedProperties::softMetal) .blockstate((c, p) -> p.simpleBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p))) .transform(StressConfigDefaults.setImpact(8.0)) - .item() + .item(ArmItem::new) .transform(customItemModel()) .register(); diff --git a/src/main/java/com/simibubi/create/ClientEvents.java b/src/main/java/com/simibubi/create/ClientEvents.java index cd986dc09..28fa9c9bf 100644 --- a/src/main/java/com/simibubi/create/ClientEvents.java +++ b/src/main/java/com/simibubi/create/ClientEvents.java @@ -109,7 +109,6 @@ public class ClientEvents { return; double delta = event.getScrollDelta(); - boolean cancelled = CreateClient.schematicHandler.mouseScrolled(delta) || CreateClient.schematicAndQuillHandler.mouseScrolled(delta) || FilteringHandler.onScroll(delta) || ScrollValueHandler.onScroll(delta); diff --git a/src/main/java/com/simibubi/create/CreateClient.java b/src/main/java/com/simibubi/create/CreateClient.java index 54a9d8b36..514e75015 100644 --- a/src/main/java/com/simibubi/create/CreateClient.java +++ b/src/main/java/com/simibubi/create/CreateClient.java @@ -14,6 +14,7 @@ import com.simibubi.create.content.curiosities.tools.ExtendoGripRenderHandler; import com.simibubi.create.content.curiosities.zapper.ZapperRenderHandler; import com.simibubi.create.content.curiosities.zapper.blockzapper.BlockzapperRenderHandler; import com.simibubi.create.content.curiosities.zapper.terrainzapper.WorldshaperRenderHandler; +import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPointHandler; import com.simibubi.create.content.schematics.ClientSchematicLoader; import com.simibubi.create.content.schematics.client.SchematicAndQuillHandler; import com.simibubi.create.content.schematics.client.SchematicHandler; @@ -109,6 +110,7 @@ public class CreateClient { KineticDebugger.tick(); ZapperRenderHandler.tick(); ExtendoGripRenderHandler.tick(); + ArmInteractionPointHandler.tick(); outliner.tickOutlines(); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockRenderer.java index e440cb32d..b99b6d784 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockRenderer.java @@ -76,7 +76,7 @@ public class CuckooClockRenderer extends KineticTileEntityRenderer { .renderInto(ms, vb); // Figure - if (clock.animationType != null) { + if (clock.animationType != Animation.NONE) { offset = -(angle / 135) * 1 / 2f + 10 / 16f; SuperByteBuffer figure = (clock.animationType == Animation.PIG ? AllBlockPartials.CUCKOO_PIG : AllBlockPartials.CUCKOO_CREEPER) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockTileEntity.java index e2cd4fb51..e67a32739 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockTileEntity.java @@ -32,17 +32,18 @@ public class CuckooClockTileEntity extends KineticTileEntity { private boolean sendAnimationUpdate; enum Animation { - PIG, CREEPER, SURPRISE; + PIG, CREEPER, SURPRISE, NONE; } public CuckooClockTileEntity(TileEntityType type) { super(type); + animationType = Animation.NONE; } @Override public CompoundNBT writeToClient(CompoundNBT compound) { if (sendAnimationUpdate) - compound.putString("Animation", animationType == null ? "none" : NBTHelper.writeEnum(animationType)); + NBTHelper.writeEnum(compound, "Animation", animationType); sendAnimationUpdate = false; return super.writeToClient(compound); } @@ -50,11 +51,7 @@ public class CuckooClockTileEntity extends KineticTileEntity { @Override public void readClientUpdate(CompoundNBT tag) { if (tag.contains("Animation")) { - String string = tag.getString("Animation"); - if ("none".equals(string)) - animationType = null; - else - animationType = NBTHelper.readEnum(string, Animation.class); + animationType = NBTHelper.readEnum(tag, "Animation", Animation.class); animationProgress.lastValue = 0; animationProgress.value = 0; } @@ -72,7 +69,7 @@ public class CuckooClockTileEntity extends KineticTileEntity { int minutes = (dayTime % 1000) * 60 / 1000; if (!world.isRemote) { - if (animationType == null) { + if (animationType == Animation.NONE) { if (hours == 12 && minutes < 5) startAnimation(Animation.PIG); if (hours == 18 && minutes < 36 && minutes > 31) @@ -81,13 +78,13 @@ public class CuckooClockTileEntity extends KineticTileEntity { float value = animationProgress.value; animationProgress.set(value + 1); if (value > 100) - animationType = null; + animationType = Animation.NONE; if (animationType == Animation.SURPRISE && animationProgress.value == 50) { Vec3d center = VecHelper.getCenterOf(pos); world.destroyBlock(pos, false); world.createExplosion(null, CUCKOO_SURPRISE, center.x, center.y, center.z, 3, false, - Explosion.Mode.BREAK); + Explosion.Mode.BREAK); } } @@ -96,7 +93,7 @@ public class CuckooClockTileEntity extends KineticTileEntity { if (world.isRemote) { moveHands(hours, minutes); - if (animationType == null) { + if (animationType == Animation.NONE) { if (AnimationTickHolder.ticks % 32 == 0) playSound(SoundEvents.BLOCK_NOTE_BLOCK_HAT, 1 / 16f, 2f); else if (AnimationTickHolder.ticks % 16 == 0) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java index 7f315c3bb..11a175391 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java @@ -162,7 +162,7 @@ public class DeployerMovementBehaviour extends MovementBehaviour { } private Mode getMode(MovementContext context) { - return NBTHelper.readEnum(context.tileData.getString("Mode"), Mode.class); + return NBTHelper.readEnum(context.tileData, "Mode", Mode.class); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerRenderer.java index c9cf85bec..8482b8529 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerRenderer.java @@ -160,7 +160,7 @@ public class DeployerRenderer extends SafeTileEntityRenderer IVertexBuilder builder = buffer.getBuffer(RenderType.getSolid()); BlockState blockState = context.state; BlockPos pos = BlockPos.ZERO; - Mode mode = NBTHelper.readEnum(context.tileData.getString("Mode"), Mode.class); + Mode mode = NBTHelper.readEnum(context.tileData, "Mode", Mode.class); World world = context.world; AllBlockPartials handPose = mode == Mode.PUNCH ? AllBlockPartials.DEPLOYER_HAND_PUNCHING : AllBlockPartials.DEPLOYER_HAND_POINTING; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java index 05a1002f5..825b15add 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java @@ -333,8 +333,8 @@ public class DeployerTileEntity extends KineticTileEntity { @Override public void read(CompoundNBT compound) { - state = NBTHelper.readEnum(compound.getString("State"), State.class); - mode = NBTHelper.readEnum(compound.getString("Mode"), Mode.class); + state = NBTHelper.readEnum(compound, "State", State.class); + mode = NBTHelper.readEnum(compound, "Mode", Mode.class); timer = compound.getInt("Timer"); deferredInventoryList = compound.getList("Inventory", NBT.TAG_COMPOUND); overflowItems = NBTHelper.readItemList(compound.getList("Overflow", NBT.TAG_COMPOUND)); @@ -345,8 +345,8 @@ public class DeployerTileEntity extends KineticTileEntity { @Override public CompoundNBT write(CompoundNBT compound) { - compound.putString("Mode", NBTHelper.writeEnum(mode)); - compound.putString("State", NBTHelper.writeEnum(state)); + NBTHelper.writeEnum(compound, "Mode", mode); + NBTHelper.writeEnum(compound, "State", state); compound.putInt("Timer", timer); if (player != null) { compound.put("HeldItem", player.getHeldItemMainhand().serializeNBT()); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/CancelPlayerFallPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/CancelPlayerFallPacket.java index 71cac0863..f26e99bff 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/CancelPlayerFallPacket.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/CancelPlayerFallPacket.java @@ -24,6 +24,8 @@ public class CancelPlayerFallPacket extends SimplePacketBase { public void handle(Supplier context) { context.get().enqueueWork(() -> { ServerPlayerEntity sender = context.get().getSender(); + if (sender == null) + return; sender.handleFallDamage(sender.fallDistance, 1.0F); sender.fallDistance = 0; sender.onGround = true; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkContraption.java index 833a51d42..97abf1372 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkContraption.java @@ -98,14 +98,14 @@ public class ClockworkContraption extends Contraption { CompoundNBT tag = super.writeNBT(); tag.putInt("facing", facing.getIndex()); tag.putInt("offset", offset); - tag.putString("HandType", NBTHelper.writeEnum(handType)); + NBTHelper.writeEnum(tag, "HandType", handType); return tag; } @Override public void readNBT(World world, CompoundNBT tag) { facing = Direction.byIndex(tag.getInt("Facing")); - handType = NBTHelper.readEnum(tag.getString("HandType"), HandType.class); + handType = NBTHelper.readEnum(tag, "HandType", HandType.class); offset = tag.getInt("offset"); super.readNBT(world, tag); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java index 6aa84ae26..4f7b006c8 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java @@ -80,13 +80,13 @@ public class MountedContraption extends Contraption { @Override public CompoundNBT writeNBT() { CompoundNBT writeNBT = super.writeNBT(); - writeNBT.putString("RotationMode", NBTHelper.writeEnum(rotationMode)); + NBTHelper.writeEnum(writeNBT, "RotationMode", rotationMode); return writeNBT; } @Override public void readNBT(World world, CompoundNBT nbt) { - rotationMode = NBTHelper.readEnum(nbt.getString("RotationMode"), CartMovementMode.class); + rotationMode = NBTHelper.readEnum(nbt, "RotationMode", CartMovementMode.class); super.readNBT(world, nbt); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/Instruction.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/Instruction.java index 5a50fffc1..b28c352f2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/Instruction.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/Instruction.java @@ -88,16 +88,16 @@ public class Instruction { CompoundNBT serialize() { CompoundNBT tag = new CompoundNBT(); - tag.putString("Type", NBTHelper.writeEnum(instruction)); - tag.putString("Modifier", NBTHelper.writeEnum(speedModifier)); + NBTHelper.writeEnum(tag, "Type", instruction); + NBTHelper.writeEnum(tag, "Modifier", speedModifier); tag.putInt("Value", value); return tag; } static Instruction deserialize(CompoundNBT tag) { Instruction instruction = - new Instruction(NBTHelper.readEnum(tag.getString("Type"), SequencerInstructions.class)); - instruction.speedModifier = NBTHelper.readEnum(tag.getString("Modifier"), InstructionSpeedModifiers.class); + new Instruction(NBTHelper.readEnum(tag, "Type", SequencerInstructions.class)); + instruction.speedModifier = NBTHelper.readEnum(tag, "Modifier", InstructionSpeedModifiers.class); instruction.value = tag.getInt("Value"); return instruction; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltInventory.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltInventory.java index eeccc7c90..a839edc5d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltInventory.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltInventory.java @@ -352,8 +352,8 @@ public class BeltInventory { } public TransportedItemStack getStackAtOffset(int offset) { - float min = offset + .5f - (SEGMENT_WINDOW / 2); - float max = offset + .5f + (SEGMENT_WINDOW / 2); + float min = offset; + float max = offset + 1; for (TransportedItemStack stack : items) { if (stack.beltPosition > max) continue; diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripInteractionPacket.java b/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripInteractionPacket.java index e0f545027..63739b632 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripInteractionPacket.java +++ b/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripInteractionPacket.java @@ -57,6 +57,8 @@ public class ExtendoGripInteractionPacket extends SimplePacketBase { .enqueueWork(() -> { ServerPlayerEntity sender = context.get() .getSender(); + if (sender == null) + return; Entity entityByID = sender.getServerWorld() .getEntityByID(target); if (entityByID != null && ExtendoGripItem.isHoldingExtendoGrip(sender)) { diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/blockzapper/BlockzapperItem.java b/src/main/java/com/simibubi/create/content/curiosities/zapper/blockzapper/BlockzapperItem.java index b2d43c796..b06e9864f 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/blockzapper/BlockzapperItem.java +++ b/src/main/java/com/simibubi/create/content/curiosities/zapper/blockzapper/BlockzapperItem.java @@ -351,17 +351,16 @@ public class BlockzapperItem extends ZapperItem { .contains(component.name())) stack.getOrCreateTag() .putString(component.name(), ComponentTier.None.name()); - return NBTHelper.readEnum(stack.getTag() - .getString(component.name()), ComponentTier.class); + return NBTHelper.readEnum(stack.getTag(), component.name(), ComponentTier.class); } public static void setTier(Components component, ComponentTier tier, ItemStack stack) { - stack.getOrCreateTag() - .putString(component.name(), NBTHelper.writeEnum(tier)); + NBTHelper.writeEnum(stack.getOrCreateTag(), component.name(), tier); } public static enum ComponentTier { None(TextFormatting.DARK_GRAY), Brass(TextFormatting.GOLD), Chromatic(TextFormatting.LIGHT_PURPLE); + public TextFormatting color; private ComponentTier(TextFormatting color) { diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperItem.java b/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperItem.java index c3b375f8f..5a2117eb0 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperItem.java +++ b/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperItem.java @@ -53,7 +53,7 @@ public class WorldshaperItem extends ZapperItem { @Override protected boolean canActivateWithoutSelectedBlock(ItemStack stack) { CompoundNBT tag = stack.getOrCreateTag(); - TerrainTools tool = NBTHelper.readEnum(tag.getString("Tool"), TerrainTools.class); + TerrainTools tool = NBTHelper.readEnum(tag, "Tool", TerrainTools.class); return !tool.requiresSelectedBlock(); } @@ -65,11 +65,11 @@ public class WorldshaperItem extends ZapperItem { List affectedPositions = new ArrayList<>(); CompoundNBT tag = stack.getOrCreateTag(); - Brush brush = NBTHelper.readEnum(tag.getString("Brush"), TerrainBrushes.class) + Brush brush = NBTHelper.readEnum(tag, "Brush", TerrainBrushes.class) .get(); BlockPos params = NBTUtil.readBlockPos(tag.getCompound("BrushParams")); - PlacementOptions option = NBTHelper.readEnum(tag.getString("Placement"), PlacementOptions.class); - TerrainTools tool = NBTHelper.readEnum(tag.getString("Tool"), TerrainTools.class); + PlacementOptions option = NBTHelper.readEnum(tag, "Placement", PlacementOptions.class); + TerrainTools tool = NBTHelper.readEnum(tag, "Tool", TerrainTools.class); brush.set(params.getX(), params.getY(), params.getZ()); targetPos = targetPos.add(brush.getOffset(player.getLookVec(), raytrace.getFace(), option)); diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperRenderHandler.java b/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperRenderHandler.java index ca8522bb4..aa1c55b60 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperRenderHandler.java +++ b/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperRenderHandler.java @@ -69,9 +69,9 @@ public class WorldshaperRenderHandler { return; } - Brush brush = NBTHelper.readEnum(tag.getString("Brush"), TerrainBrushes.class) + Brush brush = NBTHelper.readEnum(tag, "Brush", TerrainBrushes.class) .get(); - PlacementOptions placement = NBTHelper.readEnum(tag.getString("Placement"), PlacementOptions.class); + PlacementOptions placement = NBTHelper.readEnum(tag, "Placement", PlacementOptions.class); BlockPos params = NBTUtil.readBlockPos(tag.getCompound("BrushParams")); brush.set(params.getX(), params.getY(), params.getZ()); renderedShape = brush.getIncludedPositions(); diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperScreen.java b/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperScreen.java index 351ee6dfe..f9d6ec474 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperScreen.java +++ b/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperScreen.java @@ -53,9 +53,12 @@ public class WorldshaperScreen extends ZapperScreen { brushLabel = new Label(i + 58, j + 28, "").withShadow(); brushInput = new SelectionScrollInput(i + 55, j + 25, 78, 14).forOptions(brushOptions) - .titled(Lang.translate("gui.terrainzapper.brush")).writingTo(brushLabel).calling(this::brushChanged); + .titled(Lang.translate("gui.terrainzapper.brush")) + .writingTo(brushLabel) + .calling(this::brushChanged); if (nbt.contains("Brush")) - brushInput.setState(NBTHelper.readEnum(nbt.getString("Brush"), TerrainBrushes.class).ordinal()); + brushInput.setState(NBTHelper.readEnum(nbt, "Brush", TerrainBrushes.class) + .ordinal()); widgets.add(brushLabel); widgets.add(brushInput); @@ -66,11 +69,13 @@ public class WorldshaperScreen extends ZapperScreen { for (int id = 0; id < toolValues.length; id++) { TerrainTools tool = toolValues[id]; toolButtons.add(new IconButton(i + 8 + id * 18, j + 76, tool.icon)); - toolButtons.get(id).setToolTip(Lang.translate("gui.terrainzapper.tool." + tool.translationKey)); + toolButtons.get(id) + .setToolTip(Lang.translate("gui.terrainzapper.tool." + tool.translationKey)); } if (nbt.contains("Tool")) - toolButtons.get(NBTHelper.readEnum(nbt.getString("Tool"), TerrainTools.class).ordinal()).active = false; + toolButtons.get(NBTHelper.readEnum(nbt, "Tool", TerrainTools.class) + .ordinal()).active = false; widgets.addAll(toolButtons); placementButtons = new Vector<>(3); @@ -78,21 +83,25 @@ public class WorldshaperScreen extends ZapperScreen { for (int id = 0; id < placementValues.length; id++) { PlacementOptions option = placementValues[id]; placementButtons.add(new IconButton(i + 147 + id * 18, j + 76, option.icon)); - placementButtons.get(id).setToolTip(Lang.translate("gui.terrainzapper.placement." + option.translationKey)); + placementButtons.get(id) + .setToolTip(Lang.translate("gui.terrainzapper.placement." + option.translationKey)); } if (nbt.contains("Placement")) - placementButtons - .get(NBTHelper.readEnum(nbt.getString("Placement"), PlacementOptions.class).ordinal()).active = - false; + placementButtons.get(NBTHelper.readEnum(nbt, "Placement", PlacementOptions.class) + .ordinal()).active = false; widgets.addAll(placementButtons); } public void initBrushParams() { if (brushParams != null) { - nbt.put("BrushParams", NBTUtil.writeBlockPos(new BlockPos(brushParams.get(0).getState(), - brushParams.get(1).getState(), brushParams.get(2).getState()))); + nbt.put("BrushParams", NBTUtil.writeBlockPos(new BlockPos(brushParams.get(0) + .getState(), + brushParams.get(1) + .getState(), + brushParams.get(2) + .getState()))); widgets.removeAll(brushParamLabels); widgets.removeAll(brushParams); @@ -109,10 +118,12 @@ public class WorldshaperScreen extends ZapperScreen { brushParamLabels.add(label); int indexFinal = index; ScrollInput input = new ScrollInput(i + 55 + 18 * index, j + 43, 14, 14) - .withRange(currentBrush.getMin(index), currentBrush.getMax(index) + 1).writingTo(label) - .titled(currentBrush.getParamLabel(index)).calling(state -> { - label.x = i + 62 + 18 * indexFinal - font.getStringWidth(label.text) / 2; - }); + .withRange(currentBrush.getMin(index), currentBrush.getMax(index) + 1) + .writingTo(label) + .titled(currentBrush.getParamLabel(index)) + .calling(state -> { + label.x = i + 62 + 18 * indexFinal - font.getStringWidth(label.text) / 2; + }); input.setState(params[index]); input.onChanged(); if (index >= currentBrush.amtParams) { @@ -140,7 +151,8 @@ public class WorldshaperScreen extends ZapperScreen { if (placementButton.isHovered()) { placementButtons.forEach(b -> b.active = true); placementButton.active = false; - placementButton.playDownSound(Minecraft.getInstance().getSoundHandler()); + placementButton.playDownSound(Minecraft.getInstance() + .getSoundHandler()); nbt.putString("Placement", PlacementOptions.values()[placementButtons.indexOf(placementButton)].name()); } } @@ -149,7 +161,8 @@ public class WorldshaperScreen extends ZapperScreen { if (toolButton.isHovered()) { toolButtons.forEach(b -> b.active = true); toolButton.active = false; - toolButton.playDownSound(Minecraft.getInstance().getSoundHandler()); + toolButton.playDownSound(Minecraft.getInstance() + .getSoundHandler()); nbt.putString("Tool", TerrainTools.values()[toolButtons.indexOf(toolButton)].name()); } } @@ -173,9 +186,13 @@ public class WorldshaperScreen extends ZapperScreen { @Override protected void writeAdditionalOptions(CompoundNBT nbt) { super.writeAdditionalOptions(nbt); - nbt.putString("Brush", NBTHelper.writeEnum(TerrainBrushes.values()[brushInput.getState()])); - nbt.put("BrushParams", NBTUtil.writeBlockPos(new BlockPos(brushParams.get(0).getState(), - brushParams.get(1).getState(), brushParams.get(2).getState()))); + NBTHelper.writeEnum(nbt, "Brush", TerrainBrushes.values()[brushInput.getState()]); + nbt.put("BrushParams", NBTUtil.writeBlockPos(new BlockPos(brushParams.get(0) + .getState(), + brushParams.get(1) + .getState(), + brushParams.get(2) + .getState()))); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotRenderer.java index 85100bbe6..4d428f935 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotRenderer.java @@ -39,12 +39,12 @@ public class DepotRenderer extends SafeTileEntityRenderer { msr.nudge(0); float offset = MathHelper.lerp(partialTicks, transported.prevBeltPosition, transported.beltPosition); float sideOffset = MathHelper.lerp(partialTicks, transported.prevSideOffset, transported.sideOffset); - Vec3d offsetVec = new Vec3d(transported.insertedFrom.getOpposite() - .getDirectionVec()).scale(.5f - offset); - ms.translate(offsetVec.x, offsetVec.y, offsetVec.z); if (transported.insertedFrom.getAxis() .isHorizontal()) { + Vec3d offsetVec = new Vec3d(transported.insertedFrom.getOpposite() + .getDirectionVec()).scale(.5f - offset); + ms.translate(offsetVec.x, offsetVec.y, offsetVec.z); boolean alongX = transported.insertedFrom.rotateY() .getAxis() == Axis.X; if (!alongX) diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotTileEntity.java index 343ab0567..c813c00c9 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotTileEntity.java @@ -84,6 +84,13 @@ public class DepotTileEntity extends SmartTileEntity { if (heldItem.locked != wasLocked || !previousItem.equals(heldItem.stack, false)) sendData(); } + + @Override + public void remove() { + super.remove(); + if (lazyItemHandler != null) + lazyItemHandler.invalidate(); + } @Override public CompoundNBT write(CompoundNBT compound) { diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmAngleTarget.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmAngleTarget.java new file mode 100644 index 000000000..fd1b94216 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmAngleTarget.java @@ -0,0 +1,77 @@ +package com.simibubi.create.content.logistics.block.mechanicalArm; + +import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; + +public class ArmAngleTarget { + + static ArmAngleTarget NO_TARGET = new ArmAngleTarget(); + + float baseAngle; + float lowerArmAngle; + float upperArmAngle; + float headAngle; + + private ArmAngleTarget() { + lowerArmAngle = 155; + upperArmAngle = 60; + headAngle = -15; + } + + public ArmAngleTarget(BlockPos armPos, Vec3d pointTarget, Direction clawFacing) { + Vec3d target = pointTarget; + Vec3d origin = VecHelper.getCenterOf(armPos) + .add(0, 4 / 16f, 0); + Vec3d clawTarget = target; + target = target.add(new Vec3d(clawFacing.getOpposite() + .getDirectionVec()).scale(.5f)); + + Vec3d diff = target.subtract(origin); + float horizontalDistance = (float) diff.mul(1, 0, 1) + .length(); + + float baseAngle = AngleHelper.deg(MathHelper.atan2(diff.x, diff.z)) + 180; + float alphaOffset = AngleHelper.deg(MathHelper.atan2(diff.y, horizontalDistance)); + + float a = 18 / 16f; // lower arm length + float a2 = a * a; + float b = 17 / 16f; // upper arm length + float b2 = b * b; + float diffLength = + MathHelper.clamp(MathHelper.sqrt(diff.y * diff.y + horizontalDistance * horizontalDistance), 1 / 8f, a + b); + float diffLength2 = diffLength * diffLength; + + float alphaRatio = (-b2 + a2 + diffLength2) / (2 * a * diffLength); + float alpha = AngleHelper.deg(Math.acos(alphaRatio)) + alphaOffset; + float betaRatio = (-diffLength2 + a2 + b2) / (2 * b * a); + float beta = AngleHelper.deg(Math.acos(betaRatio)); + + if (Float.isNaN(alpha)) + alpha = 0; + if (Float.isNaN(beta)) + beta = 0; + + Vec3d headPos = new Vec3d(0, 0, 0); + 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 = headPos.add(origin); + Vec3d headDiff = clawTarget.subtract(headPos); + float horizontalHeadDistance = (float) headDiff.mul(1, 0, 1) + .length(); + float headAngle = + (float) (alpha + beta + 135 - AngleHelper.deg(MathHelper.atan2(headDiff.y, horizontalHeadDistance))); + + this.lowerArmAngle = alpha; + this.upperArmAngle = beta; + this.headAngle = -headAngle; + this.baseAngle = baseAngle; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmBlock.java index 2f840700c..a266435e3 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmBlock.java @@ -6,18 +6,13 @@ import com.simibubi.create.content.contraptions.base.KineticBlock; import com.simibubi.create.foundation.block.ITE; import net.minecraft.block.BlockState; -import net.minecraft.entity.player.PlayerEntity; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.ActionResultType; import net.minecraft.util.Direction.Axis; -import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.shapes.ISelectionContext; import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.IBlockReader; import net.minecraft.world.IWorldReader; -import net.minecraft.world.World; public class ArmBlock extends KineticBlock implements ITE { @@ -30,14 +25,6 @@ public class ArmBlock extends KineticBlock implements ITE { return true; } - @Override - public ActionResultType onUse(BlockState p_225533_1_, World p_225533_2_, BlockPos p_225533_3_, - PlayerEntity p_225533_4_, Hand p_225533_5_, BlockRayTraceResult p_225533_6_) { - withTileEntityDo(p_225533_2_, p_225533_3_, ArmTileEntity::toggleRave); - return ActionResultType.SUCCESS; - } - - @Override public VoxelShape getShape(BlockState p_220053_1_, IBlockReader p_220053_2_, BlockPos p_220053_3_, ISelectionContext p_220053_4_) { diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPoint.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPoint.java new file mode 100644 index 000000000..1d844ec5c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPoint.java @@ -0,0 +1,234 @@ +package com.simibubi.create.content.logistics.block.mechanicalArm; + +import javax.annotation.Nullable; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.logistics.block.realityFunnel.RealityFunnelBlock; +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; +import com.simibubi.create.foundation.utility.NBTHelper; +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.block.BlockState; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; + +public abstract class ArmInteractionPoint { + + static enum Mode { + DEPOSIT, TAKE + } + + BlockPos pos; + BlockState state; + Mode mode; + + private LazyOptional cachedHandler; + private ArmAngleTarget cachedAngles; + + public ArmInteractionPoint() { + cachedHandler = LazyOptional.empty(); + } + + @OnlyIn(Dist.CLIENT) + void transformFlag(MatrixStack stack) {} + + AllBlockPartials getFlagType() { + return mode == Mode.TAKE ? AllBlockPartials.FLAG_LONG_OUT : AllBlockPartials.FLAG_LONG_IN; + } + + void cycleMode() { + mode = mode == Mode.DEPOSIT ? Mode.TAKE : Mode.DEPOSIT; + } + + Vec3d getInteractionPositionVector() { + return VecHelper.getCenterOf(pos); + } + + Direction getInteractionDirection() { + return Direction.DOWN; + } + + abstract boolean isValid(BlockState state); + + static boolean isInteractable(BlockState state) { + return AllBlocks.DEPOT.has(state) || AllBlocks.BELT.has(state) || AllBlocks.CHUTE.has(state) + || AllBlocks.REALITY_FUNNEL.has(state); + } + + ArmAngleTarget getTargetAngles(BlockPos armPos) { + if (cachedAngles == null) + cachedAngles = new ArmAngleTarget(armPos, getInteractionPositionVector(), getInteractionDirection()); + return cachedAngles; + } + + @Nullable + IItemHandler getHandler(World world) { + if (!cachedHandler.isPresent()) { + TileEntity te = world.getTileEntity(pos); + if (te == null) + return null; + cachedHandler = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, Direction.UP); + } + return cachedHandler.orElse(null); + } + + ItemStack insert(World world, ItemStack stack, boolean simulate) { + IItemHandler handler = getHandler(world); + if (handler == null) + return stack; + return ItemHandlerHelper.insertItem(handler, stack, simulate); + } + + ItemStack extract(World world, int slot, int amount, boolean simulate) { + IItemHandler handler = getHandler(world); + if (handler == null) + return ItemStack.EMPTY; + return handler.extractItem(slot, amount, simulate); + } + + ItemStack extract(World world, int slot, boolean simulate) { + return extract(world, slot, 64, simulate); + } + + int getSlotCount(World world) { + IItemHandler handler = getHandler(world); + if (handler == null) + return 0; + return handler.getSlots(); + } + + @Nullable + static ArmInteractionPoint createAt(IBlockReader world, BlockPos pos) { + BlockState state = world.getBlockState(pos); + ArmInteractionPoint point = null; + + if (AllBlocks.DEPOT.has(state)) + point = new Depot(); + if (AllBlocks.BELT.has(state)) + point = new Belt(); + if (AllBlocks.CHUTE.has(state)) + point = new Chute(); + if (AllBlocks.REALITY_FUNNEL.has(state)) + point = new Funnel(); + + if (point != null) { + point.state = state; + point.pos = pos; + point.mode = Mode.DEPOSIT; + } + + return point; + } + + CompoundNBT serialize() { + CompoundNBT nbt = new CompoundNBT(); + nbt.put("Pos", NBTUtil.writeBlockPos(pos)); + NBTHelper.writeEnum(nbt, "Mode", mode); + return nbt; + } + + static ArmInteractionPoint deserialize(IBlockReader world, CompoundNBT nbt) { + BlockPos pos = NBTUtil.readBlockPos(nbt.getCompound("Pos")); + ArmInteractionPoint interactionPoint = createAt(world, pos); + interactionPoint.mode = NBTHelper.readEnum(nbt, "Mode", Mode.class); + return interactionPoint; + } + + static class Depot extends ArmInteractionPoint { + + @Override + Vec3d getInteractionPositionVector() { + return new Vec3d(pos).add(.5f, 14 / 16f, .5f); + } + + @Override + boolean isValid(BlockState state) { + return AllBlocks.DEPOT.has(state); + } + + } + + static class Belt extends Depot { + + @Override + boolean isValid(BlockState state) { + return AllBlocks.BELT.has(state); + } + } + + static class Chute extends ArmInteractionPoint { + + @Override + Vec3d getInteractionPositionVector() { + return new Vec3d(pos).add(.5f, 1, .5f); + } + + @Override + boolean isValid(BlockState state) { + return AllBlocks.CHUTE.has(state); + } + } + + static class Funnel extends ArmInteractionPoint { + + @Override + Vec3d getInteractionPositionVector() { + return VecHelper.getCenterOf(pos) + .add(new Vec3d(RealityFunnelBlock.getFunnelFacing(state) + .getDirectionVec()).scale(.5f)); + } + + @Override + int getSlotCount(World world) { + return 0; + } + + @Override + ItemStack extract(World world, int slot, int amount, boolean simulate) { + return ItemStack.EMPTY; + } + + @Override + Direction getInteractionDirection() { + return RealityFunnelBlock.getFunnelFacing(state).getOpposite(); + } + + @Override + ItemStack insert(World world, ItemStack stack, boolean simulate) { + FilteringBehaviour filtering = TileEntityBehaviour.get(world, pos, FilteringBehaviour.TYPE); + InsertingBehaviour inserter = TileEntityBehaviour.get(world, pos, InsertingBehaviour.TYPE); + if (inserter == null) + return stack; + if (filtering != null && !filtering.test(stack)) + return stack; + return inserter.insert(stack, simulate); + } + + @Override + boolean isValid(BlockState state) { + return AllBlocks.REALITY_FUNNEL.has(state); + } + + @Override + void cycleMode() {} + + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPointHandler.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPointHandler.java new file mode 100644 index 000000000..16dc97a97 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPointHandler.java @@ -0,0 +1,115 @@ +package com.simibubi.create.content.logistics.block.mechanicalArm; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.CreateClient; +import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Mode; +import com.simibubi.create.foundation.networking.AllPackets; + +import net.minecraft.block.BlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; + +@EventBusSubscriber(value = Dist.CLIENT) +public class ArmInteractionPointHandler { + + static Map currentSelection = new HashMap<>(); + static ItemStack currentItem; + + @SubscribeEvent + public static void rightClickingBlocksSelectsThem(PlayerInteractEvent.RightClickBlock event) { + if (currentItem == null) + return; + BlockPos pos = event.getPos(); + World world = event.getWorld(); + if (!world.isRemote) + return; + + if (!currentSelection.containsKey(pos)) { + ArmInteractionPoint point = ArmInteractionPoint.createAt(world, pos); + if (point == null) + return; + currentSelection.put(pos, point); + } + + currentSelection.get(pos) + .cycleMode(); + event.setCanceled(true); + event.setCancellationResult(ActionResultType.SUCCESS); + } + + @SubscribeEvent + public static void leftClickingBlocksDeselectsThem(PlayerInteractEvent.LeftClickBlock event) { + if (currentItem == null) + return; + if (!event.getWorld().isRemote) + return; + BlockPos pos = event.getPos(); + if (currentSelection.remove(pos) != null) { + event.setCanceled(true); + event.setCancellationResult(ActionResultType.SUCCESS); + } + } + + public static void flushSettings(BlockPos pos) { + if (currentItem == null) + return; + AllPackets.channel.sendToServer(new ArmPlacementPacket(currentSelection.values(), pos)); + currentSelection.clear(); + currentItem = null; + } + + public static void tick() { + PlayerEntity player = Minecraft.getInstance().player; + World world = Minecraft.getInstance().world; + if (player == null) + return; + + ItemStack heldItemMainhand = player.getHeldItemMainhand(); + if (!AllBlocks.MECHANICAL_ARM.isIn(heldItemMainhand)) { + currentItem = null; + return; + } + if (heldItemMainhand != currentItem) { + currentSelection.clear(); + currentItem = heldItemMainhand; + } + + for (Iterator> iterator = currentSelection.entrySet() + .iterator(); iterator.hasNext();) { + Entry entry = iterator.next(); + BlockPos pos = entry.getKey(); + BlockState state = world.getBlockState(pos); + ArmInteractionPoint point = entry.getValue(); + + if (!point.isValid(state)) { + iterator.remove(); + continue; + } + + VoxelShape shape = state.getShape(world, pos); + if (shape.isEmpty()) + continue; + + int color = point.mode == Mode.DEPOSIT ? 0xffcb74 : 0x4f8a8b; + CreateClient.outliner.showAABB(point, shape.getBoundingBox() + .offset(pos)) + .colored(color) + .lineWidth(1 / 16f); + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmItem.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmItem.java new file mode 100644 index 000000000..a459fea8c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmItem.java @@ -0,0 +1,45 @@ +package com.simibubi.create.content.logistics.block.mechanicalArm; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.BlockItem; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUseContext; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; + +@EventBusSubscriber +public class ArmItem extends BlockItem { + + public ArmItem(Block p_i48527_1_, Properties p_i48527_2_) { + super(p_i48527_1_, p_i48527_2_); + } + + @Override + public ActionResultType onItemUse(ItemUseContext ctx) { + if (ArmInteractionPoint.isInteractable(ctx.getWorld() + .getBlockState(ctx.getPos()))) + return ActionResultType.SUCCESS; + return super.onItemUse(ctx); + } + + @Override + protected boolean onBlockPlaced(BlockPos pos, World world, PlayerEntity p_195943_3_, ItemStack p_195943_4_, + BlockState p_195943_5_) { + if (world.isRemote) + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> ArmInteractionPointHandler.flushSettings(pos)); + return super.onBlockPlaced(pos, world, p_195943_3_, p_195943_4_, p_195943_5_); + } + + @Override + public boolean canPlayerBreakBlockWhileHolding(BlockState state, World p_195938_2_, BlockPos p_195938_3_, + PlayerEntity p_195938_4_) { + return !ArmInteractionPoint.isInteractable(state); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmPlacementPacket.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmPlacementPacket.java new file mode 100644 index 000000000..dcc51b7f7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmPlacementPacket.java @@ -0,0 +1,70 @@ +package com.simibubi.create.content.logistics.block.mechanicalArm; + +import java.util.Collection; +import java.util.function.Supplier; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.network.PacketBuffer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.common.util.Constants.NBT; +import net.minecraftforge.fml.network.NetworkEvent.Context; + +public class ArmPlacementPacket extends SimplePacketBase { + + private Collection points; + private ListNBT receivedTag; + private BlockPos pos; + + public ArmPlacementPacket(Collection points, BlockPos pos) { + this.points = points; + this.pos = pos; + } + + public ArmPlacementPacket(PacketBuffer buffer) { + CompoundNBT nbt = buffer.readCompoundTag(); + receivedTag = nbt.getList("Points", NBT.TAG_COMPOUND); + pos = buffer.readBlockPos(); + } + + @Override + public void write(PacketBuffer buffer) { + CompoundNBT nbt = new CompoundNBT(); + ListNBT pointsNBT = new ListNBT(); + points.stream() + .map(ArmInteractionPoint::serialize) + .forEach(pointsNBT::add); + nbt.put("Points", pointsNBT); + buffer.writeCompoundTag(nbt); + buffer.writeBlockPos(pos); + } + + @Override + public void handle(Supplier context) { + context.get() + .enqueueWork(() -> { + ServerPlayerEntity player = context.get() + .getSender(); + if (player == null) + return; + World world = player.world; + if (world == null) + return; + TileEntity tileEntity = world.getTileEntity(pos); + if (tileEntity == null || !(tileEntity instanceof ArmTileEntity)) + return; + + ArmTileEntity arm = (ArmTileEntity) tileEntity; + arm.interactionPointTag = receivedTag; + }); + context.get() + .setPacketHandled(true); + + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java index dd281191a..e9fc9ad50 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java @@ -5,17 +5,19 @@ 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.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; import net.minecraft.block.BlockState; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.ItemRenderer; import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; -import net.minecraft.util.math.MathHelper; +import net.minecraft.item.BlockItem; +import net.minecraft.item.ItemStack; public class ArmRenderer extends KineticTileEntityRenderer { @@ -24,25 +26,15 @@ public class ArmRenderer extends KineticTileEntityRenderer { } @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, - int light, int overlay) { - super.renderSafe(te, partialTicks, ms, buffer, light, overlay); + protected void renderSafe(KineticTileEntity te, float pt, MatrixStack ms, IRenderTypeBuffer buffer, int light, + int overlay) { + super.renderSafe(te, pt, ms, buffer, light, overlay); + ArmTileEntity arm = (ArmTileEntity) te; IVertexBuilder builder = buffer.getBuffer(RenderType.getSolid()); BlockState blockState = te.getBlockState(); MatrixStacker msr = MatrixStacker.of(ms); - - float angle = 0; - float clawAngle = -25; - float otherAngle = 0; int color = 0xFFFFFF; - - boolean rave = te instanceof ArmTileEntity && ((ArmTileEntity) te).debugRave; - if (rave) { - clawAngle = angle = MathHelper.lerp((MathHelper.sin(AnimationTickHolder.getRenderTick() / 2) + 1) / 2, -45, 15); - otherAngle = MathHelper.lerp((MathHelper.sin(AnimationTickHolder.getRenderTick() / 4) + 1) / 2, -95, 95); - color = ColorHelper.rainbowColor(AnimationTickHolder.ticks * 100); - } - + ms.push(); SuperByteBuffer base = AllBlockPartials.ARM_BASE.renderOn(blockState); @@ -55,33 +47,51 @@ public class ArmRenderer extends KineticTileEntityRenderer { msr.centre(); ms.translate(0, 4 / 16d, 0); - msr.rotateY(rave ? AnimationTickHolder.getRenderTick() * 10 : 0); + msr.rotateY(arm.baseAngle.get(pt)); base.renderInto(ms, builder); ms.translate(0, 1 / 16d, -2 / 16d); - msr.rotateX(angle); + msr.rotateX(arm.lowerArmAngle.get(pt) - 135); ms.translate(0, -1 / 16d, 0); - lowerBody.color(color).renderInto(ms, builder); - + lowerBody.color(color) + .renderInto(ms, builder); + ms.translate(0, 12 / 16d, 12 / 16d); - msr.rotateX(-otherAngle / 2f); - upperBody.color(color).renderInto(ms, builder); - + msr.rotateX(arm.upperArmAngle.get(pt) - 90); + upperBody.color(color) + .renderInto(ms, builder); + ms.translate(0, 11 / 16d, -11 / 16d); - msr.rotateX(-angle); + msr.rotateX(arm.headAngle.get(pt)); head.renderInto(ms, builder); - + ms.translate(0, 0, -4 / 16d); claw.renderInto(ms, builder); + ItemStack item = arm.heldItem; + ItemRenderer itemRenderer = Minecraft.getInstance() + .getItemRenderer(); + boolean hasItem = !item.isEmpty(); + boolean isBlockItem = hasItem && (item.getItem() instanceof BlockItem) + && itemRenderer.getItemModelWithOverrides(item, Minecraft.getInstance().world, null) + .isGui3d(); for (int flip : Iterate.positiveAndNegative) { ms.push(); ms.translate(0, flip * 3 / 16d, -1 / 16d); - msr.rotateX(flip * clawAngle); + msr.rotateX(flip * (hasItem ? isBlockItem ? 0 : -35 : 0)); clawGrip.renderInto(ms, builder); ms.pop(); } + if (hasItem) { + float itemScale = isBlockItem ? .5f : .625f; + msr.rotateX(90); + ms.translate(0, -4 / 16f, 0); + ms.scale(itemScale, itemScale, itemScale); + itemRenderer + .renderItem(item, TransformType.FIXED, light, overlay, ms, buffer); + } + ms.pop(); } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java index 30ba76250..9bc84fb21 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java @@ -1,45 +1,297 @@ package com.simibubi.create.content.logistics.block.mechanicalArm; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import java.util.ArrayList; +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.Mode; +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.item.ItemStack; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.INBT; +import net.minecraft.nbt.ListNBT; import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.math.MathHelper; +import net.minecraftforge.common.util.Constants.NBT; public class ArmTileEntity extends KineticTileEntity { - boolean debugRave; - - public ArmTileEntity(TileEntityType typeIn) { - super(typeIn); - } - - @Override - public void lazyTick() { - if (hasWorld()) - if (world.rand.nextInt(100) == 0) - toggleRave(); - super.lazyTick(); + // Server + List inputs; + List outputs; + ListNBT interactionPointTag; + + // Both + float chasedPointProgress; + int chasedPointIndex; + ItemStack heldItem; + Phase phase; + + // Client + ArmAngleTarget previousTarget; + InterpolatedAngle lowerArmAngle; + InterpolatedAngle upperArmAngle; + InterpolatedAngle baseAngle; + InterpolatedAngle headAngle; + InterpolatedAngle clawAngle; + float previousBaseAngle; + boolean updateInteractionPoints; + + enum Phase { + SEARCH_INPUTS, MOVE_TO_INPUT, SEARCH_OUTPUTS, MOVE_TO_OUTPUT, IDLE } - public void toggleRave() { + public ArmTileEntity(TileEntityType typeIn) { + super(typeIn); + inputs = new ArrayList<>(); + outputs = new ArrayList<>(); + heldItem = ItemStack.EMPTY; + phase = Phase.SEARCH_INPUTS; + baseAngle = new InterpolatedAngle(); + lowerArmAngle = new InterpolatedAngle(); + upperArmAngle = new InterpolatedAngle(); + headAngle = new InterpolatedAngle(); + clawAngle = new InterpolatedAngle(); + previousTarget = ArmAngleTarget.NO_TARGET; + previousBaseAngle = previousTarget.baseAngle; + updateInteractionPoints = true; + } + + @Override + public void tick() { + super.tick(); + initInteractionPoints(); + tickMovementProgress(); + if (world.isRemote) return; - debugRave = !debugRave; + if (chasedPointProgress < 1) + return; + if (phase == Phase.MOVE_TO_INPUT) + collectItem(); + if (phase == Phase.MOVE_TO_OUTPUT) + depositItem(); + } + + @Override + public void lazyTick() { + super.lazyTick(); + + if (world.isRemote) + return; + if (chasedPointProgress < .5f) + return; + if (phase == Phase.SEARCH_INPUTS) + searchForItem(); + if (phase == Phase.SEARCH_OUTPUTS) + searchForDestination(); + } + + private void tickMovementProgress() { + chasedPointProgress += Math.min(256, Math.abs(getSpeed())) / 1024f; + if (chasedPointProgress > 1) + chasedPointProgress = 1; + if (!world.isRemote) + return; + + ArmInteractionPoint targetedInteractionPoint = getTargetedInteractionPoint(); + ArmAngleTarget previousTarget = this.previousTarget; + ArmAngleTarget target = + targetedInteractionPoint == null ? ArmAngleTarget.NO_TARGET : targetedInteractionPoint.getTargetAngles(pos); + + baseAngle.set(AngleHelper.angleLerp(chasedPointProgress, previousBaseAngle, + target == ArmAngleTarget.NO_TARGET ? previousBaseAngle : target.baseAngle)); + + // Arm's angles first backup to resting position and then continue + if (chasedPointProgress < .5f) + target = ArmAngleTarget.NO_TARGET; + else + previousTarget = ArmAngleTarget.NO_TARGET; + float progress = chasedPointProgress == 1 ? 1 : (chasedPointProgress % .5f) * 2; + + 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)); + } + + @Nullable + private ArmInteractionPoint getTargetedInteractionPoint() { + if (chasedPointIndex == -1) + return null; + if (phase == Phase.MOVE_TO_INPUT && chasedPointIndex < inputs.size()) + return inputs.get(chasedPointIndex); + if (phase == Phase.MOVE_TO_OUTPUT && chasedPointIndex < outputs.size()) + return outputs.get(chasedPointIndex); + return null; + } + + protected void searchForItem() { + for (int index = 0; index < inputs.size(); index++) { + ArmInteractionPoint armInteractionPoint = inputs.get(index); + for (int i = 0; i < armInteractionPoint.getSlotCount(world); i++) { + if (getDistributableAmount(armInteractionPoint, i) == 0) + continue; + + phase = Phase.MOVE_TO_INPUT; + chasedPointIndex = index; + chasedPointProgress = 0; + sendData(); + markDirty(); + return; + } + } + } + + protected void searchForDestination() { + ItemStack held = heldItem.copy(); + for (int index = 0; index < outputs.size(); index++) { + ArmInteractionPoint armInteractionPoint = outputs.get(index); + ItemStack remainder = armInteractionPoint.insert(world, held, true); + if (remainder.equals(heldItem, false)) + continue; + + phase = Phase.MOVE_TO_OUTPUT; + chasedPointIndex = index; + chasedPointProgress = 0; + sendData(); + markDirty(); + return; + } + } + + protected int getDistributableAmount(ArmInteractionPoint armInteractionPoint, int i) { + ItemStack stack = armInteractionPoint.extract(world, i, true); + ItemStack remainder = simulateInsertion(stack); + return stack.getCount() - remainder.getCount(); + } + + protected void depositItem() { + ArmInteractionPoint armInteractionPoint = getTargetedInteractionPoint(); + ItemStack toInsert = heldItem.copy(); + ItemStack remainder = armInteractionPoint.insert(world, toInsert, false); + heldItem = remainder; + phase = heldItem.isEmpty() ? Phase.SEARCH_INPUTS : Phase.SEARCH_OUTPUTS; + chasedPointProgress = 0; + chasedPointIndex = -1; + sendData(); + markDirty(); + } + + protected void collectItem() { + ArmInteractionPoint armInteractionPoint = getTargetedInteractionPoint(); + for (int i = 0; i < armInteractionPoint.getSlotCount(world); i++) { + int amountExtracted = getDistributableAmount(armInteractionPoint, i); + if (amountExtracted == 0) + continue; + + heldItem = armInteractionPoint.extract(world, i, amountExtracted, false); + phase = Phase.SEARCH_OUTPUTS; + chasedPointProgress = 0; + chasedPointIndex = -1; + sendData(); + markDirty(); + return; + } + + phase = Phase.SEARCH_INPUTS; + chasedPointProgress = 0; + chasedPointIndex = -1; + sendData(); + markDirty(); + } + + private ItemStack simulateInsertion(ItemStack stack) { + for (ArmInteractionPoint armInteractionPoint : outputs) { + stack = armInteractionPoint.insert(world, stack, true); + if (stack.isEmpty()) + break; + } + return stack; + } + + protected void initInteractionPoints() { + if (interactionPointTag == null) + return; + inputs.clear(); + outputs.clear(); + for (INBT inbt : interactionPointTag) { + ArmInteractionPoint point = ArmInteractionPoint.deserialize(world, (CompoundNBT) inbt); + if (point.mode == Mode.DEPOSIT) + outputs.add(point); + if (point.mode == Mode.TAKE) + inputs.add(point); + } + interactionPointTag = null; markDirty(); sendData(); } - + @Override public CompoundNBT write(CompoundNBT compound) { super.write(compound); - compound.putBoolean("DebugRave", debugRave); + + ListNBT pointsNBT = new ListNBT(); + inputs.stream() + .map(ArmInteractionPoint::serialize) + .forEach(pointsNBT::add); + outputs.stream() + .map(ArmInteractionPoint::serialize) + .forEach(pointsNBT::add); + + NBTHelper.writeEnum(compound, "Phase", phase); + compound.put("InterationPoints", pointsNBT); + compound.put("HeldItem", heldItem.serializeNBT()); + compound.putInt("TargetPointIndex", chasedPointIndex); + compound.putFloat("MovementProgress", chasedPointProgress); return compound; } - + + @Override + public CompoundNBT writeToClient(CompoundNBT compound) { + super.writeToClient(compound); + if (interactionPointTag != null) + compound.put("InitialInterationPoints", interactionPointTag); + return compound; + } + @Override public void read(CompoundNBT compound) { super.read(compound); - debugRave = compound.getBoolean("DebugRave"); + heldItem = ItemStack.read(compound.getCompound("HeldItem")); + phase = NBTHelper.readEnum(compound, "Phase", Phase.class); + chasedPointIndex = compound.getInt("TargetPointIndex"); + chasedPointProgress = compound.getFloat("MovementProgress"); + + if (!hasWorld() || !world.isRemote || updateInteractionPoints) + interactionPointTag = compound.getList("InterationPoints", NBT.TAG_COMPOUND); + updateInteractionPoints = false; + } + + @Override + public void readClientUpdate(CompoundNBT tag) { + int previousIndex = chasedPointIndex; + Phase previousPhase = phase; + + super.readClientUpdate(tag); + + if (previousIndex != chasedPointIndex || (previousPhase != phase)) { + ArmInteractionPoint previousPoint = null; + if (previousPhase == Phase.MOVE_TO_INPUT && previousIndex < inputs.size()) + 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); + if (previousPoint != null) + previousBaseAngle = previousPoint.getTargetAngles(pos).baseAngle; + } + + if (tag.contains("InitialInterationPoints")) + interactionPointTag = tag.getList("InitialInterationPoints", NBT.TAG_COMPOUND); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterScreenPacket.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterScreenPacket.java index e3c7808cd..8d49abeb4 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterScreenPacket.java +++ b/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterScreenPacket.java @@ -43,7 +43,9 @@ public class FilterScreenPacket extends SimplePacketBase { public void handle(Supplier context) { context.get().enqueueWork(() -> { ServerPlayerEntity player = context.get().getSender(); - + if (player == null) + return; + if (player.openContainer instanceof AbstractFilterContainer) { AbstractFilterContainer c = (AbstractFilterContainer) player.openContainer; if (option == Option.CLEAR) { diff --git a/src/main/java/com/simibubi/create/content/schematics/packet/ConfigureSchematicannonPacket.java b/src/main/java/com/simibubi/create/content/schematics/packet/ConfigureSchematicannonPacket.java index f8f9a1e93..c69f1f822 100644 --- a/src/main/java/com/simibubi/create/content/schematics/packet/ConfigureSchematicannonPacket.java +++ b/src/main/java/com/simibubi/create/content/schematics/packet/ConfigureSchematicannonPacket.java @@ -49,6 +49,8 @@ public class ConfigureSchematicannonPacket extends SimplePacketBase { public void handle(Supplier context) { context.get().enqueueWork(() -> { ServerPlayerEntity player = context.get().getSender(); + if (player == null) + return; World world = player.world; if (world == null) return; diff --git a/src/main/java/com/simibubi/create/content/schematics/packet/SchematicPlacePacket.java b/src/main/java/com/simibubi/create/content/schematics/packet/SchematicPlacePacket.java index 4f907675f..869f966f1 100644 --- a/src/main/java/com/simibubi/create/content/schematics/packet/SchematicPlacePacket.java +++ b/src/main/java/com/simibubi/create/content/schematics/packet/SchematicPlacePacket.java @@ -32,6 +32,8 @@ public class SchematicPlacePacket extends SimplePacketBase { public void handle(Supplier context) { context.get().enqueueWork(() -> { ServerPlayerEntity player = context.get().getSender(); + if (player == null) + return; Template t = SchematicItem.loadSchematic(stack); PlacementSettings settings = SchematicItem.getSettings(stack); settings.setIgnoreEntities(false); diff --git a/src/main/java/com/simibubi/create/content/schematics/packet/SchematicUploadPacket.java b/src/main/java/com/simibubi/create/content/schematics/packet/SchematicUploadPacket.java index 447745bd5..b8c37ac39 100644 --- a/src/main/java/com/simibubi/create/content/schematics/packet/SchematicUploadPacket.java +++ b/src/main/java/com/simibubi/create/content/schematics/packet/SchematicUploadPacket.java @@ -68,6 +68,8 @@ public class SchematicUploadPacket extends SimplePacketBase { .enqueueWork(() -> { ServerPlayerEntity player = context.get() .getSender(); + if (player == null) + return; if (code == BEGIN) { BlockPos pos = ((SchematicTableContainer) player.openContainer).getTileEntity() .getPos(); diff --git a/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedAngle.java b/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedAngle.java new file mode 100644 index 000000000..d8dd660e8 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedAngle.java @@ -0,0 +1,11 @@ +package com.simibubi.create.foundation.gui.widgets; + +import com.simibubi.create.foundation.utility.AngleHelper; + +public class InterpolatedAngle extends InterpolatedValue { + + public float get(float partialTicks) { + return AngleHelper.angleLerp(partialTicks, lastValue, value); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedChasingAngle.java b/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedChasingAngle.java index 3dc30905e..b9f4f1cc2 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedChasingAngle.java +++ b/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedChasingAngle.java @@ -4,6 +4,10 @@ import com.simibubi.create.foundation.utility.AngleHelper; public class InterpolatedChasingAngle extends InterpolatedChasingValue { + public float get(float partialTicks) { + return AngleHelper.angleLerp(partialTicks, lastValue, value); + } + @Override protected float getCurrentDiff() { return AngleHelper.getShortestAngleDiff(value, getTarget()); diff --git a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java index 40a1376d2..141a0499c 100644 --- a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java +++ b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java @@ -12,6 +12,7 @@ import com.simibubi.create.content.contraptions.relays.advanced.sequencer.Config import com.simibubi.create.content.curiosities.symmetry.SymmetryEffectPacket; import com.simibubi.create.content.curiosities.tools.ExtendoGripInteractionPacket; import com.simibubi.create.content.curiosities.zapper.ZapperBeamPacket; +import com.simibubi.create.content.logistics.block.mechanicalArm.ArmPlacementPacket; import com.simibubi.create.content.logistics.item.filter.FilterScreenPacket; import com.simibubi.create.content.logistics.packet.ConfigureFlexcratePacket; import com.simibubi.create.content.logistics.packet.ConfigureStockswitchPacket; @@ -44,6 +45,7 @@ public enum AllPackets { CONFIGURE_SCROLLABLE(ScrollValueUpdatePacket.class, ScrollValueUpdatePacket::new), CANCEL_FALL(CancelPlayerFallPacket.class, CancelPlayerFallPacket::new), EXTENDO_INTERACT(ExtendoGripInteractionPacket.class, ExtendoGripInteractionPacket::new), + PLACE_ARM(ArmPlacementPacket.class, ArmPlacementPacket::new), // Server to Client SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new), diff --git a/src/main/java/com/simibubi/create/foundation/networking/NbtPacket.java b/src/main/java/com/simibubi/create/foundation/networking/NbtPacket.java index e03a3fa5c..2ea47f60a 100644 --- a/src/main/java/com/simibubi/create/foundation/networking/NbtPacket.java +++ b/src/main/java/com/simibubi/create/foundation/networking/NbtPacket.java @@ -40,6 +40,8 @@ public class NbtPacket extends SimplePacketBase { public void handle(Supplier context) { context.get().enqueueWork(() -> { ServerPlayerEntity player = context.get().getSender(); + if (player == null) + return; if (slot == -1) { ItemStack heldItem = player.getHeldItem(hand); diff --git a/src/main/java/com/simibubi/create/foundation/networking/TileEntityConfigurationPacket.java b/src/main/java/com/simibubi/create/foundation/networking/TileEntityConfigurationPacket.java index 0d8da4d47..ba3bd1f3b 100644 --- a/src/main/java/com/simibubi/create/foundation/networking/TileEntityConfigurationPacket.java +++ b/src/main/java/com/simibubi/create/foundation/networking/TileEntityConfigurationPacket.java @@ -35,6 +35,8 @@ public abstract class TileEntityConfigurationPacket public void handle(Supplier context) { context.get().enqueueWork(() -> { ServerPlayerEntity player = context.get().getSender(); + if (player == null) + return; World world = player.world; if (world == null || world.getTileEntity(pos) == null) diff --git a/src/main/java/com/simibubi/create/foundation/utility/NBTHelper.java b/src/main/java/com/simibubi/create/foundation/utility/NBTHelper.java index 2c971b671..6a08a3c62 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/NBTHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/NBTHelper.java @@ -12,8 +12,9 @@ import net.minecraft.util.math.AxisAlignedBB; public class NBTHelper { - public static > T readEnum(String name, Class enumClass) { + public static > T readEnum(CompoundNBT nbt, String key, Class enumClass) { T[] enumConstants = enumClass.getEnumConstants(); + String name = nbt.getString(key); if (enumConstants == null) throw new IllegalArgumentException("Non-Enum class passed to readEnum(): " + enumClass.getName()); for (T t : enumConstants) { @@ -22,11 +23,11 @@ public class NBTHelper { } return enumConstants[0]; } - - public static > String writeEnum(T enumConstant) { - return enumConstant.name(); + + public static > void writeEnum(CompoundNBT nbt, String key, T enumConstant) { + nbt.putString(key, enumConstant.name()); } - + public static ListNBT writeCompoundList(List list, Function serializer) { ListNBT listNBT = new ListNBT(); list.forEach(t -> listNBT.add(serializer.apply(t))); diff --git a/src/main/resources/assets/create/models/block/mechanical_arm/flag/long_in.json b/src/main/resources/assets/create/models/block/mechanical_arm/flag/long_in.json new file mode 100644 index 000000000..7996d1e8a --- /dev/null +++ b/src/main/resources/assets/create/models/block/mechanical_arm/flag/long_in.json @@ -0,0 +1,31 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "4": "create:block/marker_flag" + }, + "elements": [ + { + "from": [0, 0, 0], + "to": [1, 16, 1], + "rotation": {"angle": 0, "axis": "y", "origin": [8, -3, 10]}, + "faces": { + "north": {"uv": [1, 0, 2, 16], "texture": "#4"}, + "east": {"uv": [0, 0, 1, 16], "texture": "#4"}, + "south": {"uv": [1, 0, 2, 16], "texture": "#4"}, + "west": {"uv": [0, 0, 1, 16], "texture": "#4"}, + "up": {"uv": [0, 0, 1, 1], "texture": "#4"}, + "down": {"uv": [0, 0, 1, 1], "texture": "#4"} + } + }, + { + "from": [0.4, 7.5, 1], + "to": [0.4, 15.5, 9], + "rotation": {"angle": 0, "axis": "y", "origin": [8, -3, 10]}, + "faces": { + "east": {"uv": [16, 0, 8, 8], "texture": "#4", "tintindex": 0}, + "west": {"uv": [8, 0, 16, 8], "texture": "#4", "tintindex": 0} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/mechanical_arm/flag/long_out.json b/src/main/resources/assets/create/models/block/mechanical_arm/flag/long_out.json new file mode 100644 index 000000000..6dae60cdb --- /dev/null +++ b/src/main/resources/assets/create/models/block/mechanical_arm/flag/long_out.json @@ -0,0 +1,31 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "4": "create:block/marker_flag" + }, + "elements": [ + { + "from": [0, 0, 0], + "to": [1, 16, 1], + "rotation": {"angle": 0, "axis": "y", "origin": [8, -3, 10]}, + "faces": { + "north": {"uv": [1, 0, 2, 16], "texture": "#4"}, + "east": {"uv": [0, 0, 1, 16], "texture": "#4"}, + "south": {"uv": [1, 0, 2, 16], "texture": "#4"}, + "west": {"uv": [0, 0, 1, 16], "texture": "#4"}, + "up": {"uv": [0, 0, 1, 1], "texture": "#4"}, + "down": {"uv": [0, 0, 1, 1], "texture": "#4"} + } + }, + { + "from": [0.4, 7.5, 1], + "to": [0.4, 15.5, 9], + "rotation": {"angle": 0, "axis": "y", "origin": [8, -3, 10]}, + "faces": { + "east": {"uv": [16, 8, 8, 16], "texture": "#4", "tintindex": 0}, + "west": {"uv": [8, 8, 16, 16], "texture": "#4", "tintindex": 0} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/mechanical_arm/flag/short_in.json b/src/main/resources/assets/create/models/block/mechanical_arm/flag/short_in.json new file mode 100644 index 000000000..84f72eb0c --- /dev/null +++ b/src/main/resources/assets/create/models/block/mechanical_arm/flag/short_in.json @@ -0,0 +1,31 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "4": "create:block/marker_flag" + }, + "elements": [ + { + "from": [0, 0, 0], + "to": [1, 8, 1], + "rotation": {"angle": 0, "axis": "y", "origin": [8, -3, 10]}, + "faces": { + "north": {"uv": [1, 8, 2, 16], "texture": "#4"}, + "east": {"uv": [0, 0, 1, 8], "texture": "#4"}, + "south": {"uv": [1, 0, 2, 8], "texture": "#4"}, + "west": {"uv": [0, 0, 1, 8], "texture": "#4"}, + "up": {"uv": [0, 0, 1, 1], "texture": "#4"}, + "down": {"uv": [0, 0, 1, 1], "texture": "#4"} + } + }, + { + "from": [0.4, -0.5, 1], + "to": [0.4, 7.5, 9], + "rotation": {"angle": 0, "axis": "y", "origin": [8, -3, 10]}, + "faces": { + "east": {"uv": [16, 0, 8, 8], "texture": "#4", "tintindex": 0}, + "west": {"uv": [8, 0, 16, 8], "texture": "#4", "tintindex": 0} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/mechanical_arm/flag/short_out.json b/src/main/resources/assets/create/models/block/mechanical_arm/flag/short_out.json new file mode 100644 index 000000000..24223d31a --- /dev/null +++ b/src/main/resources/assets/create/models/block/mechanical_arm/flag/short_out.json @@ -0,0 +1,31 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "4": "create:block/marker_flag" + }, + "elements": [ + { + "from": [0, 0, 0], + "to": [1, 8, 1], + "rotation": {"angle": 0, "axis": "y", "origin": [8, -3, 10]}, + "faces": { + "north": {"uv": [1, 8, 2, 16], "texture": "#4"}, + "east": {"uv": [0, 0, 1, 8], "texture": "#4"}, + "south": {"uv": [1, 0, 2, 8], "texture": "#4"}, + "west": {"uv": [0, 0, 1, 8], "texture": "#4"}, + "up": {"uv": [0, 0, 1, 1], "texture": "#4"}, + "down": {"uv": [0, 0, 1, 1], "texture": "#4"} + } + }, + { + "from": [0.4, -0.5, 1], + "to": [0.4, 7.5, 9], + "rotation": {"angle": 0, "axis": "y", "origin": [8, -3, 10]}, + "faces": { + "east": {"uv": [16, 8, 8, 16], "texture": "#4", "tintindex": 0}, + "west": {"uv": [8, 8, 16, 16], "texture": "#4", "tintindex": 0} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/textures/block/marker_flag.png b/src/main/resources/assets/create/textures/block/marker_flag.png new file mode 100644 index 0000000000000000000000000000000000000000..0970405a30d0750e0c3a1c0badedb47b980c56ea GIT binary patch literal 324 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!JD2gjv*HQ$!C1J{``OWS-eekwV9z&0%P^J zH$U|i6%QUbe*E}{M@PBY^z`)DWMyS{M5$@`nmAnJVPfH}`237_#=kEwg_~#2lx)+U z*~0R3q0b$LCnY7b6B*tx*~Q5juuFGzbR?7%79LzB$>PDsTw=h&V^R9*%76EMxxeNn zCMgcb3=WihJ;tjcY|e1>(6L_W|IRx#8Zz`7E-{)p&#zopr00aDX3;+NC literal 0 HcmV?d00001