feat: added basic groundwork for modes and modifier, added Replace Mode

This commit is contained in:
moonleay 2024-04-22 04:44:06 +02:00
parent a81900c6e8
commit 05db012b85
Signed by: moonleay
GPG key ID: 82667543CCD715FB
21 changed files with 579 additions and 0 deletions

View file

@ -0,0 +1,78 @@
package net.moonleay.mods.gimble.client.editor
import net.minecraft.client.MinecraftClient
import net.moonleay.mods.gimble.client.util.ChatUtil
import net.moonleay.mods.gimble.client.editor.modes.Mode
import net.moonleay.mods.gimble.client.editor.modes.ModeModifier
object Editor {
var CURRENT_MODE = Mode.NORMAL
val CURRENT_MODE_MODIFIER = mutableListOf<ModeModifier>()
private val TEMP_DISABLED_MODIFIERS = mutableListOf<ModeModifier>()
fun toggleModifier(mod: ModeModifier) {
if (CURRENT_MODE.incompatibleModifiers.contains(mod)){
if (TEMP_DISABLED_MODIFIERS.contains(mod))
TEMP_DISABLED_MODIFIERS.remove(mod)
else
TEMP_DISABLED_MODIFIERS.add(mod)
}
else {
if (CURRENT_MODE_MODIFIER.contains(mod))
CURRENT_MODE_MODIFIER.remove(mod)
else
CURRENT_MODE_MODIFIER.add(mod)
}
this.onModifiersUpdated()
}
fun onModifiersUpdated() {
CURRENT_MODE_MODIFIER.sort()
this.checkForIncompatibleModeModifiers()
}
fun checkForIncompatibleModeModifiers() {
if (TEMP_DISABLED_MODIFIERS.size > 0) {
CURRENT_MODE_MODIFIER.addAll(TEMP_DISABLED_MODIFIERS)
TEMP_DISABLED_MODIFIERS.clear()
}
val incompatibleModeModifiers = CURRENT_MODE.incompatibleModifiers
for (mod in CURRENT_MODE_MODIFIER) {
if (incompatibleModeModifiers.contains(mod)) {
TEMP_DISABLED_MODIFIERS.add(mod)
}
}
for (mod in TEMP_DISABLED_MODIFIERS) {
if (CURRENT_MODE_MODIFIER.contains(mod)) { // This check is probably useless.
CURRENT_MODE_MODIFIER.remove(mod)
}
}
if(TEMP_DISABLED_MODIFIERS.isNotEmpty()) {
ChatUtil.addToChatHistory("The following modifiers are not supported by this editor mode and are therefore currently disabled: " +
this.getListAsString(TEMP_DISABLED_MODIFIERS), MinecraftClient.getInstance())
}
}
private fun getListAsString(list: List<ModeModifier>): String{
if(list.isEmpty())
return "Empty list"
val sb = StringBuilder()
for (mod in list) {
sb.append(mod.displayName)
sb.append(" ")
}
return sb.toString().dropLast(1)
}
fun getCurrentMode(): Mode {
return CURRENT_MODE
}
fun getCurrentModifier(): List<ModeModifier> {
return CURRENT_MODE_MODIFIER
}
}

View file

@ -0,0 +1,8 @@
package net.moonleay.mods.gimble.client.editor.modes
enum class Mode(val displayName: String, val color: Int, val incompatibleModifiers: List<ModeModifier>){
NORMAL("NORMAL", 0x90a959, listOf(ModeModifier.NO_UPDATES, ModeModifier.BULLDOZER, ModeModifier.FORCE_PLACE)), // Do nothing
INSERT("INSERT", 0xf4bf75, listOf()), // Place and break blocks
REPLACE("REPLACE", 0xac4242, listOf()), // Replace blocks
VISUAL("VISUAL", 0x6a9fb5, listOf(ModeModifier.BULLDOZER)), // Do fancy stuff with WE
}

View file

@ -0,0 +1,9 @@
package net.moonleay.mods.gimble.client.editor.modes
enum class ModeModifier(val displayName: String) {
// NONE("None"), // No Modifiers - default behavior
NO_UPDATES("NO UPDATES"), // Do not update blocks when placing
BULLDOZER("BULLDOZER"), // Break blocks fast
FORCE_PLACE("FORCE"), // Ignore block placement restrictions
NO_CLIP("NO CLIP"), // Do not collide with blocks
}

View file

@ -0,0 +1,26 @@
package net.moonleay.mods.gimble.client.keybindings
import net.fabricmc.fabric.impl.client.keybinding.KeyBindingRegistryImpl
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.mods.gimble.client.keybindings.impl.GimbleShortcut
object KeybindingManager {
private val shortcuts = mutableListOf<GimbleShortcut>()
/**
* Register a shortcut. This will also register the keybinding.
* */
fun registerShortcut(shortcut: GimbleShortcut) {
shortcuts.add(shortcut)
KeyBindingRegistryImpl.registerKeyBinding(shortcut.keyBinding)
}
fun onClientTick(client: MinecraftClient){
// Sadly, this cannot be done without iterating over all shortcuts :madge:
for (shortcut in shortcuts)
if (shortcut.keyBinding.wasPressed())
shortcut.onPressed(client)
}
}

View file

@ -0,0 +1,110 @@
package net.moonleay.mods.gimble.client.keybindings
import net.minecraft.client.option.KeyBinding
import net.minecraft.client.util.InputUtil
import net.moonleay.mods.gimble.build.BuildConstants
import net.moonleay.mods.gimble.client.keybindings.impl.editormode.EnableInsertModeShortcut
import net.moonleay.mods.gimble.client.keybindings.impl.editormode.EnableReplaceModeShortcut
import net.moonleay.mods.gimble.client.keybindings.impl.editormode.EnableVisualModeShortcut
import net.moonleay.mods.gimble.client.keybindings.impl.editormodemodifier.ToggleBulldozerModifierShortcut
import net.moonleay.mods.gimble.client.keybindings.impl.editormodemodifier.ToggleForcePlaceModifierShortcut
import net.moonleay.mods.gimble.client.keybindings.impl.editormodemodifier.ToggleNoClipModifierShortcut
import net.moonleay.mods.gimble.client.keybindings.impl.editormodemodifier.ToggleNoUpdatesModifierShortcut
import net.moonleay.mods.gimble.client.keybindings.impl.gamemode.CreativeModeShortcut
import net.moonleay.mods.gimble.client.keybindings.impl.gamemode.SpectatorModeShortcut
import net.moonleay.mods.gimble.client.keybindings.impl.gamemode.SurvivalModeShortcut
import org.apache.logging.log4j.LogManager
import org.lwjgl.glfw.GLFW
object KeybindingRegistrar {
private val LOGGER = LogManager.getLogger(BuildConstants.modName)
fun registerKeybindings() {
LOGGER.info("Registering keybindings...")
registerSetGameModeKeybindings()
registerSetEditorModeKeybindings()
registerSetEditorModeModifierKeybindings()
LOGGER.info("Keybindings have been registered.")
}
private fun registerSetEditorModeModifierKeybindings() {
val toggleBulldozerModifierShortcut = KeyBinding(
"gimble.key.editor.modifier.bulldozer",
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_B,
"category.gimble.editormodifier"
)
val toggleForcePlaceModifierShortcut = KeyBinding(
"gimble.key.editor.modifier.forceplace",
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_F,
"category.gimble.editormodifier"
)
val toggleNoUpdatesModifierShortcut = KeyBinding(
"gimble.key.editor.modifier.noupdates",
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_N,
"category.gimble.editormodifier"
)
val toggleNoClipModifierShortcut = KeyBinding(
"gimble.key.editor.modifier.noclip",
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_C,
"category.gimble.editormodifier"
)
KeybindingManager.registerShortcut(ToggleBulldozerModifierShortcut(toggleBulldozerModifierShortcut))
KeybindingManager.registerShortcut(ToggleForcePlaceModifierShortcut(toggleForcePlaceModifierShortcut))
KeybindingManager.registerShortcut(ToggleNoUpdatesModifierShortcut(toggleNoUpdatesModifierShortcut))
KeybindingManager.registerShortcut(ToggleNoClipModifierShortcut(toggleNoClipModifierShortcut))
}
private fun registerSetEditorModeKeybindings() {
val insertKeyBinding = KeyBinding(
"gimble.key.editor.mode.insert",
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_I,
"category.gimble.editormode"
)
val replaceKeyBinding = KeyBinding(
"gimble.key.editor.mode.replace",
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_R,
"category.gimble.editormode"
)
val visualKeyBinding = KeyBinding(
"gimble.key.editor.mode.visual",
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_V,
"category.gimble.editormode"
)
KeybindingManager.registerShortcut(EnableInsertModeShortcut(insertKeyBinding))
KeybindingManager.registerShortcut(EnableReplaceModeShortcut(replaceKeyBinding))
KeybindingManager.registerShortcut(EnableVisualModeShortcut(visualKeyBinding))
}
private fun registerSetGameModeKeybindings() {
val survivalKeyBinding = KeyBinding(
"gimble.key.game.mode.survival",
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN,
"category.gimble.gamemode"
)
val creativeKeyBinding = KeyBinding(
"gimble.key.game.mode.creative",
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN,
"category.gimble.gamemode"
)
val spectatorKeyBinding = KeyBinding(
"gimble.key.game.mode.spectator",
InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_UNKNOWN,
"category.gimble.gamemode"
)
KeybindingManager.registerShortcut(SurvivalModeShortcut(survivalKeyBinding))
KeybindingManager.registerShortcut(CreativeModeShortcut(creativeKeyBinding))
KeybindingManager.registerShortcut(SpectatorModeShortcut(spectatorKeyBinding))
}
}

