/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.google.common.collect.Lists * com.mojang.serialization.Codec * org.apache.commons.lang3.mutable.MutableBoolean * org.jspecify.annotations.Nullable */ package net.minecraft.world.level; import com.google.common.collect.Lists; import com.mojang.serialization.Codec; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.UUID; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Collectors; import net.minecraft.CrashReport; import net.minecraft.CrashReportCategory; import net.minecraft.ReportedException; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Holder; import net.minecraft.core.RegistryAccess; import net.minecraft.core.SectionPos; import net.minecraft.core.particles.ExplosionParticleInfo; import net.minecraft.core.particles.ParticleOptions; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.network.protocol.Packet; import net.minecraft.resources.Identifier; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.FullChunkStatus; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.util.AbortableIterationConsumer; import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; import net.minecraft.util.StringRepresentable; import net.minecraft.util.profiling.Profiler; import net.minecraft.util.random.WeightedList; import net.minecraft.world.TickRateManager; import net.minecraft.world.attribute.EnvironmentAttributeSystem; import net.minecraft.world.attribute.EnvironmentAttributes; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.damagesource.DamageSources; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySelector; import net.minecraft.world.entity.boss.EnderDragonPart; import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.alchemy.PotionBrewing; import net.minecraft.world.item.component.FireworkExplosion; import net.minecraft.world.item.crafting.RecipeAccess; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Explosion; import net.minecraft.world.level.ExplosionDamageCalculator; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeManager; import net.minecraft.world.level.block.BaseFireBlock; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.FuelValues; import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.PalettedContainerFactory; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.entity.EntityTypeTest; import net.minecraft.world.level.entity.LevelEntityGetter; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.Fluids; import net.minecraft.world.level.redstone.CollectingNeighborUpdater; import net.minecraft.world.level.redstone.Orientation; import net.minecraft.world.level.saveddata.maps.MapId; import net.minecraft.world.level.saveddata.maps.MapItemSavedData; import net.minecraft.world.level.storage.LevelData; import net.minecraft.world.level.storage.WritableLevelData; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import net.minecraft.world.scores.Scoreboard; import org.apache.commons.lang3.mutable.MutableBoolean; import org.jspecify.annotations.Nullable; public abstract class Level implements LevelAccessor, AutoCloseable { public static final Codec> RESOURCE_KEY_CODEC = ResourceKey.codec(Registries.DIMENSION); public static final ResourceKey OVERWORLD = ResourceKey.create(Registries.DIMENSION, Identifier.withDefaultNamespace("overworld")); public static final ResourceKey NETHER = ResourceKey.create(Registries.DIMENSION, Identifier.withDefaultNamespace("the_nether")); public static final ResourceKey END = ResourceKey.create(Registries.DIMENSION, Identifier.withDefaultNamespace("the_end")); public static final int MAX_LEVEL_SIZE = 30000000; public static final int LONG_PARTICLE_CLIP_RANGE = 512; public static final int SHORT_PARTICLE_CLIP_RANGE = 32; public static final int MAX_BRIGHTNESS = 15; public static final int MAX_ENTITY_SPAWN_Y = 20000000; public static final int MIN_ENTITY_SPAWN_Y = -20000000; private static final WeightedList DEFAULT_EXPLOSION_BLOCK_PARTICLES = WeightedList.builder().add(new ExplosionParticleInfo(ParticleTypes.POOF, 0.5f, 1.0f)).add(new ExplosionParticleInfo(ParticleTypes.SMOKE, 1.0f, 1.0f)).build(); protected final List blockEntityTickers = Lists.newArrayList(); protected final CollectingNeighborUpdater neighborUpdater; private final List pendingBlockEntityTickers = Lists.newArrayList(); private boolean tickingBlockEntities; private final Thread thread; private final boolean isDebug; private int skyDarken; protected int randValue = RandomSource.create().nextInt(); protected final int addend = 1013904223; protected float oRainLevel; protected float rainLevel; protected float oThunderLevel; protected float thunderLevel; public final RandomSource random = RandomSource.create(); @Deprecated private final RandomSource threadSafeRandom = RandomSource.createThreadSafe(); private final Holder dimensionTypeRegistration; protected final WritableLevelData levelData; private final boolean isClientSide; private final BiomeManager biomeManager; private final ResourceKey dimension; private final RegistryAccess registryAccess; private final DamageSources damageSources; private final PalettedContainerFactory palettedContainerFactory; private long subTickCount; protected Level(WritableLevelData levelData, ResourceKey dimension, RegistryAccess registryAccess, Holder dimensionTypeRegistration, boolean isClientSide, boolean isDebug, long biomeZoomSeed, int maxChainedNeighborUpdates) { this.levelData = levelData; this.dimensionTypeRegistration = dimensionTypeRegistration; this.dimension = dimension; this.isClientSide = isClientSide; this.thread = Thread.currentThread(); this.biomeManager = new BiomeManager(this, biomeZoomSeed); this.isDebug = isDebug; this.neighborUpdater = new CollectingNeighborUpdater(this, maxChainedNeighborUpdates); this.registryAccess = registryAccess; this.palettedContainerFactory = PalettedContainerFactory.create(registryAccess); this.damageSources = new DamageSources(registryAccess); } @Override public boolean isClientSide() { return this.isClientSide; } @Override public @Nullable MinecraftServer getServer() { return null; } public boolean isInWorldBounds(BlockPos pos) { return !this.isOutsideBuildHeight(pos) && Level.isInWorldBoundsHorizontal(pos); } public static boolean isInSpawnableBounds(BlockPos pos) { return !Level.isOutsideSpawnableHeight(pos.getY()) && Level.isInWorldBoundsHorizontal(pos); } private static boolean isInWorldBoundsHorizontal(BlockPos pos) { return pos.getX() >= -30000000 && pos.getZ() >= -30000000 && pos.getX() < 30000000 && pos.getZ() < 30000000; } private static boolean isOutsideSpawnableHeight(int y) { return y < -20000000 || y >= 20000000; } public LevelChunk getChunkAt(BlockPos pos) { return this.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())); } @Override public LevelChunk getChunk(int chunkX, int chunkZ) { return (LevelChunk)this.getChunk(chunkX, chunkZ, ChunkStatus.FULL); } @Override public @Nullable ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus status, boolean loadOrGenerate) { ChunkAccess chunk = this.getChunkSource().getChunk(chunkX, chunkZ, status, loadOrGenerate); if (chunk == null && loadOrGenerate) { throw new IllegalStateException("Should always be able to create a chunk!"); } return chunk; } @Override public boolean setBlock(BlockPos pos, BlockState blockState, @Block.UpdateFlags int updateFlags) { return this.setBlock(pos, blockState, updateFlags, 512); } @Override public boolean setBlock(BlockPos pos, BlockState blockState, @Block.UpdateFlags int updateFlags, int updateLimit) { if (this.isOutsideBuildHeight(pos)) { return false; } if (!this.isClientSide() && this.isDebug()) { return false; } LevelChunk chunk = this.getChunkAt(pos); Block block = blockState.getBlock(); BlockState oldState = chunk.setBlockState(pos, blockState, updateFlags); if (oldState != null) { BlockState newState = this.getBlockState(pos); if (newState == blockState) { if (oldState != newState) { this.setBlocksDirty(pos, oldState, newState); } if ((updateFlags & 2) != 0 && (!this.isClientSide() || (updateFlags & 4) == 0) && (this.isClientSide() || chunk.getFullStatus() != null && chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING))) { this.sendBlockUpdated(pos, oldState, blockState, updateFlags); } if ((updateFlags & 1) != 0) { this.updateNeighborsAt(pos, oldState.getBlock()); if (!this.isClientSide() && blockState.hasAnalogOutputSignal()) { this.updateNeighbourForOutputSignal(pos, block); } } if ((updateFlags & 0x10) == 0 && updateLimit > 0) { int neighbourUpdateFlags = updateFlags & 0xFFFFFFDE; oldState.updateIndirectNeighbourShapes(this, pos, neighbourUpdateFlags, updateLimit - 1); blockState.updateNeighbourShapes(this, pos, neighbourUpdateFlags, updateLimit - 1); blockState.updateIndirectNeighbourShapes(this, pos, neighbourUpdateFlags, updateLimit - 1); } this.updatePOIOnBlockStateChange(pos, oldState, newState); } return true; } return false; } public void updatePOIOnBlockStateChange(BlockPos pos, BlockState oldState, BlockState newState) { } @Override public boolean removeBlock(BlockPos pos, boolean movedByPiston) { FluidState fluidState = this.getFluidState(pos); return this.setBlock(pos, fluidState.createLegacyBlock(), 3 | (movedByPiston ? 64 : 0)); } @Override public boolean destroyBlock(BlockPos pos, boolean dropResources, @Nullable Entity breaker, int updateLimit) { boolean destroyed; BlockState blockState = this.getBlockState(pos); if (blockState.isAir()) { return false; } FluidState fluidState = this.getFluidState(pos); if (!(blockState.getBlock() instanceof BaseFireBlock)) { this.levelEvent(2001, pos, Block.getId(blockState)); } if (dropResources) { BlockEntity blockEntity = blockState.hasBlockEntity() ? this.getBlockEntity(pos) : null; Block.dropResources(blockState, this, pos, blockEntity, breaker, ItemStack.EMPTY); } if (destroyed = this.setBlock(pos, fluidState.createLegacyBlock(), 3, updateLimit)) { this.gameEvent(GameEvent.BLOCK_DESTROY, pos, GameEvent.Context.of(breaker, blockState)); } return destroyed; } public void addDestroyBlockEffect(BlockPos pos, BlockState blockState) { } public boolean setBlockAndUpdate(BlockPos pos, BlockState blockState) { return this.setBlock(pos, blockState, 3); } public abstract void sendBlockUpdated(BlockPos var1, BlockState var2, BlockState var3, int var4); public void setBlocksDirty(BlockPos pos, BlockState oldState, BlockState newState) { } public void updateNeighborsAt(BlockPos pos, Block sourceBlock, @Nullable Orientation orientation) { } public void updateNeighborsAtExceptFromFacing(BlockPos pos, Block blockObject, Direction skipDirection, @Nullable Orientation orientation) { } public void neighborChanged(BlockPos pos, Block changedBlock, @Nullable Orientation orientation) { } public void neighborChanged(BlockState state, BlockPos pos, Block changedBlock, @Nullable Orientation orientation, boolean movedByPiston) { } @Override public void neighborShapeChanged(Direction direction, BlockPos pos, BlockPos neighborPos, BlockState neighborState, @Block.UpdateFlags int updateFlags, int updateLimit) { this.neighborUpdater.shapeUpdate(direction, neighborState, pos, neighborPos, updateFlags, updateLimit); } @Override public int getHeight(Heightmap.Types type, int x, int z) { int y = x < -30000000 || z < -30000000 || x >= 30000000 || z >= 30000000 ? this.getSeaLevel() + 1 : (this.hasChunk(SectionPos.blockToSectionCoord(x), SectionPos.blockToSectionCoord(z)) ? this.getChunk(SectionPos.blockToSectionCoord(x), SectionPos.blockToSectionCoord(z)).getHeight(type, x & 0xF, z & 0xF) + 1 : this.getMinY()); return y; } @Override public LevelLightEngine getLightEngine() { return this.getChunkSource().getLightEngine(); } @Override public BlockState getBlockState(BlockPos pos) { if (this.isOutsideBuildHeight(pos)) { return Blocks.VOID_AIR.defaultBlockState(); } LevelChunk chunk = this.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())); return chunk.getBlockState(pos); } @Override public FluidState getFluidState(BlockPos pos) { if (this.isOutsideBuildHeight(pos)) { return Fluids.EMPTY.defaultFluidState(); } LevelChunk chunk = this.getChunkAt(pos); return chunk.getFluidState(pos); } public boolean isBrightOutside() { return !this.dimensionType().hasFixedTime() && this.skyDarken < 4; } public boolean isDarkOutside() { return !this.dimensionType().hasFixedTime() && !this.isBrightOutside(); } @Override public void playSound(@Nullable Entity except, BlockPos pos, SoundEvent sound, SoundSource source, float volume, float pitch) { this.playSound(except, (double)pos.getX() + 0.5, (double)pos.getY() + 0.5, (double)pos.getZ() + 0.5, sound, source, volume, pitch); } public abstract void playSeededSound(@Nullable Entity var1, double var2, double var4, double var6, Holder var8, SoundSource var9, float var10, float var11, long var12); public void playSeededSound(@Nullable Entity except, double x, double y, double z, SoundEvent sound, SoundSource source, float volume, float pitch, long seed) { this.playSeededSound(except, x, y, z, BuiltInRegistries.SOUND_EVENT.wrapAsHolder(sound), source, volume, pitch, seed); } public abstract void playSeededSound(@Nullable Entity var1, Entity var2, Holder var3, SoundSource var4, float var5, float var6, long var7); public void playSound(@Nullable Entity except, double x, double y, double z, SoundEvent sound, SoundSource source) { this.playSound(except, x, y, z, sound, source, 1.0f, 1.0f); } public void playSound(@Nullable Entity except, double x, double y, double z, SoundEvent sound, SoundSource source, float volume, float pitch) { this.playSeededSound(except, x, y, z, sound, source, volume, pitch, this.threadSafeRandom.nextLong()); } public void playSound(@Nullable Entity except, double x, double y, double z, Holder sound, SoundSource source, float volume, float pitch) { this.playSeededSound(except, x, y, z, sound, source, volume, pitch, this.threadSafeRandom.nextLong()); } public void playSound(@Nullable Entity except, Entity sourceEntity, SoundEvent sound, SoundSource source, float volume, float pitch) { this.playSeededSound(except, sourceEntity, BuiltInRegistries.SOUND_EVENT.wrapAsHolder(sound), source, volume, pitch, this.threadSafeRandom.nextLong()); } public void playLocalSound(BlockPos pos, SoundEvent sound, SoundSource source, float volume, float pitch, boolean distanceDelay) { this.playLocalSound((double)pos.getX() + 0.5, (double)pos.getY() + 0.5, (double)pos.getZ() + 0.5, sound, source, volume, pitch, distanceDelay); } public void playLocalSound(Entity sourceEntity, SoundEvent sound, SoundSource source, float volume, float pitch) { } public void playLocalSound(double x, double y, double z, SoundEvent sound, SoundSource source, float volume, float pitch, boolean distanceDelay) { } public void playPlayerSound(SoundEvent sound, SoundSource source, float volume, float pitch) { } @Override public void addParticle(ParticleOptions particle, double x, double y, double z, double xd, double yd, double zd) { } public void addParticle(ParticleOptions particle, boolean overrideLimiter, boolean alwaysShow, double x, double y, double z, double xd, double yd, double zd) { } public void addAlwaysVisibleParticle(ParticleOptions particle, double x, double y, double z, double xd, double yd, double zd) { } public void addAlwaysVisibleParticle(ParticleOptions particle, boolean overrideLimiter, double x, double y, double z, double xd, double yd, double zd) { } public void addBlockEntityTicker(TickingBlockEntity ticker) { (this.tickingBlockEntities ? this.pendingBlockEntityTickers : this.blockEntityTickers).add(ticker); } public void tickBlockEntities() { this.tickingBlockEntities = true; if (!this.pendingBlockEntityTickers.isEmpty()) { this.blockEntityTickers.addAll(this.pendingBlockEntityTickers); this.pendingBlockEntityTickers.clear(); } Iterator iterator = this.blockEntityTickers.iterator(); boolean tickBlockEntities = this.tickRateManager().runsNormally(); while (iterator.hasNext()) { TickingBlockEntity ticker = iterator.next(); if (ticker.isRemoved()) { iterator.remove(); continue; } if (!tickBlockEntities || !this.shouldTickBlocksAt(ticker.getPos())) continue; ticker.tick(); } this.tickingBlockEntities = false; } public void guardEntityTick(Consumer tick, T entity) { try { tick.accept(entity); } catch (Throwable t) { CrashReport report = CrashReport.forThrowable(t, "Ticking entity"); CrashReportCategory category = report.addCategory("Entity being ticked"); entity.fillCrashReportCategory(category); throw new ReportedException(report); } } public boolean shouldTickDeath(Entity entity) { return true; } public boolean shouldTickBlocksAt(long chunkPos) { return true; } public boolean shouldTickBlocksAt(BlockPos pos) { return this.shouldTickBlocksAt(ChunkPos.asLong(pos)); } public void explode(@Nullable Entity source, double x, double y, double z, float r, ExplosionInteraction blockInteraction) { this.explode(source, Explosion.getDefaultDamageSource(this, source), null, x, y, z, r, false, blockInteraction, ParticleTypes.EXPLOSION, ParticleTypes.EXPLOSION_EMITTER, DEFAULT_EXPLOSION_BLOCK_PARTICLES, SoundEvents.GENERIC_EXPLODE); } public void explode(@Nullable Entity source, double x, double y, double z, float r, boolean fire, ExplosionInteraction blockInteraction) { this.explode(source, Explosion.getDefaultDamageSource(this, source), null, x, y, z, r, fire, blockInteraction, ParticleTypes.EXPLOSION, ParticleTypes.EXPLOSION_EMITTER, DEFAULT_EXPLOSION_BLOCK_PARTICLES, SoundEvents.GENERIC_EXPLODE); } public void explode(@Nullable Entity source, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator damageCalculator, Vec3 boomPos, float r, boolean fire, ExplosionInteraction blockInteraction) { this.explode(source, damageSource, damageCalculator, boomPos.x(), boomPos.y(), boomPos.z(), r, fire, blockInteraction, ParticleTypes.EXPLOSION, ParticleTypes.EXPLOSION_EMITTER, DEFAULT_EXPLOSION_BLOCK_PARTICLES, SoundEvents.GENERIC_EXPLODE); } public void explode(@Nullable Entity source, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator damageCalculator, double x, double y, double z, float r, boolean fire, ExplosionInteraction interactionType) { this.explode(source, damageSource, damageCalculator, x, y, z, r, fire, interactionType, ParticleTypes.EXPLOSION, ParticleTypes.EXPLOSION_EMITTER, DEFAULT_EXPLOSION_BLOCK_PARTICLES, SoundEvents.GENERIC_EXPLODE); } public abstract void explode(@Nullable Entity var1, @Nullable DamageSource var2, @Nullable ExplosionDamageCalculator var3, double var4, double var6, double var8, float var10, boolean var11, ExplosionInteraction var12, ParticleOptions var13, ParticleOptions var14, WeightedList var15, Holder var16); public abstract String gatherChunkSourceStats(); @Override public @Nullable BlockEntity getBlockEntity(BlockPos pos) { if (this.isOutsideBuildHeight(pos)) { return null; } if (!this.isClientSide() && Thread.currentThread() != this.thread) { return null; } return this.getChunkAt(pos).getBlockEntity(pos, LevelChunk.EntityCreationType.IMMEDIATE); } public void setBlockEntity(BlockEntity blockEntity) { BlockPos pos = blockEntity.getBlockPos(); if (this.isOutsideBuildHeight(pos)) { return; } this.getChunkAt(pos).addAndRegisterBlockEntity(blockEntity); } public void removeBlockEntity(BlockPos pos) { if (this.isOutsideBuildHeight(pos)) { return; } this.getChunkAt(pos).removeBlockEntity(pos); } public boolean isLoaded(BlockPos pos) { if (this.isOutsideBuildHeight(pos)) { return false; } return this.getChunkSource().hasChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())); } public boolean loadedAndEntityCanStandOnFace(BlockPos pos, Entity entity, Direction faceDirection) { if (this.isOutsideBuildHeight(pos)) { return false; } ChunkAccess chunk = this.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ()), ChunkStatus.FULL, false); if (chunk == null) { return false; } return chunk.getBlockState(pos).entityCanStandOnFace(this, pos, entity, faceDirection); } public boolean loadedAndEntityCanStandOn(BlockPos pos, Entity entity) { return this.loadedAndEntityCanStandOnFace(pos, entity, Direction.UP); } public void updateSkyBrightness() { this.skyDarken = (int)(15.0f - this.environmentAttributes().getDimensionValue(EnvironmentAttributes.SKY_LIGHT_LEVEL).floatValue()); } public void setSpawnSettings(boolean spawnEnemies) { this.getChunkSource().setSpawnSettings(spawnEnemies); } public abstract void setRespawnData(LevelData.RespawnData var1); public abstract LevelData.RespawnData getRespawnData(); public LevelData.RespawnData getWorldBorderAdjustedRespawnData(LevelData.RespawnData respawnData) { WorldBorder worldBorder = this.getWorldBorder(); if (!worldBorder.isWithinBounds(respawnData.pos())) { BlockPos newPos = this.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, BlockPos.containing(worldBorder.getCenterX(), 0.0, worldBorder.getCenterZ())); return LevelData.RespawnData.of(respawnData.dimension(), newPos, respawnData.yaw(), respawnData.pitch()); } return respawnData; } protected void prepareWeather() { if (this.levelData.isRaining()) { this.rainLevel = 1.0f; if (this.levelData.isThundering()) { this.thunderLevel = 1.0f; } } } @Override public void close() throws IOException { this.getChunkSource().close(); } @Override public @Nullable BlockGetter getChunkForCollisions(int chunkX, int chunkZ) { return this.getChunk(chunkX, chunkZ, ChunkStatus.FULL, false); } @Override public List getEntities(@Nullable Entity except, AABB bb, Predicate selector) { Profiler.get().incrementCounter("getEntities"); ArrayList output = Lists.newArrayList(); this.getEntities().get(bb, entity -> { if (entity != except && selector.test((Entity)entity)) { output.add(entity); } }); for (EnderDragonPart dragonPart : this.dragonParts()) { if (dragonPart == except || dragonPart.parentMob == except || !selector.test(dragonPart) || !bb.intersects(dragonPart.getBoundingBox())) continue; output.add(dragonPart); } return output; } @Override public List getEntities(EntityTypeTest type, AABB bb, Predicate selector) { ArrayList output = Lists.newArrayList(); this.getEntities(type, bb, selector, output); return output; } public void getEntities(EntityTypeTest type, AABB bb, Predicate selector, List output) { this.getEntities(type, bb, selector, output, Integer.MAX_VALUE); } public void getEntities(EntityTypeTest type, AABB bb, Predicate selector, List output, int maxResults) { Profiler.get().incrementCounter("getEntities"); this.getEntities().get(type, bb, e -> { if (selector.test(e)) { output.add((Object)e); if (output.size() >= maxResults) { return AbortableIterationConsumer.Continuation.ABORT; } } if (e instanceof EnderDragon) { EnderDragon enderDragon = (EnderDragon)e; for (EnderDragonPart subEntity : enderDragon.getSubEntities()) { Entity castSubPart = (Entity)type.tryCast(subEntity); if (castSubPart == null || !selector.test(castSubPart)) continue; output.add((Object)castSubPart); if (output.size() < maxResults) continue; return AbortableIterationConsumer.Continuation.ABORT; } } return AbortableIterationConsumer.Continuation.CONTINUE; }); } public boolean hasEntities(EntityTypeTest type, AABB bb, Predicate selector) { Profiler.get().incrementCounter("hasEntities"); MutableBoolean hasEntities = new MutableBoolean(); this.getEntities().get(type, bb, e -> { if (selector.test(e)) { hasEntities.setTrue(); return AbortableIterationConsumer.Continuation.ABORT; } if (e instanceof EnderDragon) { EnderDragon enderDragon = (EnderDragon)e; for (EnderDragonPart subEntity : enderDragon.getSubEntities()) { Entity castSubPart = (Entity)type.tryCast(subEntity); if (castSubPart == null || !selector.test(castSubPart)) continue; hasEntities.setTrue(); return AbortableIterationConsumer.Continuation.ABORT; } } return AbortableIterationConsumer.Continuation.CONTINUE; }); return hasEntities.isTrue(); } public List getPushableEntities(Entity pusher, AABB boundingBox) { return this.getEntities(pusher, boundingBox, EntitySelector.pushableBy(pusher)); } public abstract @Nullable Entity getEntity(int var1); public @Nullable Entity getEntity(UUID uuid) { return this.getEntities().get(uuid); } public @Nullable Entity getEntityInAnyDimension(UUID uuid) { return this.getEntity(uuid); } public @Nullable Player getPlayerInAnyDimension(UUID uuid) { return this.getPlayerByUUID(uuid); } public abstract Collection dragonParts(); public void blockEntityChanged(BlockPos pos) { if (this.hasChunkAt(pos)) { this.getChunkAt(pos).markUnsaved(); } } public void onBlockEntityAdded(BlockEntity blockEntity) { } public long getDayTime() { return this.levelData.getDayTime(); } public boolean mayInteract(Entity entity, BlockPos pos) { return true; } public void broadcastEntityEvent(Entity entity, byte event) { } public void broadcastDamageEvent(Entity entity, DamageSource source) { } public void blockEvent(BlockPos pos, Block block, int b0, int b1) { this.getBlockState(pos).triggerEvent(this, pos, b0, b1); } @Override public LevelData getLevelData() { return this.levelData; } public abstract TickRateManager tickRateManager(); public float getThunderLevel(float a) { return Mth.lerp(a, this.oThunderLevel, this.thunderLevel) * this.getRainLevel(a); } public void setThunderLevel(float thunderLevel) { float clampedThunderLevel; this.oThunderLevel = clampedThunderLevel = Mth.clamp(thunderLevel, 0.0f, 1.0f); this.thunderLevel = clampedThunderLevel; } public float getRainLevel(float a) { return Mth.lerp(a, this.oRainLevel, this.rainLevel); } public void setRainLevel(float rainLevel) { float clampedRainLevel; this.oRainLevel = clampedRainLevel = Mth.clamp(rainLevel, 0.0f, 1.0f); this.rainLevel = clampedRainLevel; } public boolean canHaveWeather() { return this.dimensionType().hasSkyLight() && !this.dimensionType().hasCeiling() && this.dimension() != END; } public boolean isThundering() { return this.canHaveWeather() && (double)this.getThunderLevel(1.0f) > 0.9; } public boolean isRaining() { return this.canHaveWeather() && (double)this.getRainLevel(1.0f) > 0.2; } public boolean isRainingAt(BlockPos pos) { return this.precipitationAt(pos) == Biome.Precipitation.RAIN; } public Biome.Precipitation precipitationAt(BlockPos pos) { if (!this.isRaining()) { return Biome.Precipitation.NONE; } if (!this.canSeeSky(pos)) { return Biome.Precipitation.NONE; } if (this.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, pos).getY() > pos.getY()) { return Biome.Precipitation.NONE; } Biome biome = this.getBiome(pos).value(); return biome.getPrecipitationAt(pos, this.getSeaLevel()); } public abstract @Nullable MapItemSavedData getMapData(MapId var1); public void globalLevelEvent(int type, BlockPos pos, int data) { } public CrashReportCategory fillReportDetails(CrashReport report) { CrashReportCategory category = report.addCategory("Affected level", 1); category.setDetail("All players", () -> { List players = this.players(); return players.size() + " total; " + players.stream().map(Player::debugInfo).collect(Collectors.joining(", ")); }); category.setDetail("Chunk stats", this.getChunkSource()::gatherStats); category.setDetail("Level dimension", () -> this.dimension().identifier().toString()); try { this.levelData.fillCrashReportCategory(category, this); } catch (Throwable t) { category.setDetailError("Level Data Unobtainable", t); } return category; } public abstract void destroyBlockProgress(int var1, BlockPos var2, int var3); public void createFireworks(double x, double y, double z, double xd, double yd, double zd, List explosions) { } public abstract Scoreboard getScoreboard(); public void updateNeighbourForOutputSignal(BlockPos pos, Block changedBlock) { for (Direction direction : Direction.Plane.HORIZONTAL) { BlockPos relativePos = pos.relative(direction); if (!this.hasChunkAt(relativePos)) continue; BlockState state = this.getBlockState(relativePos); if (state.is(Blocks.COMPARATOR)) { this.neighborChanged(state, relativePos, changedBlock, null, false); continue; } if (!state.isRedstoneConductor(this, relativePos) || !(state = this.getBlockState(relativePos = relativePos.relative(direction))).is(Blocks.COMPARATOR)) continue; this.neighborChanged(state, relativePos, changedBlock, null, false); } } @Override public int getSkyDarken() { return this.skyDarken; } public void setSkyFlashTime(int skyFlashTime) { } public void sendPacketToServer(Packet packet) { throw new UnsupportedOperationException("Can't send packets to server unless you're on the client."); } @Override public DimensionType dimensionType() { return this.dimensionTypeRegistration.value(); } public Holder dimensionTypeRegistration() { return this.dimensionTypeRegistration; } public ResourceKey dimension() { return this.dimension; } @Override public RandomSource getRandom() { return this.random; } @Override public boolean isStateAtPosition(BlockPos pos, Predicate predicate) { return predicate.test(this.getBlockState(pos)); } @Override public boolean isFluidAtPosition(BlockPos pos, Predicate predicate) { return predicate.test(this.getFluidState(pos)); } public abstract RecipeAccess recipeAccess(); public BlockPos getBlockRandomPos(int xo, int yo, int zo, int yMask) { this.randValue = this.randValue * 3 + 1013904223; int val = this.randValue >> 2; return new BlockPos(xo + (val & 0xF), yo + (val >> 16 & yMask), zo + (val >> 8 & 0xF)); } public boolean noSave() { return false; } @Override public BiomeManager getBiomeManager() { return this.biomeManager; } public final boolean isDebug() { return this.isDebug; } protected abstract LevelEntityGetter getEntities(); @Override public long nextSubTickCount() { return this.subTickCount++; } @Override public RegistryAccess registryAccess() { return this.registryAccess; } public DamageSources damageSources() { return this.damageSources; } @Override public abstract EnvironmentAttributeSystem environmentAttributes(); public abstract PotionBrewing potionBrewing(); public abstract FuelValues fuelValues(); public int getClientLeafTintColor(BlockPos pos) { return 0; } public PalettedContainerFactory palettedContainerFactory() { return this.palettedContainerFactory; } public static enum ExplosionInteraction implements StringRepresentable { NONE("none"), BLOCK("block"), MOB("mob"), TNT("tnt"), TRIGGER("trigger"); public static final Codec CODEC; private final String id; private ExplosionInteraction(String id) { this.id = id; } @Override public String getSerializedName() { return this.id; } static { CODEC = StringRepresentable.fromEnum(ExplosionInteraction::values); } } }