SpongePowered / SpongeAPI

A Minecraft plugin API
http://www.spongepowered.org/
MIT License
1.14k stars 342 forks source link

Run event in case of cancellation. #900

Closed Azatik closed 9 years ago

Azatik commented 9 years ago

I'm writing a plugin to the graves. If a player dies in a private area, it will not break the grave. How to allow the player to break the grave in a private area? 2015-11-04_20 59 19

Zidane commented 9 years ago

A question: What do you define as a "private area"?

Zidane commented 9 years ago

Also, the Listener annotation has:

https://github.com/SpongePowered/SpongeAPI/blob/master/src/main/java/org/spongepowered/api/event/Listener.java#L59

Simply specify it as false and you'll get cancelled events.

Azatik commented 9 years ago

Private area - Anti Grief plugin

Azatik commented 9 years ago

How to use "ignoreCancelled()"?

octylFractal commented 9 years ago

@Listener(ignoreCancelled=true). Read up on annotations :)

Azatik commented 9 years ago

I will write in a different way. The player died on the territory of the World Guard. A player can not gain access to the grave (to break grave).

I want execute an event when his cancels other plugin. In my case: Run ChangeBlockEvent.Break, when his cancels the AntiGrief-plugin.

Zidane commented 9 years ago

So, just to decipher this:

You only want to handle this event if it was cancelled via the AntiGrief plugin?

Azatik commented 9 years ago

Allow to break blocks on the territory of the World Guard (any Anti Grief Plugin).

Zidane commented 9 years ago

@Azatik

Then what you want to do is adjust your Order to POST as well as ignoreCancelled = false

https://github.com/SpongePowered/SpongeAPI/blob/master/src/main/java/org/spongepowered/api/event/Order.java#L111

Then, if your criteria is met, setCancelled(false)

Azatik commented 9 years ago

Report.

I created two events. EventBreakBlock:

public class EventBreakBlock {   
    @Listener
    public void onEventBreakBlock(ChangeBlockEvent.Break event) {
        if (event.getCause().first(Player.class).isPresent()) {
            Player player = (Player) event.getCause().first(Player.class).get();
            Text msg = Texts.of(TextColors.DARK_RED, "Action prohibited.");
            player.sendMessage(msg);
            event.setCancelled(true);
            }
        }
    }

EventBreakBlockAllow:

public class EventBreakBlockAllow {
    @Listener(ignoreCancelled=false, order = POST)
    public void onEventBreakBlockAllow(ChangeBlockEvent.Break event) {
        if (event.getCause().first(Player.class).isPresent()) {
            Player player = (Player) event.getCause().first(Player.class).get();
            Text msg = Texts.of(TextColors.DARK_GREEN, "Action allow.");
            player.sendMessage(msg);
            event.setCancelled(false);
        }
    }
}

Result: 2015-11-04_23 12 13

gabizou commented 9 years ago

@Azatik you don't need to cast with event.getCause().first(Player.class).get() since passing the class will already make the return type a Player. I'll test locally and see if I can reproduce.

gabizou commented 9 years ago

@Azatik I ran locally and the event isn't cancelled, so the break is occurring. I'm not seeing the problem in this case.

Azatik commented 9 years ago

@gabizou It works fine. Mini Problem: output message "Action prohibited." from event EventBreakBlock.

gabizou commented 9 years ago

@Azatik yes, because the listener executed, and cancelled the event. Of course, the second listener will un-cancel it such that it's now not cancelled. This is why it's important for world protection plugins to not only have a listener for the early events to check protections, but a secondary post listener that checks if the event is still cancelled.

Your act of un cancelling the event in POST however is probably bad practice as at that point you're in a race condition of whichever listener gets the event first in the chain.

Azatik commented 9 years ago

@gabizou There are better variants?

gabizou commented 9 years ago

Could use BEFORE_POST. POST is intended for block monitoring plugins like Prism where they just log the activities etc.

gabizou commented 9 years ago

Otherwise, this isn't an issue it seems.

Azatik commented 9 years ago

I agree.