use of org.spongepowered.common.event.tracking.PhaseTracker in project SpongeCommon by SpongePowered.
the class BlockWorkerPhaseState method switchIfNecessary.
@Nullable
public PhaseContext<@NonNull ?> switchIfNecessary(final PhaseTracker server) {
final PhaseTracker instance = PhaseTracker.getInstance();
if (!server.onSidedThread()) {
return null;
}
final IPhaseState<@NonNull ?> currentState = instance.getCurrentState();
if (currentState.isApplyingStreams()) {
return null;
}
return this.createPhaseContext(server);
}
use of org.spongepowered.common.event.tracking.PhaseTracker in project SpongeCommon by SpongePowered.
the class SpongeVolumeStream method apply.
@Override
public <W extends MutableVolume> void apply(final VolumeCollector<W, T, ?> collector) {
final PhaseTracker instance = PhaseTracker.getInstance();
try (@Nullable final PhaseContext<@NonNull ?> context = instance.getPhaseContext().isApplyingStreams() ? null : PluginPhase.State.VOLUME_STREAM_APPLICATION.createPhaseContext(instance).setVolumeStream(this).spawnType(() -> PhaseTracker.getCauseStackManager().context(EventContextKeys.SPAWN_TYPE).orElse(null))) {
if (context != null) {
context.buildAndSwitch();
}
this.stream.forEach(element -> {
final W targetVolume = collector.target().get();
final VolumeElement<W, T> transformed = collector.positionTransform().apply(VolumeElement.of(collector.target(), element::type, element.position()));
collector.applicator().apply(targetVolume, transformed);
});
}
}
use of org.spongepowered.common.event.tracking.PhaseTracker in project SpongeCommon by SpongePowered.
the class ServerLevelMixin_Tracker method shadow$neighborChanged.
@Override
public void shadow$neighborChanged(final BlockPos pos, final Block blockIn, final BlockPos fromPos) {
final BlockPos immutableTarget = pos.immutable();
final BlockPos immutableFrom = fromPos.immutable();
// Sponge Start - Check asynchronicity,
// if not on the server thread and we're a server world, we've got problems...
final PhaseTracker server = PhaseTracker.SERVER;
if (server.getSidedThread() != Thread.currentThread()) {
// lol no, report the block change properly
new PrettyPrinter(60).add("Illegal Async PhaseTracker Access").centre().hr().addWrapped(PhasePrinter.ASYNC_TRACKER_ACCESS).add().add(new Exception("Async Block Notifcation Detected")).log(SpongeCommon.logger(), Level.ERROR);
// Maybe? I don't think this is wise to try and sync back a notification on the main thread.
return;
}
// world that Sponge isn't directly managing, so we'll just ignore trying to record on those.
if (this.bridge$isFake()) {
// If we're fake, well, we could effectively call this without recording on worlds we don't
// want to care about.
super.shadow$neighborChanged(immutableTarget, blockIn, immutableFrom);
return;
}
// Otherwise, we continue with recording, maybe.
final LevelChunk targetChunk = this.shadow$getChunkAt(immutableTarget);
final BlockState targetBlockState = targetChunk.getBlockState(immutableTarget);
// Sponge - Shortcircuit if the block has no neighbor logic
if (!((TrackableBlockBridge) targetBlockState.getBlock()).bridge$overridesNeighborNotificationLogic()) {
return;
}
// Sponge End
// Sponge start - prepare notification
final PhaseContext<@NonNull ?> peek = server.getPhaseContext();
// try { // Vanilla - We need to push the effect transactor so that it always pops
try {
final Supplier<ServerLevel> worldSupplier = VolumeStreamUtils.createWeaklyReferencedSupplier((ServerLevel) (Object) this, "ServerWorld");
final net.minecraft.world.level.block.entity.@Nullable BlockEntity existingTile = targetChunk.getBlockEntity(immutableTarget, LevelChunk.EntityCreationType.CHECK);
peek.getTransactor().logNeighborNotification(worldSupplier, immutableFrom, blockIn, immutableTarget, targetBlockState, existingTile);
peek.associateNeighborStateNotifier(immutableFrom, targetBlockState.getBlock(), immutableTarget, ((ServerLevel) (Object) this), PlayerTracker.Type.NOTIFIER);
// Sponge End
targetBlockState.neighborChanged(((ServerLevel) (Object) this), immutableTarget, blockIn, immutableFrom, false);
} catch (final Throwable throwable) {
final CrashReport crashreport = CrashReport.forThrowable(throwable, "Exception while updating neighbours");
final CrashReportCategory crashreportcategory = crashreport.addCategory("Block being updated");
crashreportcategory.setDetail("Source block type", () -> {
try {
return String.format("ID #%d (%s // %s)", Registry.BLOCK.getId(blockIn), blockIn.getDescriptionId(), blockIn.getClass().getCanonicalName());
} catch (final Throwable var2) {
return "ID #" + Registry.BLOCK.getId(blockIn);
}
});
CrashReportCategory.populateBlockDetails(crashreportcategory, immutableTarget, targetBlockState);
throw new ReportedException(crashreport);
}
}
use of org.spongepowered.common.event.tracking.PhaseTracker in project SpongeCommon by SpongePowered.
the class ServerLevelMixin_Tracker method tracker$throwPreEventAndRecord.
@Inject(method = "addEntity(Lnet/minecraft/world/entity/Entity;)Z", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;getX()D"), cancellable = true)
private void tracker$throwPreEventAndRecord(final Entity entityIn, final CallbackInfoReturnable<Boolean> cir) {
if (this.bridge$isFake()) {
return;
}
final PhaseTracker tracker = PhaseTracker.SERVER;
if (tracker.getSidedThread() != Thread.currentThread()) {
// TODO - async entity spawn logging
return;
}
final PhaseContext<@NonNull ?> current = tracker.getPhaseContext();
if (!current.doesAllowEntitySpawns()) {
cir.setReturnValue(false);
return;
}
try (final CauseStackManager.StackFrame frame = tracker.pushCauseFrame()) {
final List<org.spongepowered.api.entity.Entity> entities = new ArrayList<>();
entities.add((org.spongepowered.api.entity.Entity) entityIn);
frame.addContext(EventContextKeys.SPAWN_TYPE, current.getSpawnTypeForTransaction(entityIn));
final SpawnEntityEvent.Pre pre = SpongeEventFactory.createSpawnEntityEventPre(frame.currentCause(), entities);
Sponge.eventManager().post(pre);
if (pre.isCancelled() || entities.isEmpty()) {
cir.setReturnValue(false);
return;
}
}
if (current.allowsBulkEntityCaptures()) {
current.getTransactor().logEntitySpawn(current, this, entityIn);
}
}
use of org.spongepowered.common.event.tracking.PhaseTracker in project SpongeCommon by SpongePowered.
the class EntityMixin_Tracker method tracker$ensureDropEffectCompleted.
@Inject(method = "remove()V", at = @At("RETURN"))
private void tracker$ensureDropEffectCompleted(final CallbackInfo ci) {
final PhaseTracker instance = PhaseTracker.SERVER;
if (!instance.onSidedThread()) {
return;
}
if (((LevelBridge) this.level).bridge$isFake()) {
return;
}
final PhaseContext<@NonNull ?> context = instance.getPhaseContext();
if (!context.doesBlockEventTracking()) {
return;
}
if (this.tracker$dropsTransactor != null) {
this.tracker$dropsTransactor.close();
}
}
Aggregations