Fix left click on air being ignored and right click on block being handled twice

This commit is contained in:
Alexander Brandes 2023-09-16 23:44:14 +02:00
parent 81ba7d1acd
commit 319bc0a551
No known key found for this signature in database
GPG Key ID: 158F5701A6AAD00C
5 changed files with 133 additions and 43 deletions

View File

@ -42,6 +42,7 @@ import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.lifecycle.Lifecycled; import com.sk89q.worldedit.util.lifecycle.Lifecycled;
import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.registry.Registries; import com.sk89q.worldedit.world.registry.Registries;
import io.papermc.lib.PaperLib;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Server; import org.bukkit.Server;
@ -258,6 +259,14 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
return SUPPORTED_SIDE_EFFECTS; return SUPPORTED_SIDE_EFFECTS;
} }
@Override
public long getTickCount() {
if (PaperLib.isPaper()) {
return Bukkit.getCurrentTick();
}
return super.getTickCount();
}
public void unregisterCommands() { public void unregisterCommands() {
dynamicCommands.unregisterCommands(); dynamicCommands.unregisterCommands();
} }

View File

@ -27,6 +27,7 @@ import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.platform.SessionIdleEvent; import com.sk89q.worldedit.event.platform.SessionIdleEvent;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.internal.event.InteractionDebouncer;
import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
@ -55,6 +56,7 @@ import java.util.Optional;
public class WorldEditListener implements Listener { public class WorldEditListener implements Listener {
private final WorldEditPlugin plugin; private final WorldEditPlugin plugin;
private final InteractionDebouncer debouncer;
/** /**
* Construct the object. * Construct the object.
@ -63,6 +65,7 @@ public class WorldEditListener implements Listener {
*/ */
public WorldEditListener(WorldEditPlugin plugin) { public WorldEditListener(WorldEditPlugin plugin) {
this.plugin = plugin; this.plugin = plugin;
debouncer = new InteractionDebouncer(plugin.getInternalPlatform());
} }
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
@ -128,62 +131,58 @@ public class WorldEditListener implements Listener {
*/ */
@EventHandler @EventHandler
public void onPlayerInteract(PlayerInteractEvent event) { public void onPlayerInteract(PlayerInteractEvent event) {
if (!plugin.getInternalPlatform().isHookingEvents()) { if (!plugin.getInternalPlatform().isHookingEvents()
return; || event.useItemInHand() == Result.DENY
} || event.getHand() == EquipmentSlot.OFF_HAND
|| event.getAction() == Action.PHYSICAL) {
if (event.useItemInHand() == Result.DENY) {
return;
}
if (event.getHand() == EquipmentSlot.OFF_HAND) {
return; return;
} }
final Player player = plugin.wrapPlayer(event.getPlayer()); final Player player = plugin.wrapPlayer(event.getPlayer());
if (event.getAction() != Action.LEFT_CLICK_BLOCK) {
Optional<Boolean> previousResult = debouncer.getDuplicateInteractionResult(player);
if (previousResult.isPresent()) {
if (previousResult.get()) {
event.setCancelled(true);
}
return;
}
}
final World world = player.getWorld(); final World world = player.getWorld();
final WorldEdit we = plugin.getWorldEdit(); final WorldEdit we = plugin.getWorldEdit();
final Direction direction = BukkitAdapter.adapt(event.getBlockFace()); final Direction direction = BukkitAdapter.adapt(event.getBlockFace());
final Block clickedBlock = event.getClickedBlock();
final Location pos = clickedBlock == null ? null : new Location(world, clickedBlock.getX(), clickedBlock.getY(), clickedBlock.getZ());
Action action = event.getAction(); boolean result = false;
if (action == Action.LEFT_CLICK_BLOCK) { switch (event.getAction()) {
final Block clickedBlock = event.getClickedBlock(); case LEFT_CLICK_BLOCK:
final Location pos = new Location(world, clickedBlock.getX(), clickedBlock.getY(), clickedBlock.getZ()); result = we.handleBlockLeftClick(player, pos, direction) || we.handleArmSwing(player);
break;
if (we.handleBlockLeftClick(player, pos, direction)) { case LEFT_CLICK_AIR:
event.setCancelled(true); result = we.handleArmSwing(player);
} break;
case RIGHT_CLICK_BLOCK:
if (we.handleArmSwing(player)) { result = we.handleBlockRightClick(player, pos, direction) || we.handleRightClick(player);
event.setCancelled(true); break;
} case RIGHT_CLICK_AIR:
result = we.handleRightClick(player);
} else if (action == Action.LEFT_CLICK_AIR) { break;
default:
if (we.handleArmSwing(player)) { break;
event.setCancelled(true); }
} debouncer.setLastInteraction(player, result);
if (result) {
} else if (action == Action.RIGHT_CLICK_BLOCK) { event.setCancelled(true);
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.handleRightClick(player)) {
event.setCancelled(true);
}
} else if (action == Action.RIGHT_CLICK_AIR) {
if (we.handleRightClick(player)) {
event.setCancelled(true);
}
} }
} }
@EventHandler @EventHandler
public void onPlayerQuit(PlayerQuitEvent event) { public void onPlayerQuit(PlayerQuitEvent event) {
debouncer.clearInteraction(plugin.wrapPlayer(event.getPlayer()));
plugin.getWorldEdit().getEventBus().post(new SessionIdleEvent(new BukkitPlayer.SessionKeyImpl(event.getPlayer()))); plugin.getWorldEdit().getEventBus().post(new SessionIdleEvent(new BukkitPlayer.SessionKeyImpl(event.getPlayer())));
} }

View File

@ -55,4 +55,9 @@ public abstract class AbstractPlatform implements Platform {
return null; return null;
} }
@Override
public long getTickCount() {
return System.nanoTime() / 50_000_000;
}
} }

View File

@ -216,6 +216,14 @@ public interface Platform extends Keyed {
*/ */
Set<SideEffect> getSupportedSideEffects(); Set<SideEffect> getSupportedSideEffects();
/**
* Get the number of ticks since the server started.
* On some platforms this value may be an approximation based on the JVM run time.
*
* @return The number of ticks since the server started.
*/
long getTickCount();
//FAWE start //FAWE start
/** /**

View File

@ -0,0 +1,69 @@
/*
* 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.internal.event;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.util.Identifiable;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
public class InteractionDebouncer {
private final Platform platform;
private final Map<UUID, Interaction> lastInteractions = new HashMap<>();
public InteractionDebouncer(Platform platform) {
this.platform = platform;
}
public void clearInteraction(Identifiable player) {
lastInteractions.remove(player.getUniqueId());
}
public void setLastInteraction(Identifiable player, boolean result) {
lastInteractions.put(player.getUniqueId(), new Interaction(platform.getTickCount(), result));
}
public Optional<Boolean> getDuplicateInteractionResult(Identifiable player) {
Interaction last = lastInteractions.get(player.getUniqueId());
if (last == null) {
return Optional.empty();
}
long now = platform.getTickCount();
if (now - last.tick <= 1) {
return Optional.of(last.result);
}
return Optional.empty();
}
private static class Interaction {
public final long tick;
public final boolean result;
public Interaction(long tick, boolean result) {
this.tick = tick;
this.result = result;
}
}
}