Litematica (Forge)

Litematica (Forge)

336k Downloads

EasyPlaceMode places blocks in its own way

abeshi-softwire opened this issue ยท 2 comments

commented

Minecraft version
1.16.1

Mod version and malilib version
Litematica v0.0.0-dev.20200711.162756
Malilib 0.10.0-dev.21+arne.1

Description of the bug
When placing blocks, EasyPlaceMode will place the block closest to you. This means (for example) if you have a filled-in area in the schematic, it's impossible to place the middle block in easy place mode

Expected behavior (if not clear from the description)
EasyPlaceMode should place the farthest (reachable) block first.

To Reproduce (if not clear from the description already)
Steps to reproduce the behavior:

  1. Create a 3x3x3 schematic
  2. Turn on easyplacemode
  3. Can't place the middle block

UPDATE
I've found that this doesn't happen if you disable schematic rendering and hold the correct item, it will let you place it where it belongs but not switch to other items or let you place the block you're holding where a surrounding block would be (e.g. if you have a 3x3x3 schematic, 1 glass surrounded by stone, disable rendering and hold glass, then it will place the glass at the center).

commented

I just ran into this issue as well. Unfortunately, the workaround supplied doesn't work anymore on 1.17 Fabric. I think it should be as simple as checking if the raycast's distance is 0 (meaning inside a block) and rerunning the raycast ignoring the previously found block.

commented

I created a patch that helps with the issue. It makes the vanilla raytrace take precedence over the schematic raytrace so if you are looking at a block, it will always fill the schematic off of that block instead of the closest schematic. It's got some duplicated code (It's LGPLv3 so @maruohon you're free to clean it up and integrate it), but I've tested it on my own and it works for my purposes (building while inside a schematic).

Index: src/main/java/fi/dy/masa/litematica/util/WorldUtils.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/fi/dy/masa/litematica/util/WorldUtils.java b/src/main/java/fi/dy/masa/litematica/util/WorldUtils.java
--- a/src/main/java/fi/dy/masa/litematica/util/WorldUtils.java	(revision 3c513865b95f65b774e665d743cdae965c48106a)
+++ b/src/main/java/fi/dy/masa/litematica/util/WorldUtils.java	(date 1628388036926)
@@ -486,44 +486,59 @@
                     return ActionResult.FAIL;
                 }
 
-                // Abort if the required item was not able to be pick-block'd
-                if (doSchematicWorldPickBlock(true, mc) == false)
-                {
-                    return ActionResult.FAIL;
-                }
-
-                Hand hand = EntityUtils.getUsedHandForItem(mc.player, stack);
-
-                // Abort if a wrong item is in the player's hand
-                if (hand == null)
-                {
-                    return ActionResult.FAIL;
-                }
+                Hand hand;
 
                 Vec3d hitPos = trace.getPos();
                 Direction sideOrig = trace.getSide();
 
                 // If there is a block in the world right behind the targeted schematic block, then use
                 // that block as the click position
-                if (traceVanilla != null && traceVanilla.getType() == HitResult.Type.BLOCK)
+                if (traceVanilla.getType() == HitResult.Type.BLOCK)
                 {
                     BlockHitResult hitResult = (BlockHitResult) traceVanilla;
                     BlockPos posVanilla = hitResult.getBlockPos();
                     Direction sideVanilla = hitResult.getSide();
+                    BlockPos offsetPosVanilla = posVanilla.offset(sideVanilla);
                     BlockState stateVanilla = mc.world.getBlockState(posVanilla);
                     Vec3d hit = traceVanilla.getPos();
+
+                    stack = MaterialCache.getInstance().getRequiredBuildItemForState(world.getBlockState(offsetPosVanilla));
+                    // Abort if the required item was not able to be pick-block'd
+                    if (!doSchematicWorldPickBlock(false, mc))
+                    {
+                        return ActionResult.FAIL;
+                    }
+
+                    hand = EntityUtils.getUsedHandForItem(mc.player, stack);
+
+                    // Abort if a wrong item is in the player's hand
+                    if (hand == null)
+                    {
+                        return ActionResult.FAIL;
+                    }
+
                     ItemPlacementContext ctx = new ItemPlacementContext(new ItemUsageContext(mc.player, hand, hitResult));
 
-                    if (stateVanilla.canReplace(ctx) == false)
-                    {
-                        posVanilla = posVanilla.offset(sideVanilla);
-
-                        if (pos.equals(posVanilla))
-                        {
-                            hitPos = hit;
-                            sideOrig = sideVanilla;
-                        }
+                    pos = stateVanilla.canReplace(ctx) ? posVanilla : offsetPosVanilla;
+                    hitPos = hit;
+                    sideOrig = sideVanilla;
+
+                }
+                else
+                {
+                    // Abort if the required item was not able to be pick-block'd
+                    if (!doSchematicWorldPickBlock(true, mc))
+                    {
+                        return ActionResult.FAIL;
                     }
+
+                    hand = EntityUtils.getUsedHandForItem(mc.player, stack);
+
+                    // Abort if a wrong item is in the player's hand
+                    if (hand == null)
+                    {
+                        return ActionResult.FAIL;
+                    }
                 }
 
                 Direction side = applyPlacementFacing(stateSchematic, sideOrig, stateClient);