diff --git a/src/main/java/io/github/eatmyvenom/litematicin/utils/InventoryUtils.java b/src/main/java/io/github/eatmyvenom/litematicin/utils/InventoryUtils.java index 0335070c..51530724 100644 --- a/src/main/java/io/github/eatmyvenom/litematicin/utils/InventoryUtils.java +++ b/src/main/java/io/github/eatmyvenom/litematicin/utils/InventoryUtils.java @@ -24,6 +24,7 @@ import java.util.List; public class InventoryUtils { + private static int ptr = -1; public static int lastCount = 0; public static int itemChangeCount = 0; public static Item handlingItem = null; @@ -38,17 +39,27 @@ public static void tick() { trackedSelectedSlot = -1; previousItem = null; handlingItem = null; + usedSlots.clear(); } - } + public static void decrementCount() { if (lastCount > 0) { lastCount--; } } + private static int getPtr() { + ptr++; + ptr = ptr % 9; + return ptr; + } + public static int getAvailableSlot() { + if (usedSlots.size() == 9) { //full + return getPtr(); + } for (int i = 0; i < 9; i++) { if (usedSlots.containsKey(i)) { continue; @@ -95,6 +106,10 @@ public static boolean areItemsExactAllowNamed(ItemStack a, ItemStack b) { } public static boolean requiresSwap(ClientPlayerEntity player, ItemStack stack) { + int selectedSlot = player.getInventory().selectedSlot; + if (usedSlots.get(selectedSlot) != null) { + return stack.getItem() != usedSlots.get(selectedSlot); + } return previousItem == null || lastCount == 0 ? !areItemsExact(getMainHandStack(player), stack) : !areItemsExact(previousItem.getDefaultStack(), stack); } @@ -162,10 +177,10 @@ private static boolean creativeSwap(MinecraftClient client, ClientPlayerEntity p MessageHolder.sendOrderMessage("Clicked creative stack " + stack.getItem() + " for slot " + selectedSlot); //player.getInventory().addPickBlock(stack); player.getInventory().selectedSlot = selectedSlot; + client.interactionManager.clickCreativeStack(stack, 36 + selectedSlot); client.getNetworkHandler().sendPacket(new UpdateSelectedSlotC2SPacket(player.getInventory().selectedSlot)); trackedSelectedSlot = selectedSlot; player.getInventory().main.set(selectedSlot, stack); - client.interactionManager.clickCreativeStack(stack, 36 + selectedSlot); usedSlots.put(player.getInventory().selectedSlot, stack.getItem()); lastCount = 65536; handlingItem = stack.getItem(); @@ -189,10 +204,15 @@ private static boolean survivalSwap(MinecraftClient client, ClientPlayerEntity p return false; } if (PlayerInventory.isValidHotbarIndex(slot)) { + if (usedSlots.get(slot) != null) { + MessageHolder.sendOrderMessage("Hotbar slot should have been handled before, so it must be error!"); + MessageHolder.sendOrderMessage("Expected : " + usedSlots.get(slot) + " but current client handles : " + stack.getItem()); + return false; + } player.getInventory().selectedSlot = slot; trackedSelectedSlot = slot; MessageHolder.sendOrderMessage("Selected hotbar Slot " + slot); - lastCount = client.player.getAbilities().creativeMode ? 65536 : client.player.getInventory().getStack(slot).getCount(); + lastCount = player.getAbilities().creativeMode ? 65536 : player.getInventory().getStack(slot).getCount(); client.getNetworkHandler().sendPacket(new UpdateSelectedSlotC2SPacket(slot)); } else { int selectedSlot = getAvailableSlot(); @@ -200,8 +220,9 @@ private static boolean survivalSwap(MinecraftClient client, ClientPlayerEntity p MessageHolder.sendOrderMessage("All hotbar slots are used"); return false; } - lastCount = client.player.getAbilities().creativeMode ? 65536 : client.player.getInventory().getStack(slot).getCount(); - MessageHolder.sendOrderMessage("Slot at " + slot + " is swapped with " + selectedSlot); + lastCount = player.getAbilities().creativeMode ? 65536 : player.getInventory().getStack(slot).getCount(); + MessageHolder.sendOrderMessage("Slot at " + slot + "(%s)".formatted(player.getInventory().getStack(slot).getItem()) + " is swapped with " + selectedSlot + "(%s)".formatted(player.getInventory().main.get(selectedSlot))); + usedSlots.put(selectedSlot, stack.getItem()); client.interactionManager.clickSlot(player.playerScreenHandler.syncId, slot, selectedSlot, SlotActionType.SWAP, player); player.getInventory().selectedSlot = selectedSlot; trackedSelectedSlot = selectedSlot; diff --git a/src/main/java/io/github/eatmyvenom/litematicin/utils/Printer.java b/src/main/java/io/github/eatmyvenom/litematicin/utils/Printer.java index f8681657..aab566f3 100644 --- a/src/main/java/io/github/eatmyvenom/litematicin/utils/Printer.java +++ b/src/main/java/io/github/eatmyvenom/litematicin/utils/Printer.java @@ -35,6 +35,7 @@ import net.minecraft.network.packet.c2s.play.UpdateSignC2SPacket; import net.minecraft.state.property.Properties; import net.minecraft.tag.BlockTags; +import net.minecraft.text.TextContent; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; @@ -49,7 +50,6 @@ import java.util.*; import static io.github.eatmyvenom.litematicin.LitematicaMixinMod.*; -import static io.github.eatmyvenom.litematicin.utils.InventoryUtils.*; @SuppressWarnings("ConstantConditions") public class Printer { @@ -96,7 +96,7 @@ private static boolean simulateFacingData(BlockState state, BlockPos blockPos, V public static boolean canPickBlock(MinecraftClient mc, BlockState preference, BlockPos pos) { World world = SchematicWorldHandler.getSchematicWorld(); - ItemStack stack = preference.isOf(Blocks.WATER) && PRINTER_PLACE_ICE.getBooleanValue() ? Items.ICE.getDefaultStack() : MaterialCache.getInstance().getRequiredBuildItemForState(preference, world, pos); + ItemStack stack = isReplaceableWaterFluidSource(preference) && PRINTER_PLACE_ICE.getBooleanValue() ? Items.ICE.getDefaultStack() : MaterialCache.getInstance().getRequiredBuildItemForState(preference, world, pos); if (!stack.isEmpty() && stack.getItem() != Items.AIR) { PlayerInventory inv = mc.player.getInventory(); if (!mc.player.getAbilities().creativeMode) { @@ -137,7 +137,7 @@ public static boolean canPickItem(MinecraftClient mc, ItemStack stack) { synchronized public static boolean doSchematicWorldPickBlock(MinecraftClient mc, BlockState preference, BlockPos pos) { World world = SchematicWorldHandler.getSchematicWorld(); - ItemStack stack = preference.isOf(Blocks.WATER) && PRINTER_PLACE_ICE.getBooleanValue() ? Items.ICE.getDefaultStack() : MaterialCache.getInstance().getRequiredBuildItemForState(preference, world, pos); + ItemStack stack = isReplaceableWaterFluidSource(preference) && PRINTER_PLACE_ICE.getBooleanValue() ? Items.ICE.getDefaultStack() : MaterialCache.getInstance().getRequiredBuildItemForState(preference, world, pos); if (!FakeAccurateBlockPlacement.canHandleOther(stack.getItem())) { return false; } @@ -260,7 +260,6 @@ private static boolean isPositionWithinBox(Box box, BlockPos pos) { @Environment(EnvType.CLIENT) synchronized public static ActionResult doPrinterAction(MinecraftClient mc) { io.github.eatmyvenom.litematicin.utils.InventoryUtils.itemChangeCount = 0; - handlingItem = null; if (!DEBUG_MESSAGE.getBooleanValue()) { causeMap.clear(); //reduce ram usage } @@ -278,13 +277,9 @@ synchronized public static ActionResult doPrinterAction(MinecraftClient mc) { ItemInputs.clear(); } if (new Date().getTime() < lastPlaced + 1000.0 * EASY_PLACE_MODE_DELAY.getDoubleValue()) { - trackedSelectedSlot = -1; - previousItem = null; - handlingItem = null; return ActionResult.PASS; } else { isSleeping = false; - io.github.eatmyvenom.litematicin.utils.InventoryUtils.usedSlots.clear(); } BlockPos tracePos = mc.player.getBlockPos(); int posX = tracePos.getX(); @@ -1419,7 +1414,7 @@ private static boolean willExtendInWorld(World world, BlockPos pos, Direction pi If its true, then block should be placed after observer update is done Case A : Observer is facing wall attached : observer - wall - output Case B : Observer is facing Noteblock from horizontal : observer - block below noteblock - noteblock - output - + Case C : Observer is facing wire connected to observer's up offset * * */ @SuppressWarnings({"ConstantConditions"}) private static BlockPos isObserverCantAvoidOutput(MinecraftClient mc, World schematicWorld, BlockPos pos) { @@ -1464,7 +1459,6 @@ else if (qcState.isSolidBlock(schematicWorld, qcPos)) { } } } - } return null; } @@ -1559,8 +1553,39 @@ private static boolean ObserverCantAvoid(MinecraftClient mc, World world, Direct return offsetBlock instanceof WallBlock || offsetBlock instanceof WallMountedBlock && OffsetStateSchematic.get(WallMountedBlock.FACE) == WallMountLocation.CEILING; } else { return offsetBlock instanceof WallBlock || offsetBlock instanceof PaneBlock || offsetBlock instanceof FenceBlock || OffsetStateSchematic.isOf(Blocks.IRON_BARS) || offsetBlock instanceof WallMountedBlock && - OffsetStateSchematic.get(WallMountedBlock.FACE) == WallMountLocation.WALL && OffsetStateSchematic.get(WallMountedBlock.FACING) == facingSchematic; + OffsetStateSchematic.get(WallMountedBlock.FACE) == WallMountLocation.WALL && OffsetStateSchematic.get(WallMountedBlock.FACING) == facingSchematic || hasDustOrAscendingRails(world, facingSchematic, pos); + } + } + + private static boolean hasDustOrAscendingRails(World schematicWorld, Direction watching, BlockPos observerPos) { + BlockPos possible = observerPos.offset(watching); + BlockState state = schematicWorld.getBlockState(possible); + if (state.isOf(Blocks.REDSTONE_WIRE)) { + //ascending_'opposite' directions + //watching.getOpposite should have 'up' + WireConnection connection = state.get(RedstoneWireBlock.DIRECTION_TO_WIRE_CONNECTION_PROPERTY.get(watching.getOpposite())); + return connection == WireConnection.UP; + + } else if (state.getBlock() instanceof PoweredRailBlock) { + switch (watching) { + case NORTH -> { + return state.get(PoweredRailBlock.SHAPE) == RailShape.ASCENDING_SOUTH; + } + case SOUTH -> { + return state.get(PoweredRailBlock.SHAPE) == RailShape.ASCENDING_NORTH; + } + case EAST -> { + return state.get(PoweredRailBlock.SHAPE) == RailShape.ASCENDING_WEST; + } + case WEST -> { + return state.get(PoweredRailBlock.SHAPE) == RailShape.ASCENDING_EAST; + } + default -> { + return false; + } + } } + return false; } private static List getNeighborsExcept(BlockPos pos, Direction except) { @@ -1637,6 +1662,11 @@ private static Set ObserverCantAvoidPos(MinecraftClient mc, World worl relatedPos.add(pos.offset(direction, 2).down()); } } + } else if (block instanceof PoweredRailBlock || block instanceof RedstoneWireBlock) { + if (hasDustOrAscendingRails(world, direction.getOpposite(), pos)) { + relatedPos.add(pos.offset(direction, 2)); + relatedPos.addAll(getNeighborsExcept(pos, direction)); + } } } } @@ -2122,6 +2152,9 @@ public static Vec3d applyTorchHitVec(BlockPos pos, Vec3d hitVecIn, Direction sid } private static void updateSignText(MinecraftClient mc, World schematicWorld, BlockPos pos) { + if (isPositionCached(pos, false)) { + return; + } if (mc.currentScreen instanceof SignEditScreen || !schematicWorld.getBlockState(pos).isIn(BlockTags.SIGNS) || signCache.contains(pos.asLong())) { return; } @@ -2134,9 +2167,14 @@ private static void updateSignText(MinecraftClient mc, World schematicWorld, Blo return; } if (entity instanceof SignBlockEntity signBlockEntity && clientEntity instanceof SignBlockEntity clientSignEntity) { - if (!clientSignEntity.isEditable()) { + if (clientSignEntity.getTextOnRow(0, false).getContent() != TextContent.EMPTY || clientSignEntity.getTextOnRow(1, false).getContent() != TextContent.EMPTY || + clientSignEntity.getTextOnRow(2, false).getContent() != TextContent.EMPTY || + clientSignEntity.getTextOnRow(3, false).getContent() != TextContent.EMPTY) { + MessageHolder.sendDebugMessage("Text already exists in " + pos.toShortString()); + signCache.add(pos.asLong()); return; } + MessageHolder.sendDebugMessage("Tries to copy sign text in " + pos.toShortString()); signCache.add(pos.asLong()); mc.getNetworkHandler().sendPacket(new UpdateSignC2SPacket(signBlockEntity.getPos(), signBlockEntity.getTextOnRow(0, false).getString(), signBlockEntity.getTextOnRow(1, false).getString(), signBlockEntity.getTextOnRow(2, false).getString(), signBlockEntity.getTextOnRow(3, false).getString())); }