use of net.minecraft.server.level.ServerLevel in project SpongeCommon by SpongePowered.
the class WorldPipeline method processEffects.
public boolean processEffects(final PhaseContext<?> context, final BlockState currentState, final BlockState newProposedState, final BlockPos pos, @Nullable final Entity destroyer, final SpongeBlockChangeFlag flag, final int limit) {
if (this.worldEffects.isEmpty()) {
return false;
}
final ServerLevel serverWorld = Objects.requireNonNull(this.serverWorld).get();
// Keep track of the existing block entity prior to processing the chunk pipeline
// and the reasoning is that in several cases where the block entity that is being removed
// will no longer be available. This could be avoided by having the "previous cursor" returned
// from ChunkPipeline, but alas.... that's a refactor for another time.
@Nullable final BlockEntity existing = this.chunkSupplier.get().getBlockEntity(pos, LevelChunk.EntityCreationType.CHECK);
// We have to get the "old state" from
@Nullable final BlockState oldState = this.chunkPipeline.processChange(context, currentState, newProposedState, pos, limit);
if (oldState == null) {
return false;
}
final int oldOpacity = oldState.getLightBlock(serverWorld, pos);
PipelineCursor formerState = new PipelineCursor(oldState, oldOpacity, pos, existing, destroyer, limit);
for (final ResultingTransactionBySideEffect effect : this.worldEffects) {
try (final EffectTransactor ignored = context.getTransactor().pushEffect(effect)) {
final EffectResult result = effect.effect.processSideEffect(this, formerState, newProposedState, flag, limit);
if (result.hasResult) {
return result.resultingState != null;
}
if (formerState.drops.isEmpty() && !result.drops.isEmpty()) {
formerState = new PipelineCursor(oldState, oldOpacity, pos, existing, formerState.destroyer, result.drops, limit);
}
}
}
// if we've gotten here, means something is wrong, we didn't build our effects right.
return false;
}
use of net.minecraft.server.level.ServerLevel in project SpongeCommon by SpongePowered.
the class LevelChunkMixin_Tracker method bridge$createChunkPipeline.
/**
* Technically a full overwrite for {@link LevelChunk#setBlockState(BlockPos, BlockState, boolean)}
* and due to Sponge's hijacking of {@link ServerLevel#setBlock(BlockPos, BlockState, int)},
* it needs to be able to record transactions when necessary. This implementation allows for us to
* further specify the types of transactions and what proxies are needing to set up where.
*
* @param pos The position changing
* @param newState The new state
* @param currentState The current state - passed in from either chunk or world
* @param flag The sponge change flag, converted from an int to a proper struct
* @return The changed block state if not null
* @author gabizou - January 13th, 2020 - Minecraft 1.14.3
*/
@Override
@NonNull
public ChunkPipeline bridge$createChunkPipeline(final BlockPos pos, final BlockState newState, final BlockState currentState, final SpongeBlockChangeFlag flag, final int limit) {
final boolean isFake = ((LevelBridge) this.level).bridge$isFake();
if (isFake) {
throw new IllegalStateException("Cannot call ChunkBridge.bridge$buildChunkPipeline in non-Server managed worlds");
}
// int i = pos.getX() & 15;
final int xPos = pos.getX() & 15;
// int j = pos.getY();
final int yPos = pos.getY();
// int k = pos.getZ() & 15;
final int zPos = pos.getZ() & 15;
// Sponge - get the moving flag from our flag construct
LevelChunkSection chunksection = this.sections[yPos >> 4];
if (chunksection == LevelChunkMixin_Tracker.EMPTY_SECTION) {
if (newState.isAir()) {
return ChunkPipeline.nullReturn((LevelChunk) (Object) this, (ServerLevel) this.level);
}
chunksection = new LevelChunkSection(yPos >> 4 << 4);
this.sections[yPos >> 4] = chunksection;
}
// Sponge Start - Build out the BlockTransaction
final PhaseContext<@NonNull ?> context = PhaseTracker.getInstance().getPhaseContext();
@Nullable final BlockEntity existing = this.shadow$getBlockEntity(pos, LevelChunk.EntityCreationType.CHECK);
// Build a transaction maybe?
final WeakReference<ServerLevel> ref = new WeakReference<>((ServerLevel) this.level);
final SpongeBlockSnapshot snapshot = TrackingUtil.createPooledSnapshot(currentState, pos, flag, limit, existing, () -> Objects.requireNonNull(ref.get(), "ServerWorld dereferenced"), Optional::empty, Optional::empty);
// Pulled up from below
final ChangeBlock transaction = context.createTransaction(snapshot, newState, flag);
snapshot.blockChange = context.associateBlockChangeWithSnapshot(newState, currentState);
if (((BlockStateBridge) snapshot.state()).bridge$hasTileEntity() && (snapshot.blockChange == BlockChange.BREAK || snapshot.blockChange == BlockChange.MODIFY)) {
transaction.queuedRemoval = existing;
}
final ChunkPipeline.Builder builder = ChunkPipeline.builder().kickOff(transaction).chunk((LevelChunk) (Object) this).chunkSection(chunksection).world((ServerLevel) this.level);
// Populate the effects
transaction.populateChunkEffects(builder);
return builder.build();
}
use of net.minecraft.server.level.ServerLevel in project SpongeCommon by SpongePowered.
the class EndDragonFightMixin_Tracker method tracker$switchToFeatureState.
// @formatter:on
@Redirect(method = "spawnNewGateway(Lnet/minecraft/core/BlockPos;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/levelgen/feature/ConfiguredFeature;place(Lnet/minecraft/world/level/WorldGenLevel;Lnet/minecraft/world/level/chunk/ChunkGenerator;Ljava/util/Random;Lnet/minecraft/core/BlockPos;)Z"))
private boolean tracker$switchToFeatureState(final ConfiguredFeature configuredFeature, final WorldGenLevel worldIn, final ChunkGenerator generator, final Random rand, final BlockPos pos) {
try (final FeaturePhaseContext context = GenerationPhase.State.FEATURE_PLACEMENT.createPhaseContext(PhaseTracker.SERVER)) {
context.world((ServerLevel) worldIn).generator(generator).feature(configuredFeature.feature).origin(pos);
context.buildAndSwitch();
return configuredFeature.place(worldIn, generator, rand, pos);
}
}
use of net.minecraft.server.level.ServerLevel in project SpongeCommon by SpongePowered.
the class ExplosionMixin_Tracker method finalizeExplosion.
/**
* @author gabziou
* @author zidane
* @reason Run explosion logic through tracking
*/
@Overwrite
public void finalizeExplosion(final boolean spawnParticles) {
// Sponge Start - In Sponge, we no longer call doExplosionB client-side (kills client perf)
if (this.level.isClientSide) {
return;
}
// Sponge End
// Sponge Start - Send the sound packet down. We must do this as we do not call doExplosionB client-side
this.level.playSound(null, this.x, this.y, this.z, SoundEvents.GENERIC_EXPLODE, SoundSource.BLOCKS, 4.0F, (1.0F + (this.level.random.nextFloat() - this.level.random.nextFloat()) * 0.2F) * 0.7F);
// Sponge End
final boolean flag = this.blockInteraction != net.minecraft.world.level.Explosion.BlockInteraction.NONE;
if (spawnParticles) {
if (!(this.radius < 2.0F) && (flag || ((ExplosionBridge) this).bridge$getShouldDamageBlocks())) {
// hundreds of explosions at once
if (this.level instanceof ServerLevel) {
((ServerLevel) this.level).sendParticles(ParticleTypes.EXPLOSION_EMITTER, this.x, this.y, this.z, 1, 0, 0, 0, 0.1D);
} else {
this.level.addParticle(ParticleTypes.EXPLOSION_EMITTER, this.x, this.y, this.z, 1.0D, 0.0D, 0.0D);
}
// Sponge End
} else {
// hundreds of explosions at once
if (this.level instanceof ServerLevel) {
((ServerLevel) this.level).sendParticles(ParticleTypes.EXPLOSION, this.x, this.y, this.z, 1, 0, 0, 0, 0.1D);
} else {
this.level.addParticle(ParticleTypes.EXPLOSION, this.x, this.y, this.z, 1.0D, 0.0D, 0.0D);
}
// Sponge End
}
}
if (flag) {
// Sponge Start - Forward changes through a WorldPipeline to associate side effects
// Vanilla - uses a list of itemstacks to do a bunch of pre-merging
// ObjectArrayList<Pair<ItemStack, BlockPos>> objectarraylist = new ObjectArrayList<>();
Collections.shuffle(this.toBlow, this.level.random);
for (final BlockPos blockpos : this.toBlow) {
final BlockState blockstate = this.level.getBlockState(blockpos);
// Block block = blockstate.getBlock(); // Sponge - we don't use this
if (!blockstate.isAir()) {
final BlockPos blockpos1 = blockpos.immutable();
this.level.getProfiler().push("explosion_blocks");
// Sponge - All of this is forwarded to the effects
// if (block.canDropFromExplosion(this) && this.level instanceof ServerLevel) {
// BlockEntity var6 = block.isEntityBlock() ? this.level.getBlockEntity(blockpos) : null;
// LootContext.Builder lootcontext$builder = (new LootContext.Builder((ServerLevel)this.level)).withRandom(this.level.rand).withParameter(
// LootParameters.ORIGIN, Vec3.atCenterOf(blockpos)).withParameter(LootParameters.TOOL, ItemStack.EMPTY).withNullableParameter(LootParameters.BLOCK_ENTITY, var6).withNullableParameter(LootParameters.THIS_ENTITY, this.source);
// if (this.blockInteraction == Explosion.BlockInteraction.DESTROY) {
// lootcontext$builder.withParameter(LootParameters.EXPLOSION_RADIUS, this.radius);
// }
// var3.getDrops(var7).forEach((param2) -> addBlockDrops(var1, param2, var5));
// }
// this.level.setBlock(blockpos, Blocks.AIR.defaultState(), 3);
// block.onExplosionDestroy(this.world, blockpos, this);
final PhaseContext<@NonNull ?> context = PhaseTracker.getInstance().getPhaseContext();
((TrackedWorldBridge) this.level).bridge$startBlockChange(blockpos1, Blocks.AIR.defaultBlockState(), 3).ifPresent(builder -> {
final WorldPipeline build = builder.addEffect(AddBlockLootDropsEffect.getInstance()).addEffect(ExplodeBlockEffect.getInstance()).addEffect(SpawnDestructBlocksEffect.getInstance()).addEffect(WorldBlockChangeCompleteEffect.getInstance()).build();
build.processEffects(context, blockstate, Blocks.AIR.defaultBlockState(), blockpos1, null, BlockChangeFlagManager.fromNativeInt(3), Constants.World.DEFAULT_BLOCK_CHANGE_LIMIT);
});
// Sponge End
this.level.getProfiler().pop();
}
}
// Sponge Start - This is built into the SpawnDestructBlocksEffect
// for(Pair<ItemStack, BlockPos> var8 : objectarraylist) {
// Block.popResource(this.level, var8.getSecond(), var8.getFirst());
// }
// Sponge End
}
if (this.fire) {
for (final BlockPos blockpos2 : this.toBlow) {
if (this.random.nextInt(3) == 0 && this.level.getBlockState(blockpos2).isAir() && this.level.getBlockState(blockpos2.below()).isSolidRender(this.level, blockpos2.below())) {
this.level.setBlockAndUpdate(blockpos2, BaseFireBlock.getState(this.level, blockpos2));
}
}
}
}
use of net.minecraft.server.level.ServerLevel in project SpongeCommon by SpongePowered.
the class SpongeUserData method create.
public static SpongeUserData create(final GameProfile profile) throws IOException {
final ServerLevel world = SpongeCommon.server().overworld();
if (world == null) {
SpongeCommon.logger().warn("Overworld not initialized, cannot create users!");
throw new IllegalStateException("Overworld not initialized, cannot create users!");
}
final LevelStorageSource.LevelStorageAccess storageSource = ((MinecraftServerAccessor) Sponge.server()).accessor$storageSource();
final File file = storageSource.getLevelPath(LevelResource.PLAYER_DATA_DIR).resolve(profile.getId().toString() + ".dat").toFile();
if (!file.exists()) {
return new SpongeUserData(profile, new CompoundTag());
}
try {
final CompoundTag compound;
try (final FileInputStream in = new FileInputStream(file)) {
compound = NbtIo.readCompressed(in);
}
// See PlayerDataAccess - keep this line up to date.
final int version = compound.contains("DataVersion", 3) ? compound.getInt("DataVersion") : -1;
NbtUtils.update(DataFixers.getDataFixer(), DataFixTypes.PLAYER, compound, version);
return new SpongeUserData(profile, compound);
} catch (final IOException e) {
SpongeCommon.logger().warn("Unable to load corrupt user file '{}'!", file.toPath().relativize(Paths.get("")).toString(), e);
FileUtil.copyCorruptedFile(file);
throw e;
}
}
Aggregations