Created
December 9, 2021 05:45
-
-
Save RecursiveG/9879277abb1448d476f20e7858d52b74 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* SPDX-License-Identifier: MIT */ | |
package me.recursiveg.automation; | |
import net.minecraft.client.Minecraft; | |
import net.minecraft.client.multiplayer.MultiPlayerGameMode; | |
import net.minecraft.client.player.LocalPlayer; | |
import net.minecraft.core.BlockPos; | |
import net.minecraft.core.Direction; | |
import net.minecraft.core.NonNullList; | |
import net.minecraft.world.InteractionHand; | |
import net.minecraft.world.inventory.ClickType; | |
import net.minecraft.world.item.BlockItem; | |
import net.minecraft.world.item.Item; | |
import net.minecraft.world.item.ItemStack; | |
import net.minecraft.world.level.block.Block; | |
import net.minecraft.world.level.block.Blocks; | |
import net.minecraft.world.level.block.state.BlockState; | |
import net.minecraft.world.phys.BlockHitResult; | |
import net.minecraft.world.phys.Vec3; | |
import net.minecraftforge.event.TickEvent; | |
import net.minecraftforge.eventbus.api.SubscribeEvent; | |
import net.minecraftforge.fml.LogicalSide; | |
import java.util.Map; | |
public class AutoPlacement implements IAutomation { | |
private boolean enabled = false; | |
private int toolSlot = 0; | |
private Block used_material = null; | |
private BlockPos player_block_pos = null; | |
private int blockY; | |
private double blockOffsetY; // 0-1 | |
@Override | |
public void enable() { | |
LocalPlayer p = Minecraft.getInstance().player; | |
if (p == null) return; | |
double offY = p.getY() % 1.0; | |
if (offY < 0.9 && offY > 0.1) { | |
// Standing on not complete block | |
blockY = (int) Math.floor(p.getY()); | |
blockOffsetY = 0.3; | |
} else { | |
// Standing on complete block | |
blockY = (int) p.getY() - 1; | |
blockOffsetY = 0.7; | |
} | |
toolSlot = p.getInventory().selected; | |
Item item = p.getInventory().getSelected().getItem(); | |
if (item instanceof BlockItem bi) { | |
used_material = bi.getBlock(); | |
player_block_pos = p.blockPosition(); | |
enabled = true; | |
AutomationMod.msg("AutoPlacement enabled: %s, blockY: %d, blockOffsetY: %f", enabled, blockY, blockOffsetY); | |
} | |
} | |
@Override | |
public void disable() { | |
enabled = false; | |
AutomationMod.msg("AutoPlacement enabled: %s", enabled); | |
} | |
@Override | |
public boolean isEnabled() { | |
return enabled; | |
} | |
@Override | |
public Map<String, String> getOptions() { | |
return Map.of("enabled", "ro bool:" + enabled, | |
"blockY", "ro int:" + blockY, | |
"blockOffsetY", "ro double:" + blockOffsetY); | |
} | |
@Override | |
public void setOption(String op, String val) { | |
AutomationMod.msg("AutoPlacement has no options"); | |
} | |
@SubscribeEvent | |
public void onTick(TickEvent.PlayerTickEvent e) { | |
if (enabled && e.side == LogicalSide.CLIENT && e.player != null && e.player == Minecraft.getInstance().player) { | |
if (e.player.getInventory().selected != toolSlot) { | |
enabled = false; | |
AutomationMod.msg("Tool switched. AutoPlacement disabled"); | |
return; | |
} | |
if (e.player.blockPosition().equals(player_block_pos)) return; | |
player_block_pos = e.player.blockPosition(); | |
if (e.player.getInventory().getSelected().isEmpty()) { | |
boolean success = tryFillItemInHand(Minecraft.getInstance().player); | |
if (!success) { | |
enabled = false; | |
AutomationMod.msg("Item used up! AutoPlacement disabled"); | |
} | |
} | |
if (!tryPlacement(Minecraft.getInstance().player)) { | |
enabled = false; | |
AutomationMod.msg("Place Fail! AutoPlacement disabled"); | |
} | |
} | |
} | |
public static void moveInventoryItem(int srcIdx, int dstIdx) { | |
LocalPlayer p = Minecraft.getInstance().player; | |
if (p == null) return; | |
NonNullList<ItemStack> a = p.getInventory().items; | |
MultiPlayerGameMode gm = Minecraft.getInstance().gameMode; | |
if (gm == null) return; | |
if (a.get(srcIdx).isEmpty()) return; | |
if (a.get(dstIdx).isEmpty()) { | |
gm.handleInventoryMouseClick( | |
/*containerId=*/0, | |
/*slotNum=*/srcIdx < 9 ? srcIdx + 36 : srcIdx, | |
/*buttonNum=*/0, | |
ClickType.PICKUP, | |
p); | |
gm.handleInventoryMouseClick( | |
/*containerId=*/0, | |
/*slotNum=*/dstIdx < 9 ? dstIdx + 36 : dstIdx, | |
/*buttonNum=*/0, | |
ClickType.PICKUP, | |
p); | |
} else { | |
gm.handleInventoryMouseClick( | |
/*containerId=*/0, | |
/*slotNum=*/srcIdx < 9 ? srcIdx + 36 : srcIdx, | |
/*buttonNum=*/0, | |
ClickType.PICKUP, | |
p); | |
gm.handleInventoryMouseClick( | |
/*containerId=*/0, | |
/*slotNum=*/dstIdx < 9 ? dstIdx + 36 : dstIdx, | |
/*buttonNum=*/0, | |
ClickType.PICKUP, | |
p); | |
gm.handleInventoryMouseClick( | |
/*containerId=*/0, | |
/*slotNum=*/srcIdx < 9 ? srcIdx + 36 : srcIdx, | |
/*buttonNum=*/0, | |
ClickType.PICKUP, | |
p); | |
} | |
} | |
// return true if success | |
private boolean tryFillItemInHand(LocalPlayer p) { | |
ItemStack itemStack = p.getItemInHand(InteractionHand.MAIN_HAND); | |
if (!itemStack.isEmpty()) return true; | |
if (used_material == null) return false; | |
ItemStack expectingItem = new ItemStack(used_material); | |
int supplmentIdx = -1; | |
NonNullList<ItemStack> inv = p.getInventory().items; | |
for (int idx = 0; idx < 36; ++idx) { | |
ItemStack s = inv.get(idx); | |
if (s.getItem() == expectingItem.getItem() && | |
s.getDamageValue() == expectingItem.getDamageValue() && | |
!s.hasTag()) { | |
supplmentIdx = idx; | |
break; | |
} | |
} | |
if (supplmentIdx < 0) return false; | |
moveInventoryItem(supplmentIdx, p.getInventory().selected); | |
return true; | |
} | |
static BlockHitResult getHitResult(BlockPos block, Direction face, double blockOffsetY) { | |
// New block will be placed on `face` of `block`. | |
Vec3 hit = switch (face) { | |
case UP -> new Vec3(block.getX() + 0.5, block.getY() + 1, block.getZ() + 0.5); | |
case DOWN -> new Vec3(block.getX() + 0.5, block.getY(), block.getZ() + 0.5); | |
case EAST -> new Vec3(block.getX() + 1, block.getY() + blockOffsetY, block.getZ() + 0.5); | |
case SOUTH -> new Vec3(block.getX() + 0.5, block.getY() + blockOffsetY, block.getZ() + 1); | |
case WEST -> new Vec3(block.getX(), block.getY() + blockOffsetY, block.getZ() + 0.5); | |
case NORTH -> new Vec3(block.getX() + 0.5, block.getY() + blockOffsetY, block.getZ()); | |
}; | |
return new BlockHitResult(hit, face, block, false); | |
} | |
public boolean tryPlacement(LocalPlayer p) { | |
BlockPos blockStandingOn = player_block_pos.atY(blockY); | |
Direction d = Direction.fromYRot(p.getYRot()); | |
BlockPos blockWillPlaceOn = blockStandingOn.relative(d); | |
BlockState blockToBeReplaced = p.level.getBlockState(blockWillPlaceOn); | |
if (blockToBeReplaced.isAir() || blockToBeReplaced.getBlock() == Blocks.WATER || | |
blockToBeReplaced.getBlock() == Blocks.LAVA) { | |
Minecraft.getInstance().gameMode.useItemOn(p, p.clientLevel, InteractionHand.MAIN_HAND, | |
getHitResult(blockStandingOn, d, blockOffsetY)); | |
} | |
return true; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment