Skip to content

Commit

Permalink
Fix left click on air being ignored and right click on block being ha…
Browse files Browse the repository at this point in the history
…ndled twice
  • Loading branch information
Yeregorix committed Jan 3, 2023
1 parent 474c191 commit efa6834
Show file tree
Hide file tree
Showing 12 changed files with 459 additions and 196 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.World;
import io.papermc.lib.PaperLib;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.bukkit.event.Event.Result;
import org.bukkit.event.EventHandler;
Expand All @@ -45,12 +49,15 @@
import org.enginehub.piston.inject.MapBackedValueStore;

import java.util.Optional;
import java.util.UUID;

/**
* Handles all events thrown in relation to a Player.
*/
public class WorldEditListener implements Listener {

private final Object2IntMap<UUID> lastInteractionTicks = new Object2IntOpenHashMap<>();

private final WorldEditPlugin plugin;

/**
Expand Down Expand Up @@ -86,6 +93,19 @@ public void onPlayerCommandSend(PlayerCommandSendEvent event) {
);
}

private static int getCurrentTick() {
if (PaperLib.isPaper()) {
return Bukkit.getCurrentTick();
}
return (int) (System.currentTimeMillis() / 50);
}

private boolean isDuplicateInteraction(Player player) {
int now = getCurrentTick();
int last = lastInteractionTicks.getInt(player.getUniqueId());
return now - last <= 1;
}

/**
* Called when a player interacts.
*
Expand Down Expand Up @@ -124,31 +144,36 @@ public void onPlayerInteract(PlayerInteractEvent event) {
}

} else if (action == Action.LEFT_CLICK_AIR) {

if (we.handleArmSwing(player)) {
if (!isDuplicateInteraction(player) && we.handleArmSwing(player)) {
event.setCancelled(true);
}

} else if (action == Action.RIGHT_CLICK_BLOCK) {
final Block clickedBlock = event.getClickedBlock();
final Location pos = new Location(world, clickedBlock.getX(), clickedBlock.getY(), clickedBlock.getZ());
if (!isDuplicateInteraction(player)) {
final Block clickedBlock = event.getClickedBlock();
final Location pos = new Location(world, clickedBlock.getX(), clickedBlock.getY(), clickedBlock.getZ());

if (we.handleBlockRightClick(player, pos, direction)) {
event.setCancelled(true);
}
if (we.handleBlockRightClick(player, pos, direction)) {
event.setCancelled(true);
}

if (we.handleRightClick(player)) {
event.setCancelled(true);
if (we.handleRightClick(player)) {
event.setCancelled(true);
}
}
} else if (action == Action.RIGHT_CLICK_AIR) {
if (we.handleRightClick(player)) {
if (!isDuplicateInteraction(player) && we.handleRightClick(player)) {
event.setCancelled(true);
}
}

lastInteractionTicks.put(player.getUniqueId(), getCurrentTick());
}

@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
lastInteractionTicks.removeInt(event.getPlayer().getUniqueId());

plugin.getWorldEdit().getEventBus().post(new SessionIdleEvent(new BukkitPlayer.SessionKeyImpl(event.getPlayer())));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.item.ItemCategory;
import com.sk89q.worldedit.world.item.ItemType;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
Expand Down Expand Up @@ -82,6 +84,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.fabric.FabricAdapter.adaptPlayer;
Expand Down Expand Up @@ -113,6 +116,8 @@ public static <T> Registry<T> getRegistry(ResourceKey<Registry<T>> key) {

public static FabricWorldEdit inst;

private final Object2IntMap<UUID> lastInteractionTicks = new Object2IntOpenHashMap<>();

private FabricPlatform platform;
private FabricConfiguration config;
private Path workingDir;
Expand Down Expand Up @@ -250,19 +255,36 @@ private void onStopServer(MinecraftServer minecraftServer) {
WorldEdit.getInstance().getEventBus().post(new PlatformUnreadyEvent(platform));
}

private boolean shouldSkip() {
if (platform == null) {
return true;
}
private boolean skipEvents() {
return platform == null || !platform.isHookingEvents();
}

return !platform.isHookingEvents(); // We have to be told to catch these events
private boolean isDuplicateInteraction(ServerPlayer player) {
int now = player.server.getTickCount();
int last = lastInteractionTicks.getInt(player.getUUID());
return now - last <= 1;
}

private void saveInteractionTick(ServerPlayer player) {
int now = player.server.getTickCount();
lastInteractionTicks.put(player.getUUID(), now);
}

private void removeInteractionTick(ServerPlayer player) {
lastInteractionTicks.removeInt(player.getUUID());
}

private boolean skipInteractionEvent(Player player, InteractionHand hand) {
return skipEvents() || hand != InteractionHand.MAIN_HAND || player.level.isClientSide || !(player instanceof ServerPlayer);
}

private InteractionResult onLeftClickBlock(Player playerEntity, Level world, InteractionHand hand, BlockPos blockPos, Direction direction) {
if (shouldSkip() || hand == InteractionHand.OFF_HAND || world.isClientSide) {
if (skipInteractionEvent(playerEntity, hand)) {
return InteractionResult.PASS;
}

saveInteractionTick((ServerPlayer) playerEntity);

WorldEdit we = WorldEdit.getInstance();
FabricPlayer player = adaptPlayer((ServerPlayer) playerEntity);
FabricWorld localWorld = getWorld(world);
Expand All @@ -285,10 +307,12 @@ private InteractionResult onLeftClickBlock(Player playerEntity, Level world, Int
}

private InteractionResult onRightClickBlock(Player playerEntity, Level world, InteractionHand hand, BlockHitResult blockHitResult) {
if (shouldSkip() || hand == InteractionHand.OFF_HAND || world.isClientSide) {
if (skipInteractionEvent(playerEntity, hand)) {
return InteractionResult.PASS;
}

saveInteractionTick((ServerPlayer) playerEntity);

WorldEdit we = WorldEdit.getInstance();
FabricPlayer player = adaptPlayer((ServerPlayer) playerEntity);
FabricWorld localWorld = getWorld(world);
Expand All @@ -310,12 +334,27 @@ private InteractionResult onRightClickBlock(Player playerEntity, Level world, In
return InteractionResult.PASS;
}

public void onLeftClickAir(ServerPlayer playerEntity, InteractionHand hand) {
if (skipInteractionEvent(playerEntity, hand) || isDuplicateInteraction(playerEntity)) {
return;
}

saveInteractionTick(playerEntity);

WorldEdit we = WorldEdit.getInstance();
FabricPlayer player = adaptPlayer(playerEntity);

we.handleArmSwing(player);
}

private InteractionResultHolder<ItemStack> onRightClickAir(Player playerEntity, Level world, InteractionHand hand) {
ItemStack stackInHand = playerEntity.getItemInHand(hand);
if (shouldSkip() || hand == InteractionHand.OFF_HAND || world.isClientSide) {
if (skipInteractionEvent(playerEntity, hand) || isDuplicateInteraction((ServerPlayer) playerEntity)) {
return InteractionResultHolder.pass(stackInHand);
}

saveInteractionTick((ServerPlayer) playerEntity);

WorldEdit we = WorldEdit.getInstance();
FabricPlayer player = adaptPlayer((ServerPlayer) playerEntity);

Expand All @@ -326,9 +365,9 @@ private InteractionResultHolder<ItemStack> onRightClickAir(Player playerEntity,
return InteractionResultHolder.pass(stackInHand);
}

// TODO Pass empty left click to server

private void onPlayerDisconnect(ServerGamePacketListenerImpl handler, MinecraftServer server) {
removeInteractionTick(handler.player);

WorldEdit.getInstance().getEventBus()
.post(new SessionIdleEvent(new FabricPlayer.SessionKeyImpl(handler.player)));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.sk89q.worldedit.fabric.mixin;

import net.minecraft.server.level.ServerPlayerGameMode;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;

@Mixin(ServerPlayerGameMode.class)
public interface AccessorServerPlayerGameMode {

@Accessor("isDestroyingBlock")
boolean isDestroyingBlock();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.sk89q.worldedit.fabric.mixin;

import com.sk89q.worldedit.fabric.FabricWorldEdit;
import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket;
import net.minecraft.network.protocol.game.ServerboundSwingPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
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(ServerGamePacketListenerImpl.class)
public class MixinServerGamePacketListenerImpl {
@Shadow
public ServerPlayer player;

private int ignoreSwingPackets;

@Inject(method = "handleAnimate", at = @At("HEAD"))
private void onAnimate(ServerboundSwingPacket packet, CallbackInfo ci) {
if (!((AccessorServerPlayerGameMode) this.player.gameMode).isDestroyingBlock()) {
if (this.ignoreSwingPackets > 0) {
this.ignoreSwingPackets--;
} else if (FabricWorldEdit.inst != null) {
FabricWorldEdit.inst.onLeftClickAir(this.player, packet.getHand());
}
}
}

@Inject(method = "handlePlayerAction", at = @At("HEAD"))
private void onAction(ServerboundPlayerActionPacket packet, CallbackInfo ci) {
switch (packet.getAction()) {
case DROP_ITEM:
case DROP_ALL_ITEMS:
case START_DESTROY_BLOCK:
this.ignoreSwingPackets++;
break;
default:
break;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
"AccessorPrimaryLevelData",
"AccessorDerivedLevelData",
"AccessorServerChunkCache",
"AccessorServerPlayerGameMode",
"MixinLevelChunkSetBlockHook",
"MixinMinecraftServer",
"MixinServerGamePacketListenerImpl",
"MixinServerPlayer"
],
"plugin": "com.sk89q.worldedit.fabric.internal.MixinConfigPlugin",
Expand Down
Loading

0 comments on commit efa6834

Please sign in to comment.