Skip to content

Commit

Permalink
!feat: Add CompositeEvent
Browse files Browse the repository at this point in the history
This also breaks InteractBlockEvent.Secondary and SpawnEntityEvent.Pre
  • Loading branch information
gabizou committed Jun 4, 2024
1 parent 1fb6e5b commit 326bc20
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 34 deletions.
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
80 changes: 80 additions & 0 deletions src/main/java/org/spongepowered/api/event/CompositeEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* This file is part of SpongeAPI, licensed under the MIT License (MIT).
*
* Copyright (c) SpongePowered <https://www.spongepowered.org>
* 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.
* <p>Using {@link #setCancelled(boolean)} will perform a best effort cancellation
* on each of the children events.
*/
@GenerateFactoryMethod
@ImplementedBy(AbstractCompositeEvent.class)
public interface CompositeEvent<E extends Event> extends Event, Cancellable {

E baseEvent();

List<Event> children();

default <E extends Event> List<? extends E> event(Class<E> type) {
return this.children().stream()
.filter(type::isInstance)
.map(type::cast)
.toList();
}

default <E extends Event> void applyTo(Class<E> type, Consumer<? super E> 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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -101,7 +103,8 @@ interface Finish extends Primary, Cancellable {
*
* <p>This is usually right-click.</p>
*/
interface Secondary extends InteractBlockEvent, Cancellable {
@GenerateFactoryMethod
interface Secondary extends InteractBlockEvent {

Tristate originalUseItemResult();

Expand Down Expand Up @@ -143,43 +146,51 @@ interface Secondary extends InteractBlockEvent, Cancellable {
*/
Tristate useBlockResult();

/**
* Sets whether the {@link Player#itemInHand} should be used.
*
* <ul>
* <li>FALSE: The {@link ItemStack} will never be used.</li>
* <li>UNDEFINED: The {@link ItemStack} will be used if the block fails.
* </li>
* <li>TRUE: The {@link ItemStack} will always be used.</li>
* </ul>
*
* <p>Note: These results may differ depending on implementation.</p>
*
* @param result Whether the {@link Player#itemInHand} should be used
*/
void setUseItemResult(Tristate result);

/**
* Sets whether the interacted {@link BlockSnapshot} should be used.
*
* <ul>
* <li>FALSE: {@link BlockSnapshot} will never be used.</li>
* <li>UNDEFINED: {@link BlockSnapshot} will be used as normal.</li>
* <li>TRUE: {@link BlockSnapshot} will always be used.</li>
* </ul>
*
* <p>Note: These results may differ depending on implementation.</p>
*
* @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.
*
* <ul>
* <li>FALSE: The {@link ItemStack} will never be used.</li>
* <li>UNDEFINED: The {@link ItemStack} will be used if the block fails.
* </li>
* <li>TRUE: The {@link ItemStack} will always be used.</li>
* </ul>
*
* <p>Note: These results may differ depending on implementation.</p>
*
* @param result Whether the {@link Player#itemInHand} should be used
*/
void setUseItemResult(Tristate result);

/**
* Sets whether the interacted {@link BlockSnapshot} should be used.
*
* <ul>
* <li>FALSE: {@link BlockSnapshot} will never be used.</li>
* <li>UNDEFINED: {@link BlockSnapshot} will be used as normal.</li>
* <li>TRUE: {@link BlockSnapshot} will always be used.</li>
* </ul>
*
* <p>Note: These results may differ depending on implementation.</p>
*
* @param result Whether the interacted {@link BlockSnapshot} should be
* used
*/
void setUseBlockResult(Tristate result);
}

interface Post extends CompositeEvent<InteractBlockEvent.Secondary> {

}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* This file is part of SpongeAPI, licensed under the MIT License (MIT).
*
* Copyright (c) SpongePowered <https://www.spongepowered.org>
* 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<E extends Event> extends AbstractEvent implements CompositeEvent<E> {

@UseField(overrideToString = true)
protected List<Event> 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);
}
});
}
}

0 comments on commit 326bc20

Please sign in to comment.