View file

@ -0,0 +1,9 @@
package net.moonleay.mods.gimble.client.keybindings.impl
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
abstract class GimbleShortcut(val keyBinding: KeyBinding) {
abstract fun onPressed(client: MinecraftClient)
}

View file

@ -0,0 +1,16 @@
package net.moonleay.mods.gimble.client.keybindings.impl.editormode
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.mods.gimble.client.editor.Editor
import net.moonleay.mods.gimble.client.keybindings.impl.GimbleShortcut
import net.moonleay.mods.gimble.client.editor.modes.Mode
class EnableInsertModeShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
Editor.CURRENT_MODE = Mode.INSERT
Editor.checkForIncompatibleModeModifiers()
}
}

View file

@ -0,0 +1,16 @@
package net.moonleay.mods.gimble.client.keybindings.impl.editormode
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.mods.gimble.client.editor.Editor
import net.moonleay.mods.gimble.client.keybindings.impl.GimbleShortcut
import net.moonleay.mods.gimble.client.editor.modes.Mode
class EnableReplaceModeShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
Editor.CURRENT_MODE = Mode.REPLACE
Editor.checkForIncompatibleModeModifiers()
}
}

View file

@ -0,0 +1,16 @@
package net.moonleay.mods.gimble.client.keybindings.impl.editormode
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.mods.gimble.client.editor.Editor
import net.moonleay.mods.gimble.client.keybindings.impl.GimbleShortcut
import net.moonleay.mods.gimble.client.editor.modes.Mode
class EnableVisualModeShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
Editor.CURRENT_MODE = Mode.VISUAL
Editor.checkForIncompatibleModeModifiers()
}
}

View file

@ -0,0 +1,15 @@
package net.moonleay.mods.gimble.client.keybindings.impl.editormodemodifier
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.mods.gimble.client.editor.Editor
import net.moonleay.mods.gimble.client.keybindings.impl.GimbleShortcut
import net.moonleay.mods.gimble.client.editor.modes.ModeModifier
class ToggleBulldozerModifierShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
Editor.toggleModifier(ModeModifier.BULLDOZER)
Editor.onModifiersUpdated()
}
}

View file

@ -0,0 +1,15 @@
package net.moonleay.mods.gimble.client.keybindings.impl.editormodemodifier
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.mods.gimble.client.editor.Editor
import net.moonleay.mods.gimble.client.keybindings.impl.GimbleShortcut
import net.moonleay.mods.gimble.client.editor.modes.ModeModifier
class ToggleForcePlaceModifierShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
Editor.toggleModifier(ModeModifier.FORCE_PLACE)
Editor.onModifiersUpdated()
}
}

View file

