Skip to content

Commit

Permalink
Create 'implicit context' when plugin pushes frames
Browse files Browse the repository at this point in the history
This allows plugins to properly append
the cause for events that use the transaction
system and fires the events after the frame
has been closed.
  • Loading branch information
aromaa committed Feb 1, 2025
1 parent 06a58ae commit 49fe76a
Show file tree
Hide file tree
Showing 8 changed files with 46 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public class PhaseContext<P extends PhaseContext<P>> implements PhaseStateProxy<
private boolean allowsEntityEvents = true;
private boolean allowsBulkBlockCaptures = true; // Defaults to allow block captures
private boolean allowsBulkEntityCaptures = true;
private boolean requiresImplicitPhase = false;
@Nullable Deque<CauseStackManager.StackFrame> usedFrame;

private @Nullable Object source;
Expand Down Expand Up @@ -378,6 +379,15 @@ public Optional<ServerLocation> containerLocation() {
return Optional.empty();
}

public final boolean requiresImplicitPhase() {
return this.requiresImplicitPhase;
}

protected P requiresImplicitPhase(final boolean requiresImplicitPhase) {
this.requiresImplicitPhase = requiresImplicitPhase;
return (P) this;
}

protected boolean isRunaway(final PhaseContext<?> phaseContext) {
return phaseContext.getClass() == this.getClass();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import org.spongepowered.common.applaunch.config.core.SpongeConfigs;
import org.spongepowered.common.event.cause.entity.SpongeSpawnTypes;
import org.spongepowered.common.event.tracking.phase.general.GeneralPhase;
import org.spongepowered.common.event.tracking.phase.plugin.PluginPhase;
import org.spongepowered.common.event.tracking.phase.tick.TickPhase;
import org.spongepowered.common.launch.Launch;
import org.spongepowered.common.util.Constants;
Expand Down Expand Up @@ -568,6 +569,10 @@ public Object peekCause() {

@Override
public StackFrame pushCauseFrame() {
return this.pushCauseFrame0(false);
}

public StackFrame pushCauseFrame0(final boolean skipImplicitPhaseCreation) {
this.enforceMainThread();
// Ensure duplicate causes will be correctly sized.
final int size = this.cause.size();
Expand Down Expand Up @@ -596,14 +601,35 @@ public StackFrame pushCauseFrame() {
// were created.
frame.stackDebug = new Exception();
}
if (!skipImplicitPhaseCreation && this.getPhaseContext().requiresImplicitPhase()) {
frame.implicitContext = PluginPhase.State.PLUGIN.createPhaseContext(this).buildAndSwitch();
}
return frame;
}

@Override
public void popCauseFrame(final StackFrame oldFrame) {
Objects.requireNonNull(oldFrame, "oldFrame");
this.enforceMainThread();
final @Nullable SpongeCauseStackFrame frame = this.frames.peek();
@Nullable SpongeCauseStackFrame frame = this.frames.peek();
if (frame != oldFrame) {
// If implicit context is present, we need to
// first close it as it might have pushed new frames.
// This is an implementation detail so the caller has
// no knowledge of this context, so it can't close it
// by itself and instead closes the outer frame.
if (((SpongeCauseStackFrame) oldFrame).implicitContext != null) {
((SpongeCauseStackFrame) oldFrame).implicitContext.close();
((SpongeCauseStackFrame) oldFrame).implicitContext = null;
frame = this.frames.peek();
}
} else if (frame.implicitContext != null) {
// See above, no frames to close here.
// Fast path to avoid casting.
frame.implicitContext.close();
frame.implicitContext = null;
}

if (frame != oldFrame) {
// If the given frame is not the top frame then some form of
// corruption of the stack has occurred and we do our best to correct
Expand Down Expand Up @@ -763,7 +789,7 @@ private void checkProviders() {
// except for this method call-point.
for (final Iterator<PhaseContext<@NonNull ?>> iterator = this.phaseContextProviders.descendingIterator(); iterator.hasNext(); ) {
final PhaseContext<@NonNull ?> context = iterator.next();
final StackFrame frame = this.pushCauseFrame(); // these should auto close
final StackFrame frame = this.pushCauseFrame0(true); // these should auto close
context.getFrameModifier().accept(frame); // The frame will be auto closed by the phase context
}
// Clear the list since everything is now loaded.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public final class SpongeCauseStackFrame implements CauseStackManager.StackFrame
private final Map<EventContextKey<?>, Object> storedContext;
int old_min_depth;
int lastCauseSize;
@Nullable PhaseContext<?> implicitContext = null;

@Nullable Exception stackDebug = null;

Expand All @@ -58,6 +59,7 @@ public void clear() {
this.storedContext.clear();
this.lastCauseSize = -1;
this.old_min_depth = -1;
this.implicitContext = null;
this.stackDebug = null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public class CommandPhaseContext extends GeneralPhaseContext<CommandPhaseContext

CommandPhaseContext(final IPhaseState<CommandPhaseContext> state, final PhaseTracker tracker) {
super(state, tracker);
this.requiresImplicitPhase(true);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import org.spongepowered.api.event.CauseStackManager;
import org.spongepowered.common.event.tracking.PhaseTracker;
import org.spongepowered.common.event.tracking.TrackingUtil;

import java.util.function.BiConsumer;

Expand All @@ -51,6 +52,6 @@ public BiConsumer<CauseStackManager.StackFrame, BasicPluginContext> getFrameModi

@Override
public void unwind(final BasicPluginContext phaseContext) {

TrackingUtil.processBlockCaptures(phaseContext);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public static class Context extends PluginPhaseContext<Context> {

public Context(final IPhaseState<Context> phaseState, final PhaseTracker tracker) {
super(phaseState, tracker);
this.requiresImplicitPhase(false);
}

public Context container(final PluginContainer container) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public static final class State {
public static final IPhaseState<VolumeStreamApplicationState.Context> VOLUME_STREAM_APPLICATION = new VolumeStreamApplicationState();
public static final IPhaseState<BasicPluginContext> SCHEDULED_TASK = new ScheduledTaskPhaseState();
public static final IPhaseState<DelayedTaskPhaseState.Context> DELAYED_TASK = new DelayedTaskPhaseState();
public static final IPhaseState<BasicPluginContext> PLUGIN = new BasicPluginState();

private State() {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public class PluginPhaseContext<P extends PluginPhaseContext<P>> extends PhaseCo

protected PluginPhaseContext(final IPhaseState<P> phaseState, final PhaseTracker tracker) {
super(phaseState, tracker);
this.requiresImplicitPhase(true);
}

@Override
Expand Down

0 comments on commit 49fe76a

Please sign in to comment.