use of net.minecraft.world.level.Level in project SpongeCommon by SpongePowered.
the class ServerGamePacketListenerImplMixin method impl$usePlayerDimensionForRespawn.
@Redirect(method = "handleClientCommand", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/players/PlayerList;respawn(Lnet/minecraft/server/level/ServerPlayer;Z)Lnet/minecraft/server/level/ServerPlayer;"))
private net.minecraft.server.level.ServerPlayer impl$usePlayerDimensionForRespawn(final PlayerList playerList, final net.minecraft.server.level.ServerPlayer player, final boolean keepAllPlayerData) {
// A few changes to Vanilla logic here that, by default, still preserve game mechanics:
// - If we have conquered The End then keep the dimension type we're headed to (which is Overworld as of 1.15)
// - Otherwise, check the platform hooks for which dimension to respawn to. In Sponge, this is the Player's dimension they
// are already in if we can respawn there which is only true for Overworld dimensions
final ResourceKey<Level> respawnDimension = player.getRespawnDimension();
@Nullable final ServerLevel destinationWorld = this.server.getLevel(respawnDimension);
final ServerLevel overworld = this.server.getLevel(Level.OVERWORLD);
if (overworld == null) {
throw new IllegalStateException("Somehow the Overworld is not retrievable while trying to respawn player " + player.getGameProfile().getName());
}
final ServerLevel destination = destinationWorld == null ? overworld : destinationWorld;
final RespawnPlayerEvent.SelectWorld event = SpongeEventFactory.createRespawnPlayerEventSelectWorld(PhaseTracker.getCauseStackManager().currentCause(), (org.spongepowered.api.world.server.ServerWorld) destination, (org.spongepowered.api.world.server.ServerWorld) player.getLevel(), (org.spongepowered.api.world.server.ServerWorld) overworld, (ServerPlayer) player);
SpongeCommon.post(event);
((PlayerListBridge) this.server.getPlayerList()).bridge$setOriginalDestinationDimension(((ServerLevel) event.originalDestinationWorld()).dimension());
((PlayerListBridge) this.server.getPlayerList()).bridge$setNewDestinationDimension(((ServerLevel) event.destinationWorld()).dimension());
// The key is reset to null in the overwrite
return playerList.respawn(player, keepAllPlayerData);
}
use of net.minecraft.world.level.Level 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 net.minecraft.world.level.Level in project SpongeCommon by SpongePowered.
the class BlockMixin_Tracker method tracker$captureBlockProposedToBeSpawningDrops.
@Inject(method = "dropResources(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/LevelAccessor;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/entity/BlockEntity;)V", at = @At("HEAD"))
private static void tracker$captureBlockProposedToBeSpawningDrops(final BlockState state, final LevelAccessor worldIn, final BlockPos pos, @Nullable final BlockEntity tileEntity, final CallbackInfo ci) {
if (!(worldIn instanceof Level)) {
// In the name of my father, and his father before him, I cast you out!
return;
}
final PhaseTracker server = PhaseTracker.SERVER;
if (server.getSidedThread() != Thread.currentThread()) {
return;
}
final PhaseContext<@NonNull ?> context = server.getPhaseContext();
BlockMixin_Tracker.tracker$effectTransactorForDrops = context.getTransactor().logBlockDrops((Level) worldIn, pos, state, tileEntity);
}
use of net.minecraft.world.level.Level in project SpongeCommon by SpongePowered.
the class SpongeWorldManager method worldExists.
@Override
public boolean worldExists(final ResourceKey key) {
final net.minecraft.resources.ResourceKey<Level> registryKey = SpongeWorldManager.createRegistryKey(Objects.requireNonNull(key, "key"));
if (Level.OVERWORLD.equals(registryKey)) {
return true;
}
if (this.worlds.get(registryKey) != null) {
return true;
}
final boolean isVanillaSubLevel = Level.NETHER.equals(registryKey) || Level.END.equals(registryKey);
final Path levelDirectory = isVanillaSubLevel ? this.defaultWorldDirectory.resolve(this.getDirectoryName(key)) : this.customWorldsDirectory.resolve(key.namespace()).resolve(key.value());
return Files.exists(levelDirectory);
}
use of net.minecraft.world.level.Level in project SpongeCommon by SpongePowered.
the class SpongeWorldManager method loadWorld0.
private CompletableFuture<org.spongepowered.api.world.server.ServerWorld> loadWorld0(final net.minecraft.resources.ResourceKey<Level> registryKey, final LevelStem template, final WorldGenSettings generatorSettings) {
final PrimaryLevelData defaultLevelData = (PrimaryLevelData) this.server.getWorldData();
final LevelSettings defaultLevelSettings = ((PrimaryLevelDataAccessor) defaultLevelData).accessor$settings();
final LevelStemBridge templateBridge = (LevelStemBridge) (Object) template;
final ResourceKey worldKey = ((ResourceKeyBridge) templateBridge).bridge$getKey();
final WorldType worldType = (WorldType) template.type();
final ResourceKey worldTypeKey = RegistryTypes.WORLD_TYPE.get().valueKey((WorldType) template.type());
MinecraftServerAccessor.accessor$LOGGER().info("Loading world '{}' ({})", worldKey, worldTypeKey);
final String directoryName = this.getDirectoryName(worldKey);
final boolean isVanillaSubLevel = this.isVanillaSubWorld(directoryName);
final LevelStorageSource.LevelStorageAccess storageSource;
try {
if (isVanillaSubLevel) {
storageSource = LevelStorageSource.createDefault(this.defaultWorldDirectory).createAccess(directoryName);
} else {
storageSource = LevelStorageSource.createDefault(this.customWorldsDirectory).createAccess(worldKey.namespace() + File.separator + worldKey.value());
}
} catch (final IOException e) {
e.printStackTrace();
return FutureUtil.completedWithException(new RuntimeException(String.format("Failed to create level data for world '%s'!", worldKey), e));
}
PrimaryLevelData levelData;
levelData = (PrimaryLevelData) storageSource.getDataTag((DynamicOps<Tag>) BootstrapProperties.worldSettingsAdapter, defaultLevelSettings.getDataPackConfig());
if (levelData == null) {
final LevelSettings levelSettings;
final WorldGenSettings generationSettings;
if (this.server.isDemo()) {
levelSettings = MinecraftServer.DEMO_SETTINGS;
generationSettings = WorldGenSettings.demoSettings(BootstrapProperties.registries);
} else {
levelSettings = new LevelSettings(directoryName, (GameType) (Object) BootstrapProperties.gameMode.get(Sponge.game()), templateBridge.bridge$hardcore().orElse(BootstrapProperties.hardcore), (Difficulty) (Object) BootstrapProperties.difficulty.get(Sponge.game()), templateBridge.bridge$commands().orElse(BootstrapProperties.commands), new GameRules(), defaultLevelData.getDataPackConfig());
generationSettings = generatorSettings;
}
levelData = new PrimaryLevelData(levelSettings, generationSettings, Lifecycle.stable());
}
((PrimaryLevelDataBridge) levelData).bridge$populateFromDimension(template);
final InheritableConfigHandle<WorldConfig> configAdapter = SpongeGameConfigs.createWorld(worldTypeKey, worldKey);
((PrimaryLevelDataBridge) levelData).bridge$configAdapter(configAdapter);
levelData.setModdedInfo(this.server.getServerModName(), this.server.getModdedStatus().isPresent());
final boolean isDebugGeneration = levelData.worldGenSettings().isDebug();
final long seed = BiomeManager.obfuscateSeed(levelData.worldGenSettings().seed());
final ChunkProgressListener chunkStatusListener = ((MinecraftServerAccessor) this.server).accessor$progressListenerFactory().create(11);
final ServerLevel world = new ServerLevel(this.server, ((MinecraftServerAccessor) this.server).accessor$executor(), storageSource, levelData, registryKey, (DimensionType) worldType, chunkStatusListener, template.generator(), isDebugGeneration, seed, ImmutableList.of(), true);
this.worlds.put(registryKey, world);
return SpongeCommon.asyncScheduler().submit(() -> this.prepareWorld(world, isDebugGeneration)).thenApply(w -> {
((MinecraftServerAccessor) this.server).invoker$forceDifficulty();
return w;
}).thenCompose(w -> this.postWorldLoad(w, false)).thenApply(w -> (org.spongepowered.api.world.server.ServerWorld) w);
}
Aggregations