@ -0,0 +1,15 @@
package net.moonleay.mods.gimble.client.keybindings.impl.editormodemodifier
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.mods.gimble.client.editor.Editor
import net.moonleay.mods.gimble.client.keybindings.impl.GimbleShortcut
import net.moonleay.mods.gimble.client.editor.modes.ModeModifier
class ToggleNoClipModifierShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
Editor.toggleModifier(ModeModifier.NO_CLIP)
Editor.onModifiersUpdated()
}
}

View file

@ -0,0 +1,15 @@
package net.moonleay.mods.gimble.client.keybindings.impl.editormodemodifier
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.mods.gimble.client.editor.Editor
import net.moonleay.mods.gimble.client.keybindings.impl.GimbleShortcut
import net.moonleay.mods.gimble.client.editor.modes.ModeModifier
class ToggleNoUpdatesModifierShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
Editor.toggleModifier(ModeModifier.NO_UPDATES)
Editor.onModifiersUpdated()
}
}

View file

@ -0,0 +1,12 @@
package net.moonleay.mods.gimble.client.keybindings.impl.gamemode
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.mods.gimble.client.keybindings.impl.GimbleShortcut
import net.moonleay.mods.gimble.client.util.ChatUtil
class CreativeModeShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ChatUtil.sendCommand("/gamemode creative", client, false)
}
}

View file

@ -0,0 +1,12 @@
package net.moonleay.mods.gimble.client.keybindings.impl.gamemode
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.mods.gimble.client.keybindings.impl.GimbleShortcut
import net.moonleay.mods.gimble.client.util.ChatUtil
class SpectatorModeShortcut(key: KeyBinding): GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ChatUtil.sendCommand("/gamemode spectator", client, false)
}
}

View file

@ -0,0 +1,14 @@
package net.moonleay.mods.gimble.client.keybindings.impl.gamemode
import net.minecraft.client.MinecraftClient
import net.minecraft.client.option.KeyBinding
import net.moonleay.mods.gimble.client.keybindings.impl.GimbleShortcut
import net.moonleay.mods.gimble.client.util.ChatUtil
class SurvivalModeShortcut(key: KeyBinding) : GimbleShortcut(key) {
override fun onPressed(client: MinecraftClient) {
ChatUtil.sendCommand("/gamemode survival", client, false)
}
}

View file

@ -0,0 +1,20 @@
package net.moonleay.mods.gimble.client.util
import net.minecraft.client.MinecraftClient
import net.minecraft.text.Text
object ChatUtil {
/**
* Note: command arg should contain "/" at the beginning.
* */
fun sendCommand(command: String, client: MinecraftClient, addToHistory: Boolean = true): Boolean {
if (addToHistory) {
client.inGameHud.chatHud.addToMessageHistory(command)
}
return client.player?.sendCommand(command.substring(1))?: false
}
fun addToChatHistory(message: String, client: MinecraftClient) {
client.inGameHud.chatHud.addMessage(Text.of(message))
}
}

View file

@ -0,0 +1,66 @@
package net.moonleay.mods.gimble.mixin;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.hud.InGameHud;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text;
import net.moonleay.mods.gimble.client.editor.Editor;
import net.moonleay.mods.gimble.client.editor.modes.Mode;
import net.moonleay.mods.gimble.client.editor.modes.ModeModifier;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
@Mixin(InGameHud.class)
public class HudMixin {
@Shadow @Final private MinecraftClient client;
@Inject(method = "renderStatusEffectOverlay", at = @At("HEAD"))
private void render(MatrixStack matrices, CallbackInfo ci) {
Mode currentMode = Editor.INSTANCE.getCurrentMode();
StringBuilder displayText = getStringBuilder(currentMode);
MinecraftClient mc = MinecraftClient.getInstance();
TextRenderer tr = mc.textRenderer;
// int screenWidth = mc.getWindow().getWidth();
// int screenHeight = mc.getWindow().getHeight();
// int scale = (mc.options.getGuiScale().getValue() == 0 ? 1 : mc.options.getGuiScale().getValue());
// int bottomY = screenHeight / scale - 4 - tr.fontHeight - 12;
tr.drawWithShadow(matrices,
Text.of(displayText.toString()),
4, 4,
currentMode.getColor());
}
@Unique
private static @NotNull StringBuilder getStringBuilder(Mode currentMode) {
List<ModeModifier> currentModifier = Editor.INSTANCE.getCurrentModifier();
StringBuilder displayText = new StringBuilder(currentMode.getDisplayName());
if (!currentModifier.isEmpty()) {
displayText.append(" [");
for (int i = 0; i < currentModifier.size(); i++) {
displayText.append(currentModifier.get(i).getDisplayName());
if (i != currentModifier.size() - 1) {
displayText.append(", ");
}
}
displayText.append("]");
}
return displayText;
}
@Unique
private int getXRight(String txt, int screenWidth) {
return screenWidth / (MinecraftClient.getInstance().options.getGuiScale().getValue() == 0 ? 1 : MinecraftClient.getInstance().options.getGuiScale().getValue()) - 4 - MinecraftClient.getInstance().textRenderer.getWidth(Text.of(txt));
}
}

