From 326bc20803412ccabf63269e7b206065d8e44e26 Mon Sep 17 00:00:00 2001 From: Gabriel Harris-Rouquette Date: Sun, 21 Apr 2024 15:25:40 -0700 Subject: [PATCH] !feat: Add CompositeEvent This also breaks InteractBlockEvent.Secondary and SpawnEntityEvent.Pre --- build.gradle.kts | 1 + .../api/event/CompositeEvent.java | 80 +++++++++++++++++++ .../api/event/block/InteractBlockEvent.java | 77 ++++++++++-------- .../api/event/entity/SpawnEntityEvent.java | 4 +- .../event/impl/AbstractCompositeEvent.java | 56 +++++++++++++ 5 files changed, 184 insertions(+), 34 deletions(-) create mode 100644 src/main/java/org/spongepowered/api/event/CompositeEvent.java create mode 100644 src/main/java/org/spongepowered/api/event/impl/AbstractCompositeEvent.java diff --git a/build.gradle.kts b/build.gradle.kts index 95dda334e29..9d21dcd03cf 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -137,6 +137,7 @@ tasks { outputFactory = "org.spongepowered.api.event.SpongeEventFactory" include("org/spongepowered/api/event/*/**/*") + include("org/spongepowered/api/event/CompositeEvent.java") exclude("org/spongepowered/api/event/action/InteractEvent.java") exclude("org/spongepowered/api/event/cause/") exclude("org/spongepowered/api/event/entity/AffectEntityEvent.java") diff --git a/src/main/java/org/spongepowered/api/event/CompositeEvent.java b/src/main/java/org/spongepowered/api/event/CompositeEvent.java new file mode 100644 index 00000000000..0e2ac4b4f82 --- /dev/null +++ b/src/main/java/org/spongepowered/api/event/CompositeEvent.java @@ -0,0 +1,80 @@ +/* + * This file is part of SpongeAPI, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.api.event; + +import org.spongepowered.api.event.impl.AbstractCompositeEvent; +import org.spongepowered.api.util.annotation.eventgen.GenerateFactoryMethod; +import org.spongepowered.api.util.annotation.eventgen.ImplementedBy; +import org.spongepowered.api.util.annotation.eventgen.PropertySettings; + +import java.util.List; +import java.util.function.Consumer; + +/** + * A {@link CompositeEvent} is an {@link Event} that contains multiple + * side effectual {@link Event Events}, which may have their own side effects + * and may be {@link Cancellable}. In some cases, the interactions of this event + * may be cancellable as a whole, but are not guaranteed to revert all side + * effects on the {@link org.spongepowered.api.Game}. The {@link #children()} of + * this event are ordered in a "best-effort" basis, and may not be guaranteed + * to be in any particular order. + *

Using {@link #setCancelled(boolean)} will perform a best effort cancellation + * on each of the children events. + */ +@GenerateFactoryMethod +@ImplementedBy(AbstractCompositeEvent.class) +public interface CompositeEvent extends Event, Cancellable { + + E baseEvent(); + + List children(); + + default List event(Class type) { + return this.children().stream() + .filter(type::isInstance) + .map(type::cast) + .toList(); + } + + default void applyTo(Class type, Consumer consumer) { + this.children().stream() + .filter(type::isInstance) + .map(type::cast) + .forEach(consumer); + } + + /** + * {@inheritDoc} + * + * Cancels this event and all related events captured {@link #children()}. + * Selectively, if individual events are wished to be cancelled, + * the individual events should be cancelled instead. + * + * @param cancel The new cancelled state + */ + @PropertySettings(generateMethods = false) + @Override + void setCancelled(boolean cancel); +} diff --git a/src/main/java/org/spongepowered/api/event/block/InteractBlockEvent.java b/src/main/java/org/spongepowered/api/event/block/InteractBlockEvent.java index 161452c8bdf..1378a517efc 100644 --- a/src/main/java/org/spongepowered/api/event/block/InteractBlockEvent.java +++ b/src/main/java/org/spongepowered/api/event/block/InteractBlockEvent.java @@ -29,10 +29,12 @@ import org.spongepowered.api.block.BlockTypes; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.event.Cancellable; +import org.spongepowered.api.event.CompositeEvent; import org.spongepowered.api.event.action.InteractEvent; import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.util.Direction; import org.spongepowered.api.util.Tristate; +import org.spongepowered.api.util.annotation.eventgen.GenerateFactoryMethod; import org.spongepowered.api.world.server.ServerLocation; import org.spongepowered.math.vector.Vector3d; @@ -101,7 +103,8 @@ interface Finish extends Primary, Cancellable { * *

This is usually right-click.

*/ - interface Secondary extends InteractBlockEvent, Cancellable { + @GenerateFactoryMethod + interface Secondary extends InteractBlockEvent { Tristate originalUseItemResult(); @@ -143,43 +146,51 @@ interface Secondary extends InteractBlockEvent, Cancellable { */ Tristate useBlockResult(); - /** - * Sets whether the {@link Player#itemInHand} should be used. - * - * - * - *

Note: These results may differ depending on implementation.

- * - * @param result Whether the {@link Player#itemInHand} should be used - */ - void setUseItemResult(Tristate result); - - /** - * Sets whether the interacted {@link BlockSnapshot} should be used. - * - * - * - *

Note: These results may differ depending on implementation.

- * - * @param result Whether the interacted {@link BlockSnapshot} should be - * used - */ - void setUseBlockResult(Tristate result); - /** * Gets the point of interaction where the interaction occurred as a {@link Vector3d}. * * @return The interaction point */ Vector3d interactionPoint(); + + interface Pre extends Secondary, Cancellable { + + /** + * Sets whether the {@link Player#itemInHand} should be used. + * + * + * + *

Note: These results may differ depending on implementation.

+ * + * @param result Whether the {@link Player#itemInHand} should be used + */ + void setUseItemResult(Tristate result); + + /** + * Sets whether the interacted {@link BlockSnapshot} should be used. + * + * + * + *

Note: These results may differ depending on implementation.

+ * + * @param result Whether the interacted {@link BlockSnapshot} should be + * used + */ + void setUseBlockResult(Tristate result); + } + + interface Post extends CompositeEvent { + + } + } } diff --git a/src/main/java/org/spongepowered/api/event/entity/SpawnEntityEvent.java b/src/main/java/org/spongepowered/api/event/entity/SpawnEntityEvent.java index f459b856f79..81e4f127143 100644 --- a/src/main/java/org/spongepowered/api/event/entity/SpawnEntityEvent.java +++ b/src/main/java/org/spongepowered/api/event/entity/SpawnEntityEvent.java @@ -26,6 +26,7 @@ import org.spongepowered.api.entity.Entity; import org.spongepowered.api.event.Cause; +import org.spongepowered.api.event.impl.entity.AbstractAffectEntityEvent; import org.spongepowered.api.event.impl.entity.AbstractSpawnEntityEvent; import org.spongepowered.api.util.annotation.eventgen.GenerateFactoryMethod; import org.spongepowered.api.util.annotation.eventgen.ImplementedBy; @@ -51,7 +52,8 @@ public interface SpawnEntityEvent extends AffectEntityEvent { * will result in no awareness to the client that the entity was being * spawned and later cancelled. */ - interface Pre extends SpawnEntityEvent {} + @ImplementedBy(value = AbstractAffectEntityEvent.class, priority = 2) + interface Pre extends AffectEntityEvent {} interface Custom extends SpawnEntityEvent {} } diff --git a/src/main/java/org/spongepowered/api/event/impl/AbstractCompositeEvent.java b/src/main/java/org/spongepowered/api/event/impl/AbstractCompositeEvent.java new file mode 100644 index 00000000000..73b0e759990 --- /dev/null +++ b/src/main/java/org/spongepowered/api/event/impl/AbstractCompositeEvent.java @@ -0,0 +1,56 @@ +/* + * This file is part of SpongeAPI, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.api.event.impl; + +import org.spongepowered.api.event.Cancellable; +import org.spongepowered.api.event.CompositeEvent; +import org.spongepowered.api.event.Event; +import org.spongepowered.api.util.annotation.eventgen.UseField; + +import java.util.Collections; +import java.util.List; + +public abstract class AbstractCompositeEvent extends AbstractEvent implements CompositeEvent { + + @UseField(overrideToString = true) + protected List children; + + @UseField + protected boolean cancelled; + + public final void postInit() { + this.children = Collections.unmodifiableList(this.children); + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + this.children().forEach(event -> { + if (event instanceof Cancellable cancellable) { + cancellable.setCancelled(cancel); + } + }); + } +}