Solved WorldEdit cancel region edit and point selection

Discussion in 'Spigot Plugin Development' started by Stef, May 9, 2018.

  1. I'm trying to cancel a point selection and the editing of a region. For the points I tried listening to PointSelectionEvent (or whatever it is called), but it isn't cancellable. I tried BlockInteractEvent, but when you cancel it it doesn't cancel the point selection and it gets called for every block interaction. For the region I tried listening to EditSessionEvent and setting the extent to a NullExtent, but that doesn't do anything either. Here's what I currently have for the interaction:
    Code (Java):

    @Subscribe
    public void onBlockInteract(BlockInteractEvent event) {
       if (!event.getCause().isPlayer() || !(event.getCause() instanceof BukkitPlayer))
           return;

       Player player = ((BukkitPlayer) event.getCause()).getPlayer();
       Arena arena = ArenaManager.getInstance().getArena(player);

       //don't do anything if the player isn't in an arena
       if (arena == null)
           return;

       com.sk89q.worldedit.util.Location location = event.getLocation();

       //this will fail to work if plugins are doing weird stuff
       if (arena.getPlot(player).getBoundary().isInside(new Location(player.getWorld(), location.getX(), location.getY(), location.getZ())))
           return;

       player.sendMessage(ChatColor.RED + "You can't select a point outside the plot");

       event.setCancelled(true);
    }
    And the edit canceling:
    Code (Java):

    @Subscribe
    public void onEditSession(EditSessionEvent event) {
       if (!event.getActor().isPlayer() || !(event.getActor() instanceof BukkitPlayer))
           return;

       Player player = ((BukkitPlayer) event.getActor()).getPlayer();
       Arena arena = ArenaManager.getInstance().getArena(player);

       //don't do anything if the player isn't in an arena
       if (arena == null)
           return;

       Region boundary = arena.getPlot(player).getBoundary(); //my own region, not WE's region
       World world = Bukkit.getWorld(event.getWorld().getName());
       Extent extent = event.getExtent();

       //no edits will happen anyway
       if (extent instanceof NullExtent)
           return;

       Vector minimumPoint = extent.getMinimumPoint();
       Vector maximumPoint = extent.getMaximumPoint();

       //if the minimum point and the maximum point are both inside the boundary, every point will be
       if (boundary.isInside(new Location(world, minimumPoint.getX(), minimumPoint.getY(), minimumPoint.getZ())) && boundary.isInside(new Location(world, maximumPoint.getX(), maximumPoint.getY(), maximumPoint.getZ())))
           return;

       player.sendMessage(ChatColor.RED + "You can't make any edits outside the plot");

       event.setExtent(new NullExtent());
    }
    Does anyone know a way that allows you to cancel the point selection and cancel the region being edited? I've looked at the documentation, but can't find anything that could be of use.
     
  2. Several things:
    • You'd need to change the event priority if you want to receive the BlockInteractEvent before WorldEdit.
    • CUI events (like SelectionPointEvent) are not called on the server, they are sent to the client only if they have the WE-CUI mod installed.
    • When you use extent.getMinimimPoint() etc, the extent is the world, and you are always going to get the minimum position in the world (-30M blocks), not the player's selection.
    • You are trying to check if the bondary is in the selection, but it should be the other way around
    • There is no guarantee that the actor will be an instanceof BukkitPlayer, you're better off using Bukkit.getPlayer(uuid)
    • Your approach wouldn't work if the player doesn't use a cuboid selection
    • Your approach wouldn't work if the player uses some operation that either extends past the selection, or doesn't use a selection (the majority of WorldEdit commands)
    I would suggest preventing placement on a per-block basis, by passing an AbstractDelegateExtent (instead of a NullExtent), and overriding the setBlock methods.

    If you are using FAWE, then there's an API for region restrictions you can use.
     
    • Useful Useful x 1
  3. Thanks for your reply.

    Would that have any effect on the selection itself if I cancel the event before WorldEdit handles it? Cause, unless there is some implementation detail in the eventbus I missed, it seems like WorldEdit doesn't care if the event was canceled when it handles it (https://github.com/sk89q/WorldEdit/...nsion/platform/PlatformManager.java#L307-L386)
    Boundary is my own class, the isInside method checks if the given location is inside the boundary, so that should work fine.
    Wouldn't
    Code (Java):
    if (!event.getCause().isPlayer() || !(event.getCause() instanceof BukkitPlayer))
           return;
    ensure this?
    Okay, thanks for your help.
     
  4. Yes, though checking the cuboid pos1/pos2 is still a flawed solution to restricting WorldEdit (i.e. you shouldn't do it).

    My mistake.

    Not what I said. Several operations will use ProxyPlayer, or some other wrapper around BukkitPlayer. So these operations won't be restricted at all, because you simply return if it's not a BukkitPlayer.

    btw, you can cancel the EditSessionEvent by throwing some WorldEditException or CommandException
     
  5. Okay, thanks for your help.