use of org.spongepowered.api.world.server.ServerWorld in project SpongeCommon by SpongePowered.
the class EntityMixin method bridge$changeDimension.
/**
* This is effectively an overwrite of changeDimension: required due to
* Forge changing the signature.
*
* @author dualspiral - 18th December 2020 - 1.16.4
* @author dualspiral - 8th August 2021 - 1.16.5 (adjusted for SpongeForge)
*
* @param originalDestinationWorld The original target world
* @param originalPortalLogic performs additional teleportation logic, as required.
* @return The {@link Entity} that is either this one, or replaces this one
*/
@SuppressWarnings("ConstantConditions")
@org.checkerframework.checker.nullness.qual.Nullable
public Entity bridge$changeDimension(final net.minecraft.server.level.ServerLevel originalDestinationWorld, final PortalLogic originalPortalLogic) {
// Sponge Start
if (this.shadow$getCommandSenderWorld().isClientSide || this.removed) {
return null;
}
final boolean isPlayer = ((Object) this) instanceof ServerPlayer;
final TeleportContext contextToSwitchTo = EntityPhase.State.PORTAL_DIMENSION_CHANGE.createPhaseContext(PhaseTracker.getInstance()).worldChange();
if (isPlayer) {
contextToSwitchTo.player();
}
try (final TeleportContext context = contextToSwitchTo.buildAndSwitch();
final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) {
frame.pushCause(this);
frame.pushCause(originalPortalLogic.getPortalType());
frame.addContext(EventContextKeys.MOVEMENT_TYPE, originalPortalLogic.getMovementType());
this.impl$originalDestinationWorld = new WeakReference<>((ServerWorld) originalDestinationWorld);
final ChangeEntityWorldEvent.Pre preChangeEvent = PlatformHooks.INSTANCE.getEventHooks().callChangeEntityWorldEventPre((Entity) (Object) this, originalDestinationWorld);
if (preChangeEvent.isCancelled()) {
this.impl$onPreWorldChangeCanceled();
return null;
}
this.impl$customPortal = preChangeEvent.originalDestinationWorld() != preChangeEvent.destinationWorld();
final PortalLogic finalPortalLogic;
if (this.impl$customPortal && originalPortalLogic == originalDestinationWorld.getPortalForcer()) {
finalPortalLogic = (PortalLogic) ((ServerLevel) preChangeEvent.destinationWorld()).getPortalForcer();
} else {
finalPortalLogic = originalPortalLogic;
}
final net.minecraft.server.level.ServerLevel targetWorld = (net.minecraft.server.level.ServerLevel) preChangeEvent.destinationWorld();
final Vector3d currentPosition = VecHelper.toVector3d(this.shadow$position());
// If a player, set the fact they are changing dimensions
this.impl$onChangingDimension(targetWorld);
final net.minecraft.server.level.ServerLevel serverworld = (net.minecraft.server.level.ServerLevel) this.level;
final ResourceKey<Level> registrykey = serverworld.dimension();
if (isPlayer && registrykey == Level.END && targetWorld.dimension() == Level.OVERWORLD && finalPortalLogic.isVanilla()) {
// avoids modded dimensions
return this.impl$postProcessChangeDimension(this.impl$performGameWinLogic());
} else {
// Sponge Start: Redirect the find portal call to the teleporter.
// If this is vanilla, this will house our Reposition Event and return an appropriate
// portal info
final PortalInfo portalinfo = originalPortalLogic.getPortalInfo((Entity) (Object) this, targetWorld, // don't make this a method reference, it'll crash vanilla.
x -> this.shadow$findDimensionEntryPoint(x));
// Sponge End
if (portalinfo != null) {
if (portalinfo instanceof SpongePortalInfo) {
frame.addContext(EventContextKeys.PORTAL, ((SpongePortalInfo) portalinfo).portal());
}
// Only start teleporting if we have somewhere to go.
this.impl$prepareForPortalTeleport(serverworld, targetWorld);
try {
// Sponge Start: wrap the teleportation logic within a function to allow for modification
// of the teleporter
final Vector3d originalDestination = new Vector3d(portalinfo.pos.x, portalinfo.pos.y, portalinfo.pos.z);
// Note that impl$portalRepositioning is the lambda. As this will be different in ServerPlayer,
// we transfer it to a method instead so we can override it.
final Entity transportedEntity = originalPortalLogic.placeEntity((Entity) (Object) this, serverworld, targetWorld, this.yRot, createEndPlatform -> this.impl$portalRepositioning(createEndPlatform, serverworld, targetWorld, portalinfo));
// Make sure the right object was returned
this.impl$validateEntityAfterTeleport(transportedEntity, originalPortalLogic);
// If we need to reposition: well... reposition.
// Downside: portals won't come with us, but with how it's implemented in Forge,
// not sure how we'd do this.
//
// If this is vanilla, we've already fired and dealt with the event
final Cause cause = PhaseTracker.getCauseStackManager().currentCause();
if (transportedEntity != null && this.impl$shouldFireRepositionEvent) {
final Vector3d destination = VecHelper.toVector3d(this.shadow$position());
final ChangeEntityWorldEvent.Reposition reposition = SpongeEventFactory.createChangeEntityWorldEventReposition(cause, (org.spongepowered.api.entity.Entity) transportedEntity, (org.spongepowered.api.world.server.ServerWorld) serverworld, currentPosition, destination, (org.spongepowered.api.world.server.ServerWorld) originalDestinationWorld, originalDestination, (org.spongepowered.api.world.server.ServerWorld) targetWorld);
final Vector3d finalPosition;
if (reposition.isCancelled()) {
// send them back to the original destination
finalPosition = originalDestination;
} else if (reposition.destinationPosition() != destination) {
finalPosition = reposition.destinationPosition();
} else {
finalPosition = null;
}
if (finalPosition != null) {
// TODO: Rollback captures during phase - anything generated needs to vanish here
// Issue chunk ticket of type Portal, even if a portal isn't being created here.
final BlockPos ticketPos = VecHelper.toBlockPos(finalPosition);
targetWorld.getChunkSource().addRegionTicket(TicketType.PORTAL, new ChunkPos(ticketPos), 3, ticketPos);
this.shadow$absMoveTo(finalPosition.x(), finalPosition.y(), finalPosition.z());
}
}
// Used to perform player specific tasks.
this.impl$postPortalForceChangeTasks(transportedEntity, targetWorld, originalPortalLogic.getPortalType() instanceof NetherPortalType);
// Call post event
Sponge.eventManager().post(SpongeEventFactory.createChangeEntityWorldEventPost(cause, (org.spongepowered.api.entity.Entity) this, (ServerWorld) serverworld, (ServerWorld) originalDestinationWorld, (ServerWorld) targetWorld));
} catch (final RuntimeException e) {
// just in case a mod does something less than clever.
if ((Object) this instanceof ServerPlayer) {
this.impl$postPortalForceChangeTasks((Entity) (Object) this, (net.minecraft.server.level.ServerLevel) this.level, false);
}
throw e;
}
// Sponge End
} else {
// Didn't work out.
return null;
}
}
return this.impl$postProcessChangeDimension((Entity) (Object) this);
} finally {
// Reset for the next attempt.
this.impl$shouldFireRepositionEvent = true;
this.impl$originalDestinationWorld = null;
this.impl$customPortal = false;
}
}
use of org.spongepowered.api.world.server.ServerWorld in project SpongeCommon by SpongePowered.
the class EntityMixin method impl$fireRepositionEventWhenFindingAPortal.
@Inject(method = "getExitPortal", cancellable = true, at = @At("RETURN"))
private void impl$fireRepositionEventWhenFindingAPortal(final net.minecraft.server.level.ServerLevel targetWorld, final BlockPos targetPosition, final boolean targetIsNether, final CallbackInfoReturnable<Optional<BlockUtil.FoundRectangle>> cir) {
if (this.impl$shouldFireRepositionEvent) {
// This exists as we're injecting at return
final Optional<BlockUtil.FoundRectangle> result = cir.getReturnValue();
final Vector3d destinationPosition = result.map(this::impl$getEntityPositionInPotentialExitPortal).orElseGet(() -> VecHelper.toVector3d(targetPosition));
final ServerWorld originalDestinationWorld;
if (this.impl$originalDestinationWorld != null && this.impl$originalDestinationWorld.get() != null) {
originalDestinationWorld = this.impl$originalDestinationWorld.get();
} else {
originalDestinationWorld = (ServerWorld) targetWorld;
}
final ChangeEntityWorldEvent.Reposition reposition = this.bridge$fireRepositionEvent(originalDestinationWorld, (ServerWorld) targetWorld, destinationPosition);
if (!reposition.isCancelled() && reposition.destinationPosition() != destinationPosition) {
// Something changed so we want to re-rerun this loop.
// TODO: There is an open question here about whether we want to force the creation of a portal in this
// scenario, or whether we're happy if the repositioning will put someone in a nearby portal.
cir.setReturnValue(this.shadow$getExitPortal(targetWorld, VecHelper.toBlockPos(reposition.destinationPosition()), targetIsNether));
this.impl$dontCreateExitPortal = true;
}
}
}
use of org.spongepowered.api.world.server.ServerWorld in project SpongeCommon by SpongePowered.
the class EntityMixin method bridge$setLocation.
@Override
public boolean bridge$setLocation(final ServerLocation location) {
if (this.removed || ((LevelBridge) location.world()).bridge$isFake()) {
return false;
}
try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) {
frame.addContext(EventContextKeys.MOVEMENT_TYPE, MovementTypes.PLUGIN);
final net.minecraft.server.level.ServerLevel originalWorld = (ServerLevel) this.shadow$getCommandSenderWorld();
final net.minecraft.server.level.ServerLevel originalDestinationWorld = (net.minecraft.server.level.ServerLevel) location.world();
final net.minecraft.server.level.ServerLevel destinationWorld;
@org.checkerframework.checker.nullness.qual.Nullable final Vector3d destinationPosition;
final boolean isChangeOfWorld = this.shadow$getCommandSenderWorld() != originalDestinationWorld;
if (isChangeOfWorld) {
final ChangeEntityWorldEvent.Pre event = PlatformHooks.INSTANCE.getEventHooks().callChangeEntityWorldEventPre((Entity) (Object) this, originalDestinationWorld);
if (event.isCancelled() || ((LevelBridge) event.destinationWorld()).bridge$isFake()) {
return false;
}
destinationWorld = (ServerLevel) event.destinationWorld();
final ChangeEntityWorldEvent.Reposition repositionEvent = this.bridge$fireRepositionEvent(event.originalDestinationWorld(), event.destinationWorld(), location.position());
if (repositionEvent.isCancelled()) {
return false;
}
destinationPosition = repositionEvent.destinationPosition();
} else {
destinationWorld = (ServerLevel) this.level;
destinationPosition = this.impl$fireMoveEvent(PhaseTracker.SERVER, location.position());
if (destinationPosition == null) {
return false;
}
}
final boolean completed = this.impl$setLocation(isChangeOfWorld, originalDestinationWorld, destinationWorld, destinationPosition);
if (isChangeOfWorld) {
Sponge.eventManager().post(SpongeEventFactory.createChangeEntityWorldEventPost(PhaseTracker.getCauseStackManager().currentCause(), (org.spongepowered.api.entity.Entity) this, (ServerWorld) originalWorld, (ServerWorld) originalDestinationWorld, (ServerWorld) destinationWorld));
}
return completed;
}
}
use of org.spongepowered.api.world.server.ServerWorld in project SpongeCommon by SpongePowered.
the class LivingEntityMixin method impl$callFinishSleepingEvent.
// End implementation of UseItemStackEvent
@Inject(method = "stopSleeping", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;clearSleepingPos()V"))
private void impl$callFinishSleepingEvent(final CallbackInfo ci) {
if (this.level.isClientSide) {
return;
}
final Optional<BlockPos> sleepingPos = this.shadow$getSleepingPos();
if (!sleepingPos.isPresent()) {
return;
}
final BlockSnapshot snapshot = ((ServerWorld) this.level).createSnapshot(sleepingPos.get().getX(), sleepingPos.get().getY(), sleepingPos.get().getZ());
final Cause currentCause = Sponge.server().causeStackManager().currentCause();
final ServerLocation loc = ServerLocation.of((ServerWorld) this.level, VecHelper.toVector3d(this.shadow$position()));
final Vector3d rot = ((Living) this).rotation();
final SleepingEvent.Finish event = SpongeEventFactory.createSleepingEventFinish(currentCause, loc, loc, rot, rot, snapshot, (Living) this);
Sponge.eventManager().post(event);
this.shadow$clearSleepingPos();
if (event.toLocation().world() != this.level) {
throw new UnsupportedOperationException("World change is not supported here.");
}
this.shadow$setPos(event.toLocation().x(), event.toLocation().y(), event.toLocation().z());
((Living) this).setRotation(event.toRotation());
}
use of org.spongepowered.api.world.server.ServerWorld in project SpongeCommon by SpongePowered.
the class NoteBlockMixin method impl$throwNoteBlockSoundEvent.
@SuppressWarnings("ConstantConditions")
@Inject(method = "triggerEvent", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;playSound(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/core/BlockPos;Lnet/minecraft/sounds/SoundEvent;Lnet/minecraft/sounds/SoundSource;FF)V"), cancellable = true)
private void impl$throwNoteBlockSoundEvent(BlockState state, Level worldIn, BlockPos pos, int id, int param, CallbackInfoReturnable<Boolean> callbackInfo) {
if (!ShouldFire.PLAY_SOUND_EVENT_NOTE_BLOCK) {
return;
}
// No noteblock sounds if the block above it isn't air
if (worldIn.getBlockState(pos.above()).getMaterial() != Material.AIR) {
return;
}
// InstrumentProperty doesn't return what we wan't for the noteblock directly, so we have to check the block under it.
InstrumentType instrumentType = ((ServerWorld) worldIn).block(pos.getX(), pos.getY() - 1, pos.getZ()).get(Keys.REPRESENTED_INSTRUMENT).orElse(null);
if (instrumentType == null) {
return;
}
float pitch = (float) Math.pow(2.0D, (double) (param - 12) / 12.0D);
final MappedRegistry<NotePitch> registry = (MappedRegistry<NotePitch>) (Object) Sponge.game().registry(RegistryTypes.NOTE_PITCH);
final PlaySoundEvent.NoteBlock event = SpongeCommonEventFactory.callPlaySoundNoteBlockEvent(PhaseTracker.getCauseStackManager().currentCause(), (ServerWorld) worldIn, pos, NoteBlockInstrument.byState(state).getSoundEvent(), instrumentType, registry.byId(param), pitch);
if (event.isCancelled()) {
callbackInfo.setReturnValue(true);
}
}
Aggregations