View file

@ -0,0 +1,16 @@
package net.moonleay.mods.gimble.mixin;
import net.minecraft.client.Keyboard;
import org.lwjgl.glfw.GLFW;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Keyboard.class)
public class KeyMixin {
// This Mixin is not registered. This will be used to handle key events with static Buttons.
@Inject(method = "onKey", at = @At("TAIL"))
private void onKey(long window, int key, int scancode, int action, int modifiers, CallbackInfo ci) {
}
}

View file

@ -0,0 +1,23 @@
package net.moonleay.mods.gimble.mixin;
import net.minecraft.client.MinecraftClient;
import net.moonleay.mods.gimble.client.editor.Editor;
import net.moonleay.mods.gimble.client.editor.modes.Mode;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(MinecraftClient.class)
public class NormalModeMixin {
@Inject(method = "openPauseMenu", at = @At("HEAD"), cancellable = true)
private void setNormalMode(boolean pause, CallbackInfo ci) {
if (Editor.INSTANCE.getCURRENT_MODE() != Mode.NORMAL){
// Set the editor mode to normal
Editor.INSTANCE.setCURRENT_MODE(Mode.NORMAL);
Editor.INSTANCE.checkForIncompatibleModeModifiers();
ci.cancel();
}
}
}

View file

@ -0,0 +1,68 @@
package net.moonleay.mods.gimble.mixin;
import net.minecraft.block.BlockState;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.network.ClientPlayerInteractionManager;
import net.minecraft.client.particle.ParticleManager;
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.moonleay.mods.gimble.client.editor.Editor;
import net.moonleay.mods.gimble.client.editor.modes.Mode;
import net.moonleay.mods.gimble.client.util.ChatUtil;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(MinecraftClient.class)
public abstract class ReplaceModeMixin {
@Shadow protected abstract void handleBlockBreaking(boolean breaking);
@Shadow @Nullable public ClientPlayerInteractionManager interactionManager;
@Shadow @Final public ParticleManager particleManager;
@Shadow @Nullable public ClientPlayerEntity player;
@Shadow @Nullable public HitResult crosshairTarget;
@Inject(method = "doItemUse", at = @At("HEAD"))
private void replaceBlock(CallbackInfo ci) {
// Check if should run
if (!Editor.INSTANCE.getCURRENT_MODE().equals(Mode.REPLACE))
return; // Mode is not REPLACE, ignore
MinecraftClient client = MinecraftClient.getInstance();
assert this.interactionManager != null;
if (!this.interactionManager.getCurrentGameMode().isCreative())
return;
if (!(this.crosshairTarget instanceof BlockHitResult))
return;
BlockHitResult blockHitResult = (BlockHitResult)this.crosshairTarget;
if (blockHitResult == null)
return;
// Gather data
BlockPos pos = blockHitResult.getBlockPos();
Direction direction = blockHitResult.getSide();
BlockState blockState = client.world.getBlockState(pos);
// Start sending shit
client.getTutorialManager().onBlockBreaking(client.world, pos, blockState, 1.0F);
this.interactionManager.sendSequencedPacket(client.world, sequence -> {
this.interactionManager.breakBlock(pos);
return new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.START_DESTROY_BLOCK, pos, direction, sequence);
});
this.player.swingHand(Hand.MAIN_HAND);
}
}