ClientLevel.java

net.minecraft.client.multiplayer.ClientLevel

信息

  • 全限定名:net.minecraft.client.multiplayer.ClientLevel
  • 类型:public class
  • 包:net.minecraft.client.multiplayer
  • 源码路径:src/main/java/net/minecraft/client/multiplayer/ClientLevel.java
  • 起始行号:L129
  • 继承:Level
  • 实现:BlockAndTintGetter, CacheSlot.Cleaner
  • 职责:

    TODO

字段/常量

  • LOGGER

    • 类型: Logger
    • 修饰符: private static final
    • 源码定位: L130
    • 说明:

      TODO

  • DEFAULT_QUIT_MESSAGE

    • 类型: Component
    • 修饰符: public static final
    • 源码定位: L131
    • 说明:

      TODO

  • FLUID_PARTICLE_SPAWN_OFFSET

    • 类型: double
    • 修饰符: private static final
    • 源码定位: L132
    • 说明:

      TODO

  • NORMAL_LIGHT_UPDATES_PER_FRAME

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L133
    • 说明:

      TODO

  • LIGHT_UPDATE_QUEUE_SIZE_THRESHOLD

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L134
    • 说明:

      TODO

  • tickingEntities

    • 类型: EntityTickList
    • 修饰符: private final
    • 源码定位: L135
    • 说明:

      TODO

  • entityStorage

    • 类型: TransientEntitySectionManager<Entity>
    • 修饰符: private final
    • 源码定位: L136
    • 说明:

      TODO

  • connection

    • 类型: ClientPacketListener
    • 修饰符: private final
    • 源码定位: L137
    • 说明:

      TODO

  • levelRenderer

    • 类型: LevelRenderer
    • 修饰符: private final
    • 源码定位: L138
    • 说明:

      TODO

  • levelEventHandler

    • 类型: LevelEventHandler
    • 修饰符: private final
    • 源码定位: L139
    • 说明:

      TODO

  • clientLevelData

    • 类型: ClientLevel.ClientLevelData
    • 修饰符: private final
    • 源码定位: L140
    • 说明:

      TODO

  • tickRateManager

    • 类型: TickRateManager
    • 修饰符: private final
    • 源码定位: L141
    • 说明:

      TODO

  • endFlashState

    • 类型: EndFlashState
    • 修饰符: private final
    • 源码定位: L142
    • 说明:

      TODO

  • minecraft

    • 类型: Minecraft
    • 修饰符: private final
    • 源码定位: L143
    • 说明:

      TODO

  • players

    • 类型: List<AbstractClientPlayer>
    • 修饰符: private final
    • 源码定位: L144
    • 说明:

      TODO

  • dragonParts

    • 类型: List<EnderDragonPart>
    • 修饰符: private final
    • 源码定位: L145
    • 说明:

      TODO

  • mapData

    • 类型: Map<MapId,MapItemSavedData>
    • 修饰符: private final
    • 源码定位: L146
    • 说明:

      TODO

  • skyFlashTime

    • 类型: int
    • 修饰符: private
    • 源码定位: L147
    • 说明:

      TODO

  • tintCaches

    • 类型: Object2ObjectArrayMap<ColorResolver,BlockTintCache>
    • 修饰符: private final
    • 源码定位: L148
    • 说明:

      TODO

  • chunkSource

    • 类型: ClientChunkCache
    • 修饰符: private final
    • 源码定位: L154
    • 说明:

      TODO

  • lightUpdateQueue

    • 类型: Deque<Runnable>
    • 修饰符: private final
    • 源码定位: L155
    • 说明:

      TODO

  • serverSimulationDistance

    • 类型: int
    • 修饰符: private
    • 源码定位: L156
    • 说明:

      TODO

  • blockStatePredictionHandler

    • 类型: BlockStatePredictionHandler
    • 修饰符: private final
    • 源码定位: L157
    • 说明:

      TODO

  • globallyRenderedBlockEntities

    • 类型: Set<BlockEntity>
    • 修饰符: private final
    • 源码定位: L158
    • 说明:

      TODO

  • explosionTracker

    • 类型: ClientExplosionTracker
    • 修饰符: private final
    • 源码定位: L159
    • 说明:

      TODO

  • worldBorder

    • 类型: WorldBorder
    • 修饰符: private final
    • 源码定位: L160
    • 说明:

      TODO

  • environmentAttributes

    • 类型: EnvironmentAttributeSystem
    • 修饰符: private final
    • 源码定位: L161
    • 说明:

      TODO

  • seaLevel

    • 类型: int
    • 修饰符: private final
    • 源码定位: L162
    • 说明:

      TODO

  • MARKER_PARTICLE_ITEMS

    • 类型: Set<Item>
    • 修饰符: private static final
    • 源码定位: L163
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.client.multiplayer.ClientLevel.ClientLevelData

    • 类型: class
    • 修饰符: public static
    • 源码定位: L1015
    • 说明:

      TODO

  • net.minecraft.client.multiplayer.ClientLevel.EntityCallbacks

    • 类型: class
    • 修饰符: private final
    • 源码定位: L1086
    • 说明:

      TODO

构造器

public ClientLevel(ClientPacketListener connection, ClientLevel.ClientLevelData levelData, ResourceKey<Level> dimension, Holder<DimensionType> dimensionType, int serverChunkRadius, int serverSimulationDistance, LevelRenderer levelRenderer, boolean isDebug, long biomeZoomSeed, int seaLevel) @ L221

  • 构造器名:ClientLevel
  • 源码定位:L221
  • 修饰符:public

参数:

  • connection: ClientPacketListener
  • levelData: ClientLevel.ClientLevelData
  • dimension: ResourceKey
  • dimensionType: Holder
  • serverChunkRadius: int
  • serverSimulationDistance: int
  • levelRenderer: LevelRenderer
  • isDebug: boolean
  • biomeZoomSeed: long
  • seaLevel: int

说明:

TODO

方法

下面的方法块按源码顺序生成。

public void handleBlockChangedAck(int sequence) @ L165

  • 方法名:handleBlockChangedAck
  • 源码定位:L165
  • 返回类型:void
  • 修饰符:public

参数:

  • sequence: int

说明:

TODO

public void onBlockEntityAdded(BlockEntity blockEntity) @ L173

  • 方法名:onBlockEntityAdded
  • 源码定位:L173
  • 返回类型:void
  • 修饰符:public

参数:

  • blockEntity: BlockEntity

说明:

TODO

public Set<BlockEntity> getGloballyRenderedBlockEntities() @ L181

  • 方法名:getGloballyRenderedBlockEntities
  • 源码定位:L181
  • 返回类型:Set
  • 修饰符:public

参数:

说明:

TODO

public void setServerVerifiedBlockState(BlockPos pos, BlockState blockState, int updateFlag) @ L185

  • 方法名:setServerVerifiedBlockState
  • 源码定位:L185
  • 返回类型:void
  • 修饰符:public

参数:

  • pos: BlockPos
  • blockState: BlockState
  • updateFlag: int

说明:

TODO

public void syncBlockState(BlockPos pos, BlockState state, Vec3 playerPos) @ L191

  • 方法名:syncBlockState
  • 源码定位:L191
  • 返回类型:void
  • 修饰符:public

参数:

  • pos: BlockPos
  • state: BlockState
  • playerPos: Vec3

说明:

TODO

BlockStatePredictionHandler getBlockStatePredictionHandler() @ L202

  • 方法名:getBlockStatePredictionHandler
  • 源码定位:L202
  • 返回类型:BlockStatePredictionHandler
  • 修饰符:package-private

参数:

说明:

TODO

public boolean setBlock(BlockPos pos, BlockState blockState, int updateFlags, int updateLimit) @ L206

  • 方法名:setBlock
  • 源码定位:L206
  • 返回类型:boolean
  • 修饰符:public

参数:

  • pos: BlockPos
  • blockState: BlockState
  • updateFlags: int
  • updateLimit: int

说明:

TODO

private EnvironmentAttributeSystem.Builder addEnvironmentAttributeLayers(EnvironmentAttributeSystem.Builder environmentAttributes) @ L248

  • 方法名:addEnvironmentAttributeLayers
  • 源码定位:L248
  • 返回类型:EnvironmentAttributeSystem.Builder
  • 修饰符:private

参数:

  • environmentAttributes: EnvironmentAttributeSystem.Builder

说明:

TODO

public void queueLightUpdate(Runnable update) @ L260

  • 方法名:queueLightUpdate
  • 源码定位:L260
  • 返回类型:void
  • 修饰符:public

参数:

  • update: Runnable

说明:

TODO

public void pollLightUpdates() @ L264

  • 方法名:pollLightUpdates
  • 源码定位:L264
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public EndFlashState endFlashState() @ L278

  • 方法名:endFlashState
  • 源码定位:L278
  • 返回类型:EndFlashState
  • 修饰符:public

参数:

说明:

TODO

public void tick(BooleanSupplier haveTime) @ L282

  • 方法名:tick
  • 源码定位:L282
  • 返回类型:void
  • 修饰符:public

参数:

  • haveTime: BooleanSupplier

说明:

TODO

private void tickTime() @ L322

  • 方法名:tickTime
  • 源码定位:L322
  • 返回类型:void
  • 修饰符:private

参数:

说明:

TODO

public void setTimeFromServer(long gameTime) @ L326

  • 方法名:setTimeFromServer
  • 源码定位:L326
  • 返回类型:void
  • 修饰符:public

参数:

  • gameTime: long

说明:

TODO

public Iterable<Entity> entitiesForRendering() @ L330

  • 方法名:entitiesForRendering
  • 源码定位:L330
  • 返回类型:Iterable
  • 修饰符:public

参数:

说明:

TODO

public void tickEntities() @ L334

  • 方法名:tickEntities
  • 源码定位:L334
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public boolean isTickingEntity(Entity entity) @ L342

  • 方法名:isTickingEntity
  • 源码定位:L342
  • 返回类型:boolean
  • 修饰符:public

参数:

  • entity: Entity

说明:

TODO

public boolean shouldTickDeath(Entity entity) @ L346

  • 方法名:shouldTickDeath
  • 源码定位:L346
  • 返回类型:boolean
  • 修饰符:public

参数:

  • entity: Entity

说明:

TODO

public void tickNonPassenger(Entity entity) @ L351

  • 方法名:tickNonPassenger
  • 源码定位:L351
  • 返回类型:void
  • 修饰符:public

参数:

  • entity: Entity

说明:

TODO

private void tickPassenger(Entity vehicle, Entity entity) @ L363

  • 方法名:tickPassenger
  • 源码定位:L363
  • 返回类型:void
  • 修饰符:private

参数:

  • vehicle: Entity
  • entity: Entity

说明:

TODO

public void update() @ L377

  • 方法名:update
  • 源码定位:L377
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public void unload(LevelChunk levelChunk) @ L386

  • 方法名:unload
  • 源码定位:L386
  • 返回类型:void
  • 修饰符:public

参数:

  • levelChunk: LevelChunk

说明:

TODO

public void onChunkLoaded(ChunkPos pos) @ L392

  • 方法名:onChunkLoaded
  • 源码定位:L392
  • 返回类型:void
  • 修饰符:public

参数:

  • pos: ChunkPos

说明:

TODO

public void onSectionBecomingNonEmpty(long sectionNode) @ L397

  • 方法名:onSectionBecomingNonEmpty
  • 源码定位:L397
  • 返回类型:void
  • 修饰符:public

参数:

  • sectionNode: long

说明:

TODO

public void clearTintCaches() @ L401

  • 方法名:clearTintCaches
  • 源码定位:L401
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public boolean hasChunk(int chunkX, int chunkZ) @ L405

  • 方法名:hasChunk
  • 源码定位:L405
  • 返回类型:boolean
  • 修饰符:public

参数:

  • chunkX: int
  • chunkZ: int

说明:

TODO

public int getEntityCount() @ L410

  • 方法名:getEntityCount
  • 源码定位:L410
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

public void addEntity(Entity entity) @ L414

  • 方法名:addEntity
  • 源码定位:L414
  • 返回类型:void
  • 修饰符:public

参数:

  • entity: Entity

说明:

TODO

public void removeEntity(int id, Entity.RemovalReason reason) @ L419

  • 方法名:removeEntity
  • 源码定位:L419
  • 返回类型:void
  • 修饰符:public

参数:

  • id: int
  • reason: Entity.RemovalReason

说明:

TODO

public List<Entity> getPushableEntities(Entity pusher, AABB boundingBox) @ L427

  • 方法名:getPushableEntities
  • 源码定位:L427
  • 返回类型:List
  • 修饰符:public

参数:

  • pusher: Entity
  • boundingBox: AABB

说明:

TODO

public Entity getEntity(int id) @ L435

  • 方法名:getEntity
  • 源码定位:L435
  • 返回类型:Entity
  • 修饰符:public

参数:

  • id: int

说明:

TODO

public void disconnect(Component message) @ L440

  • 方法名:disconnect
  • 源码定位:L440
  • 返回类型:void
  • 修饰符:public

参数:

  • message: Component

说明:

TODO

public void animateTick(int xt, int yt, int zt) @ L444

  • 方法名:animateTick
  • 源码定位:L444
  • 返回类型:void
  • 修饰符:public

参数:

  • xt: int
  • yt: int
  • zt: int

说明:

TODO

private Block getMarkerParticleTarget() @ L456

  • 方法名:getMarkerParticleTarget
  • 源码定位:L456
  • 返回类型:Block
  • 修饰符:private

参数:

说明:

TODO

public void doAnimateTick(int xt, int yt, int zt, int r, RandomSource animateRandom, Block markerParticleTarget, BlockPos.MutableBlockPos pos) @ L468

  • 方法名:doAnimateTick
  • 源码定位:L468
  • 返回类型:void
  • 修饰符:public

参数:

  • xt: int
  • yt: int
  • zt: int
  • r: int
  • animateRandom: RandomSource
  • markerParticleTarget: Block
  • pos: BlockPos.MutableBlockPos

说明:

TODO

private void trySpawnDripParticles(BlockPos pos, BlockState state, ParticleOptions dripParticle, boolean isTopSolid) @ L507

  • 方法名:trySpawnDripParticles
  • 源码定位:L507
  • 返回类型:void
  • 修饰符:private

参数:

  • pos: BlockPos
  • state: BlockState
  • dripParticle: ParticleOptions
  • isTopSolid: boolean

说明:

TODO

private void spawnParticle(BlockPos pos, ParticleOptions dripParticle, VoxelShape dripShape, double height) @ L532

  • 方法名:spawnParticle
  • 源码定位:L532
  • 返回类型:void
  • 修饰符:private

参数:

  • pos: BlockPos
  • dripParticle: ParticleOptions
  • dripShape: VoxelShape
  • height: double

说明:

TODO

private void spawnFluidParticle(double x1, double x2, double z1, double z2, double y, ParticleOptions dripParticle) @ L543

  • 方法名:spawnFluidParticle
  • 源码定位:L543
  • 返回类型:void
  • 修饰符:private

参数:

  • x1: double
  • x2: double
  • z1: double
  • z2: double
  • y: double
  • dripParticle: ParticleOptions

说明:

TODO

public CrashReportCategory fillReportDetails(CrashReport report) @ L547

  • 方法名:fillReportDetails
  • 源码定位:L547
  • 返回类型:CrashReportCategory
  • 修饰符:public

参数:

  • report: CrashReport

说明:

TODO

public void playSeededSound(Entity except, double x, double y, double z, Holder<SoundEvent> sound, SoundSource source, float volume, float pitch, long seed) @ L559

  • 方法名:playSeededSound
  • 源码定位:L559
  • 返回类型:void
  • 修饰符:public

参数:

  • except: Entity
  • x: double
  • y: double
  • z: double
  • sound: Holder
  • source: SoundSource
  • volume: float
  • pitch: float
  • seed: long

说明:

TODO

public void playSeededSound(Entity except, Entity sourceEntity, Holder<SoundEvent> sound, SoundSource source, float volume, float pitch, long seed) @ L568

  • 方法名:playSeededSound
  • 源码定位:L568
  • 返回类型:void
  • 修饰符:public

参数:

  • except: Entity
  • sourceEntity: Entity
  • sound: Holder
  • source: SoundSource
  • volume: float
  • pitch: float
  • seed: long

说明:

TODO

public void playLocalSound(Entity sourceEntity, SoundEvent sound, SoundSource source, float volume, float pitch) @ L577

  • 方法名:playLocalSound
  • 源码定位:L577
  • 返回类型:void
  • 修饰符:public

参数:

  • sourceEntity: Entity
  • sound: SoundEvent
  • source: SoundSource
  • volume: float
  • pitch: float

说明:

TODO

public void playPlayerSound(SoundEvent sound, SoundSource source, float volume, float pitch) @ L582

  • 方法名:playPlayerSound
  • 源码定位:L582
  • 返回类型:void
  • 修饰符:public

参数:

  • sound: SoundEvent
  • source: SoundSource
  • volume: float
  • pitch: float

说明:

TODO

public void playLocalSound(double x, double y, double z, SoundEvent sound, SoundSource source, float volume, float pitch, boolean distanceDelay) @ L589

  • 方法名:playLocalSound
  • 源码定位:L589
  • 返回类型:void
  • 修饰符:public

参数:

  • x: double
  • y: double
  • z: double
  • sound: SoundEvent
  • source: SoundSource
  • volume: float
  • pitch: float
  • distanceDelay: boolean

说明:

TODO

private void playSound(double x, double y, double z, SoundEvent sound, SoundSource source, float volume, float pitch, boolean distanceDelay, long seed) @ L594

  • 方法名:playSound
  • 源码定位:L594
  • 返回类型:void
  • 修饰符:private

参数:

  • x: double
  • y: double
  • z: double
  • sound: SoundEvent
  • source: SoundSource
  • volume: float
  • pitch: float
  • distanceDelay: boolean
  • seed: long

说明:

TODO

public void createFireworks(double x, double y, double z, double xd, double yd, double zd, List<FireworkExplosion> explosions) @ L605

  • 方法名:createFireworks
  • 源码定位:L605
  • 返回类型:void
  • 修饰符:public

参数:

  • x: double
  • y: double
  • z: double
  • xd: double
  • yd: double
  • zd: double
  • explosions: List

说明:

TODO

public void sendPacketToServer(Packet<?> packet) @ L616

  • 方法名:sendPacketToServer
  • 源码定位:L616
  • 返回类型:void
  • 修饰符:public

参数:

  • packet: Packet<?>

说明:

TODO

public WorldBorder getWorldBorder() @ L621

  • 方法名:getWorldBorder
  • 源码定位:L621
  • 返回类型:WorldBorder
  • 修饰符:public

参数:

说明:

TODO

public RecipeAccess recipeAccess() @ L626

  • 方法名:recipeAccess
  • 源码定位:L626
  • 返回类型:RecipeAccess
  • 修饰符:public

参数:

说明:

TODO

public TickRateManager tickRateManager() @ L631

  • 方法名:tickRateManager
  • 源码定位:L631
  • 返回类型:TickRateManager
  • 修饰符:public

参数:

说明:

TODO

public ClientClockManager clockManager() @ L636

  • 方法名:clockManager
  • 源码定位:L636
  • 返回类型:ClientClockManager
  • 修饰符:public

参数:

说明:

TODO

public EnvironmentAttributeSystem environmentAttributes() @ L640

  • 方法名:environmentAttributes
  • 源码定位:L640
  • 返回类型:EnvironmentAttributeSystem
  • 修饰符:public

参数:

说明:

TODO

public LevelTickAccess<Block> getBlockTicks() @ L645

  • 方法名:getBlockTicks
  • 源码定位:L645
  • 返回类型:LevelTickAccess
  • 修饰符:public

参数:

说明:

TODO

public LevelTickAccess<Fluid> getFluidTicks() @ L650

  • 方法名:getFluidTicks
  • 源码定位:L650
  • 返回类型:LevelTickAccess
  • 修饰符:public

参数:

说明:

TODO

public ClientChunkCache getChunkSource() @ L655

  • 方法名:getChunkSource
  • 源码定位:L655
  • 返回类型:ClientChunkCache
  • 修饰符:public

参数:

说明:

TODO

public MapItemSavedData getMapData(MapId id) @ L659

  • 方法名:getMapData
  • 源码定位:L659
  • 返回类型:MapItemSavedData
  • 修饰符:public

参数:

  • id: MapId

说明:

TODO

public void overrideMapData(MapId id, MapItemSavedData data) @ L664

  • 方法名:overrideMapData
  • 源码定位:L664
  • 返回类型:void
  • 修饰符:public

参数:

  • id: MapId
  • data: MapItemSavedData

说明:

TODO

public Scoreboard getScoreboard() @ L668

  • 方法名:getScoreboard
  • 源码定位:L668
  • 返回类型:Scoreboard
  • 修饰符:public

参数:

说明:

TODO

public void sendBlockUpdated(BlockPos pos, BlockState old, BlockState current, int updateFlags) @ L673

  • 方法名:sendBlockUpdated
  • 源码定位:L673
  • 返回类型:void
  • 修饰符:public

参数:

  • pos: BlockPos
  • old: BlockState
  • current: BlockState
  • updateFlags: int

说明:

TODO

public void setBlocksDirty(BlockPos pos, BlockState oldState, BlockState newState) @ L678

  • 方法名:setBlocksDirty
  • 源码定位:L678
  • 返回类型:void
  • 修饰符:public

参数:

  • pos: BlockPos
  • oldState: BlockState
  • newState: BlockState

说明:

TODO

public void setSectionDirtyWithNeighbors(int chunkX, int chunkY, int chunkZ) @ L683

  • 方法名:setSectionDirtyWithNeighbors
  • 源码定位:L683
  • 返回类型:void
  • 修饰符:public

参数:

  • chunkX: int
  • chunkY: int
  • chunkZ: int

说明:

TODO

public void setSectionRangeDirty(int minSectionX, int minSectionY, int minSectionZ, int maxSectionX, int maxSectionY, int maxSectionZ) @ L687

  • 方法名:setSectionRangeDirty
  • 源码定位:L687
  • 返回类型:void
  • 修饰符:public

参数:

  • minSectionX: int
  • minSectionY: int
  • minSectionZ: int
  • maxSectionX: int
  • maxSectionY: int
  • maxSectionZ: int

说明:

TODO

public void destroyBlockProgress(int id, BlockPos blockPos, int progress) @ L691

  • 方法名:destroyBlockProgress
  • 源码定位:L691
  • 返回类型:void
  • 修饰符:public

参数:

  • id: int
  • blockPos: BlockPos
  • progress: int

说明:

TODO

public void globalLevelEvent(int type, BlockPos pos, int data) @ L696

  • 方法名:globalLevelEvent
  • 源码定位:L696
  • 返回类型:void
  • 修饰符:public

参数:

  • type: int
  • pos: BlockPos
  • data: int

说明:

TODO

public void levelEvent(Entity source, int type, BlockPos pos, int data) @ L701

  • 方法名:levelEvent
  • 源码定位:L701
  • 返回类型:void
  • 修饰符:public

参数:

  • source: Entity
  • type: int
  • pos: BlockPos
  • data: int

说明:

TODO

public void addParticle(ParticleOptions particle, double x, double y, double z, double xd, double yd, double zd) @ L716

  • 方法名:addParticle
  • 源码定位:L716
  • 返回类型:void
  • 修饰符:public

参数:

  • particle: ParticleOptions
  • x: double
  • y: double
  • z: double
  • xd: double
  • yd: double
  • zd: double

说明:

TODO

public void addParticle(ParticleOptions particle, boolean overrideLimiter, boolean alwaysShow, double x, double y, double z, double xd, double yd, double zd) @ L721

  • 方法名:addParticle
  • 源码定位:L721
  • 返回类型:void
  • 修饰符:public

参数:

  • particle: ParticleOptions
  • overrideLimiter: boolean
  • alwaysShow: boolean
  • x: double
  • y: double
  • z: double
  • xd: double
  • yd: double
  • zd: double

说明:

TODO

public void addAlwaysVisibleParticle(ParticleOptions particle, double x, double y, double z, double xd, double yd, double zd) @ L728

  • 方法名:addAlwaysVisibleParticle
  • 源码定位:L728
  • 返回类型:void
  • 修饰符:public

参数:

  • particle: ParticleOptions
  • x: double
  • y: double
  • z: double
  • xd: double
  • yd: double
  • zd: double

说明:

TODO

public void addAlwaysVisibleParticle(ParticleOptions particle, boolean overrideLimiter, double x, double y, double z, double xd, double yd, double zd) @ L733

  • 方法名:addAlwaysVisibleParticle
  • 源码定位:L733
  • 返回类型:void
  • 修饰符:public

参数:

  • particle: ParticleOptions
  • overrideLimiter: boolean
  • x: double
  • y: double
  • z: double
  • xd: double
  • yd: double
  • zd: double

说明:

TODO

private void doAddParticle(ParticleOptions particle, boolean overrideLimiter, boolean alwaysShowParticles, double x, double y, double z, double xd, double yd, double zd) @ L738

  • 方法名:doAddParticle
  • 源码定位:L738
  • 返回类型:void
  • 修饰符:private

参数:

  • particle: ParticleOptions
  • overrideLimiter: boolean
  • alwaysShowParticles: boolean
  • x: double
  • y: double
  • z: double
  • xd: double
  • yd: double
  • zd: double

说明:

TODO

private ParticleStatus calculateParticleLevel(boolean alwaysShowParticles) @ L763

  • 方法名:calculateParticleLevel
  • 源码定位:L763
  • 返回类型:ParticleStatus
  • 修饰符:private

参数:

  • alwaysShowParticles: boolean

说明:

TODO

public List<AbstractClientPlayer> players() @ L776

  • 方法名:players
  • 源码定位:L776
  • 返回类型:List
  • 修饰符:public

参数:

说明:

TODO

public List<EnderDragonPart> dragonParts() @ L781

  • 方法名:dragonParts
  • 源码定位:L781
  • 返回类型:List
  • 修饰符:public

参数:

说明:

TODO

public Holder<Biome> getUncachedNoiseBiome(int quartX, int quartY, int quartZ) @ L785

  • 方法名:getUncachedNoiseBiome
  • 源码定位:L785
  • 返回类型:Holder
  • 修饰符:public

参数:

  • quartX: int
  • quartY: int
  • quartZ: int

说明:

TODO

private int getSkyFlashTime() @ L790

  • 方法名:getSkyFlashTime
  • 源码定位:L790
  • 返回类型:int
  • 修饰符:private

参数:

说明:

TODO

public void setSkyFlashTime(int skyFlashTime) @ L794

  • 方法名:setSkyFlashTime
  • 源码定位:L794
  • 返回类型:void
  • 修饰符:public

参数:

  • skyFlashTime: int

说明:

TODO

public CardinalLighting cardinalLighting() @ L799

  • 方法名:cardinalLighting
  • 源码定位:L799
  • 返回类型:CardinalLighting
  • 修饰符:public

参数:

说明:

TODO

public int getBlockTint(BlockPos pos, ColorResolver resolver) @ L804

  • 方法名:getBlockTint
  • 源码定位:L804
  • 返回类型:int
  • 修饰符:public

参数:

  • pos: BlockPos
  • resolver: ColorResolver

说明:

TODO

public int calculateBlockTint(BlockPos pos, ColorResolver colorResolver) @ L810

  • 方法名:calculateBlockTint
  • 源码定位:L810
  • 返回类型:int
  • 修饰符:public

参数:

  • pos: BlockPos
  • colorResolver: ColorResolver

说明:

TODO

public void setRespawnData(LevelData.RespawnData respawnData) @ L834

  • 方法名:setRespawnData
  • 源码定位:L834
  • 返回类型:void
  • 修饰符:public

参数:

  • respawnData: LevelData.RespawnData

说明:

TODO

public LevelData.RespawnData getRespawnData() @ L839

  • 方法名:getRespawnData
  • 源码定位:L839
  • 返回类型:LevelData.RespawnData
  • 修饰符:public

参数:

说明:

TODO

public String toString() @ L844

  • 方法名:toString
  • 源码定位:L844
  • 返回类型:String
  • 修饰符:public

参数:

说明:

TODO

public ClientLevel.ClientLevelData getLevelData() @ L849

  • 方法名:getLevelData
  • 源码定位:L849
  • 返回类型:ClientLevel.ClientLevelData
  • 修饰符:public

参数:

说明:

TODO

public void gameEvent(Holder<GameEvent> gameEvent, Vec3 pos, GameEvent.Context context) @ L853

  • 方法名:gameEvent
  • 源码定位:L853
  • 返回类型:void
  • 修饰符:public

参数:

  • gameEvent: Holder
  • pos: Vec3
  • context: GameEvent.Context

说明:

TODO

protected Map<MapId,MapItemSavedData> getAllMapData() @ L857

  • 方法名:getAllMapData
  • 源码定位:L857
  • 返回类型:Map<MapId,MapItemSavedData>
  • 修饰符:protected

参数:

说明:

TODO

protected void addMapData(Map<MapId,MapItemSavedData> mapData) @ L861

  • 方法名:addMapData
  • 源码定位:L861
  • 返回类型:void
  • 修饰符:protected

参数:

  • mapData: Map<MapId,MapItemSavedData>

说明:

TODO

protected LevelEntityGetter<Entity> getEntities() @ L865

  • 方法名:getEntities
  • 源码定位:L865
  • 返回类型:LevelEntityGetter
  • 修饰符:protected

参数:

说明:

TODO

public String gatherChunkSourceStats() @ L870

  • 方法名:gatherChunkSourceStats
  • 源码定位:L870
  • 返回类型:String
  • 修饰符:public

参数:

说明:

TODO

public void addDestroyBlockEffect(BlockPos pos, BlockState blockState) @ L875

  • 方法名:addDestroyBlockEffect
  • 源码定位:L875
  • 返回类型:void
  • 修饰符:public

参数:

  • pos: BlockPos
  • blockState: BlockState

说明:

TODO

public void addBreakingBlockEffect(BlockPos pos, Direction direction) @ L913

  • 方法名:addBreakingBlockEffect
  • 源码定位:L913
  • 返回类型:void
  • 修饰符:public

参数:

  • pos: BlockPos
  • direction: Direction

说明:

TODO

public void setServerSimulationDistance(int serverSimulationDistance) @ L952

  • 方法名:setServerSimulationDistance
  • 源码定位:L952
  • 返回类型:void
  • 修饰符:public

参数:

  • serverSimulationDistance: int

说明:

TODO

public int getServerSimulationDistance() @ L956

  • 方法名:getServerSimulationDistance
  • 源码定位:L956
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

public FeatureFlagSet enabledFeatures() @ L960

  • 方法名:enabledFeatures
  • 源码定位:L960
  • 返回类型:FeatureFlagSet
  • 修饰符:public

参数:

说明:

TODO

public PotionBrewing potionBrewing() @ L965

  • 方法名:potionBrewing
  • 源码定位:L965
  • 返回类型:PotionBrewing
  • 修饰符:public

参数:

说明:

TODO

public FuelValues fuelValues() @ L970

  • 方法名:fuelValues
  • 源码定位:L970
  • 返回类型:FuelValues
  • 修饰符:public

参数:

说明:

TODO

public void explode(Entity source, DamageSource damageSource, ExplosionDamageCalculator damageCalculator, double x, double y, double z, float r, boolean fire, Level.ExplosionInteraction interactionType, ParticleOptions smallExplosionParticles, ParticleOptions largeExplosionParticles, WeightedList<ExplosionParticleInfo> secondaryParticles, Holder<SoundEvent> explosionSound) @ L975

  • 方法名:explode
  • 源码定位:L975
  • 返回类型:void
  • 修饰符:public

参数:

  • source: Entity
  • damageSource: DamageSource
  • damageCalculator: ExplosionDamageCalculator
  • x: double
  • y: double
  • z: double
  • r: float
  • fire: boolean
  • interactionType: Level.ExplosionInteraction
  • smallExplosionParticles: ParticleOptions
  • largeExplosionParticles: ParticleOptions
  • secondaryParticles: WeightedList
  • explosionSound: Holder

说明:

TODO

public int getSeaLevel() @ L993

  • 方法名:getSeaLevel
  • 源码定位:L993
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

public int getClientLeafTintColor(BlockPos pos) @ L998

  • 方法名:getClientLeafTintColor
  • 源码定位:L998
  • 返回类型:int
  • 修饰符:public

参数:

  • pos: BlockPos

说明:

TODO

public void registerForCleaning(CacheSlot<ClientLevel,?> slot) @ L1005

  • 方法名:registerForCleaning
  • 源码定位:L1005
  • 返回类型:void
  • 修饰符:public

参数:

  • slot: CacheSlot<ClientLevel,?>

说明:

TODO

public void trackExplosionEffects(Vec3 center, float radius, int blockCount, WeightedList<ExplosionParticleInfo> blockParticles) @ L1010

  • 方法名:trackExplosionEffects
  • 源码定位:L1010
  • 返回类型:void
  • 修饰符:public

参数:

  • center: Vec3
  • radius: float
  • blockCount: int
  • blockParticles: WeightedList

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public class ClientLevel extends Level implements BlockAndTintGetter, CacheSlot.Cleaner<ClientLevel> {
    private static final Logger LOGGER = LogUtils.getLogger();
    public static final Component DEFAULT_QUIT_MESSAGE = Component.translatable("multiplayer.status.quitting");
    private static final double FLUID_PARTICLE_SPAWN_OFFSET = 0.05;
    private static final int NORMAL_LIGHT_UPDATES_PER_FRAME = 10;
    private static final int LIGHT_UPDATE_QUEUE_SIZE_THRESHOLD = 1000;
    private final EntityTickList tickingEntities = new EntityTickList();
    private final TransientEntitySectionManager<Entity> entityStorage = new TransientEntitySectionManager<>(Entity.class, new ClientLevel.EntityCallbacks());
    private final ClientPacketListener connection;
    private final LevelRenderer levelRenderer;
    private final LevelEventHandler levelEventHandler;
    private final ClientLevel.ClientLevelData clientLevelData;
    private final TickRateManager tickRateManager;
    private final @Nullable EndFlashState endFlashState;
    private final Minecraft minecraft = Minecraft.getInstance();
    private final List<AbstractClientPlayer> players = Lists.newArrayList();
    private final List<EnderDragonPart> dragonParts = Lists.newArrayList();
    private final Map<MapId, MapItemSavedData> mapData = Maps.newHashMap();
    private int skyFlashTime;
    private final Object2ObjectArrayMap<ColorResolver, BlockTintCache> tintCaches = Util.make(new Object2ObjectArrayMap<>(3), cache -> {
        cache.put(BiomeColors.GRASS_COLOR_RESOLVER, new BlockTintCache(pos -> this.calculateBlockTint(pos, BiomeColors.GRASS_COLOR_RESOLVER)));
        cache.put(BiomeColors.FOLIAGE_COLOR_RESOLVER, new BlockTintCache(pos -> this.calculateBlockTint(pos, BiomeColors.FOLIAGE_COLOR_RESOLVER)));
        cache.put(BiomeColors.DRY_FOLIAGE_COLOR_RESOLVER, new BlockTintCache(pos -> this.calculateBlockTint(pos, BiomeColors.DRY_FOLIAGE_COLOR_RESOLVER)));
        cache.put(BiomeColors.WATER_COLOR_RESOLVER, new BlockTintCache(pos -> this.calculateBlockTint(pos, BiomeColors.WATER_COLOR_RESOLVER)));
    });
    private final ClientChunkCache chunkSource;
    private final Deque<Runnable> lightUpdateQueue = Queues.newArrayDeque();
    private int serverSimulationDistance;
    private final BlockStatePredictionHandler blockStatePredictionHandler = new BlockStatePredictionHandler();
    private final Set<BlockEntity> globallyRenderedBlockEntities = new ReferenceOpenHashSet<>();
    private final ClientExplosionTracker explosionTracker = new ClientExplosionTracker();
    private final WorldBorder worldBorder = new WorldBorder();
    private final EnvironmentAttributeSystem environmentAttributes;
    private final int seaLevel;
    private static final Set<Item> MARKER_PARTICLE_ITEMS = Set.of(Items.BARRIER, Items.LIGHT);
 
    public void handleBlockChangedAck(int sequence) {
        if (SharedConstants.DEBUG_BLOCK_BREAK) {
            LOGGER.debug("ACK {}", sequence);
        }
 
        this.blockStatePredictionHandler.endPredictionsUpTo(sequence, this);
    }
 
    @Override
    public void onBlockEntityAdded(BlockEntity blockEntity) {
        BlockEntityRenderer<BlockEntity, ?> renderer = this.minecraft.getBlockEntityRenderDispatcher().getRenderer(blockEntity);
        if (renderer != null && renderer.shouldRenderOffScreen()) {
            this.globallyRenderedBlockEntities.add(blockEntity);
        }
    }
 
    public Set<BlockEntity> getGloballyRenderedBlockEntities() {
        return this.globallyRenderedBlockEntities;
    }
 
    public void setServerVerifiedBlockState(BlockPos pos, BlockState blockState, @Block.UpdateFlags int updateFlag) {
        if (!this.blockStatePredictionHandler.updateKnownServerState(pos, blockState)) {
            super.setBlock(pos, blockState, updateFlag, 512);
        }
    }
 
    public void syncBlockState(BlockPos pos, BlockState state, @Nullable Vec3 playerPos) {
        BlockState oldState = this.getBlockState(pos);
        if (oldState != state) {
            this.setBlock(pos, state, 19);
            Player player = this.minecraft.player;
            if (playerPos != null && this == player.level() && player.isColliding(pos, state)) {
                player.absSnapTo(playerPos.x, playerPos.y, playerPos.z);
            }
        }
    }
 
    BlockStatePredictionHandler getBlockStatePredictionHandler() {
        return this.blockStatePredictionHandler;
    }
 
    @Override
    public boolean setBlock(BlockPos pos, BlockState blockState, @Block.UpdateFlags int updateFlags, int updateLimit) {
        if (this.blockStatePredictionHandler.isPredicting()) {
            BlockState oldState = this.getBlockState(pos);
            boolean success = super.setBlock(pos, blockState, updateFlags, updateLimit);
            if (success) {
                this.blockStatePredictionHandler.retainKnownServerState(pos, oldState, this.minecraft.player);
            }
 
            return success;
        } else {
            return super.setBlock(pos, blockState, updateFlags, updateLimit);
        }
    }
 
    public ClientLevel(
        ClientPacketListener connection,
        ClientLevel.ClientLevelData levelData,
        ResourceKey<Level> dimension,
        Holder<DimensionType> dimensionType,
        int serverChunkRadius,
        int serverSimulationDistance,
        LevelRenderer levelRenderer,
        boolean isDebug,
        long biomeZoomSeed,
        int seaLevel
    ) {
        super(levelData, dimension, connection.registryAccess(), dimensionType, true, isDebug, biomeZoomSeed, 1000000);
        this.connection = connection;
        this.chunkSource = new ClientChunkCache(this, serverChunkRadius);
        this.tickRateManager = new TickRateManager();
        this.clientLevelData = levelData;
        this.levelRenderer = levelRenderer;
        this.seaLevel = seaLevel;
        this.levelEventHandler = new LevelEventHandler(this.minecraft, this);
        this.endFlashState = dimensionType.value().hasEndFlashes() ? new EndFlashState() : null;
        this.setRespawnData(LevelData.RespawnData.of(dimension, new BlockPos(8, 64, 8), 0.0F, 0.0F));
        this.serverSimulationDistance = serverSimulationDistance;
        this.environmentAttributes = this.addEnvironmentAttributeLayers(EnvironmentAttributeSystem.builder()).build();
        this.updateSkyBrightness();
    }
 
    private EnvironmentAttributeSystem.Builder addEnvironmentAttributeLayers(EnvironmentAttributeSystem.Builder environmentAttributes) {
        environmentAttributes.addDefaultLayers(this);
        int flashColor = ARGB.color(204, 204, 255);
        environmentAttributes.addTimeBasedLayer(
            EnvironmentAttributes.SKY_COLOR, (skyColor, cacheTickId) -> this.getSkyFlashTime() > 0 ? ARGB.srgbLerp(0.22F, skyColor, flashColor) : skyColor
        );
        environmentAttributes.addTimeBasedLayer(
            EnvironmentAttributes.SKY_LIGHT_FACTOR, (skyFactor, cacheTickId) -> this.getSkyFlashTime() > 0 ? 1.0F : skyFactor
        );
        return environmentAttributes;
    }
 
    public void queueLightUpdate(Runnable update) {
        this.lightUpdateQueue.add(update);
    }
 
    public void pollLightUpdates() {
        int size = this.lightUpdateQueue.size();
        int lightUpdatesPerFrame = size < 1000 ? Math.max(10, size / 10) : size;
 
        for (int i = 0; i < lightUpdatesPerFrame; i++) {
            Runnable update = this.lightUpdateQueue.poll();
            if (update == null) {
                break;
            }
 
            update.run();
        }
    }
 
    public @Nullable EndFlashState endFlashState() {
        return this.endFlashState;
    }
 
    public void tick(BooleanSupplier haveTime) {
        this.updateSkyBrightness();
        if (this.tickRateManager().runsNormally()) {
            this.getWorldBorder().tick();
            this.tickTime();
        }
 
        if (this.skyFlashTime > 0) {
            this.setSkyFlashTime(this.skyFlashTime - 1);
        }
 
        if (this.endFlashState != null) {
            this.endFlashState.tick(this.getDefaultClockTime());
            if (this.endFlashState.flashStartedThisTick() && !(this.minecraft.screen instanceof WinScreen)) {
                this.minecraft
                    .getSoundManager()
                    .playDelayed(
                        new DirectionalSoundInstance(
                            SoundEvents.WEATHER_END_FLASH,
                            SoundSource.WEATHER,
                            this.random,
                            this.minecraft.gameRenderer.getMainCamera(),
                            this.endFlashState.getXAngle(),
                            this.endFlashState.getYAngle()
                        ),
                        30
                    );
            }
        }
 
        this.explosionTracker.tick(this);
 
        try (Zone ignored = Profiler.get().zone("blocks")) {
            this.chunkSource.tick(haveTime, true);
        }
 
        JvmProfiler.INSTANCE.onClientTick(this.minecraft.getFps());
        this.environmentAttributes().invalidateTickCache();
    }
 
    private void tickTime() {
        this.clientLevelData.setGameTime(this.clientLevelData.getGameTime() + 1L);
    }
 
    public void setTimeFromServer(long gameTime) {
        this.clientLevelData.setGameTime(gameTime);
    }
 
    public Iterable<Entity> entitiesForRendering() {
        return this.getEntities().getAll();
    }
 
    public void tickEntities() {
        this.tickingEntities.forEach(entity -> {
            if (!entity.isRemoved() && !entity.isPassenger() && !this.tickRateManager.isEntityFrozen(entity)) {
                this.guardEntityTick(this::tickNonPassenger, entity);
            }
        });
    }
 
    public boolean isTickingEntity(Entity entity) {
        return this.tickingEntities.contains(entity);
    }
 
    @Override
    public boolean shouldTickDeath(Entity entity) {
        return entity.chunkPosition().getChessboardDistance(this.minecraft.player.chunkPosition()) <= this.serverSimulationDistance;
    }
 
    public void tickNonPassenger(Entity entity) {
        entity.setOldPosAndRot();
        entity.tickCount++;
        Profiler.get().push(entity.typeHolder()::getRegisteredName);
        entity.tick();
        Profiler.get().pop();
 
        for (Entity passenger : entity.getPassengers()) {
            this.tickPassenger(entity, passenger);
        }
    }
 
    private void tickPassenger(Entity vehicle, Entity entity) {
        if (entity.isRemoved() || entity.getVehicle() != vehicle) {
            entity.stopRiding();
        } else if (entity instanceof Player || this.tickingEntities.contains(entity)) {
            entity.setOldPosAndRot();
            entity.tickCount++;
            entity.rideTick();
 
            for (Entity passenger : entity.getPassengers()) {
                this.tickPassenger(entity, passenger);
            }
        }
    }
 
    public void update() {
        ProfilerFiller profiler = Profiler.get();
        profiler.push("populateLightUpdates");
        this.pollLightUpdates();
        profiler.popPush("runLightUpdates");
        this.getChunkSource().getLightEngine().runLightUpdates();
        profiler.pop();
    }
 
    public void unload(LevelChunk levelChunk) {
        levelChunk.clearAllBlockEntities();
        this.chunkSource.getLightEngine().setLightEnabled(levelChunk.getPos(), false);
        this.entityStorage.stopTicking(levelChunk.getPos());
    }
 
    public void onChunkLoaded(ChunkPos pos) {
        this.tintCaches.forEach((resolver, cache) -> cache.invalidateForChunk(pos.x(), pos.z()));
        this.entityStorage.startTicking(pos);
    }
 
    public void onSectionBecomingNonEmpty(long sectionNode) {
        this.levelRenderer.onSectionBecomingNonEmpty(sectionNode);
    }
 
    public void clearTintCaches() {
        this.tintCaches.forEach((resolver, cache) -> cache.invalidateAll());
    }
 
    @Override
    public boolean hasChunk(int chunkX, int chunkZ) {
        return true;
    }
 
    public int getEntityCount() {
        return this.entityStorage.count();
    }
 
    public void addEntity(Entity entity) {
        this.removeEntity(entity.getId(), Entity.RemovalReason.DISCARDED);
        this.entityStorage.addEntity(entity);
    }
 
    public void removeEntity(int id, Entity.RemovalReason reason) {
        Entity entity = this.getEntities().get(id);
        if (entity != null) {
            entity.setRemoved(reason);
            entity.onClientRemoval();
        }
    }
 
    @Override
    public List<Entity> getPushableEntities(Entity pusher, AABB boundingBox) {
        LocalPlayer player = this.minecraft.player;
        return player != null && player != pusher && player.getBoundingBox().intersects(boundingBox) && EntitySelector.pushableBy(pusher).test(player)
            ? List.of(player)
            : List.of();
    }
 
    @Override
    public @Nullable Entity getEntity(int id) {
        return this.getEntities().get(id);
    }
 
    public void disconnect(Component message) {
        this.connection.getConnection().disconnect(message);
    }
 
    public void animateTick(int xt, int yt, int zt) {
        int r = 32;
        RandomSource animateRandom = RandomSource.createThreadLocalInstance();
        Block markerParticleTarget = this.getMarkerParticleTarget();
        BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
 
        for (int i = 0; i < 667; i++) {
            this.doAnimateTick(xt, yt, zt, 16, animateRandom, markerParticleTarget, pos);
            this.doAnimateTick(xt, yt, zt, 32, animateRandom, markerParticleTarget, pos);
        }
    }
 
    private @Nullable Block getMarkerParticleTarget() {
        if (this.minecraft.gameMode.getPlayerMode() == GameType.CREATIVE) {
            ItemStack carriedItemStack = this.minecraft.player.getMainHandItem();
            Item carriedItem = carriedItemStack.getItem();
            if (MARKER_PARTICLE_ITEMS.contains(carriedItem) && carriedItem instanceof BlockItem blockItem) {
                return blockItem.getBlock();
            }
        }
 
        return null;
    }
 
    public void doAnimateTick(int xt, int yt, int zt, int r, RandomSource animateRandom, @Nullable Block markerParticleTarget, BlockPos.MutableBlockPos pos) {
        int x = xt + this.random.nextInt(r) - this.random.nextInt(r);
        int y = yt + this.random.nextInt(r) - this.random.nextInt(r);
        int z = zt + this.random.nextInt(r) - this.random.nextInt(r);
        pos.set(x, y, z);
        BlockState state = this.getBlockState(pos);
        state.getBlock().animateTick(state, this, pos, animateRandom);
        FluidState fluidState = this.getFluidState(pos);
        if (!fluidState.isEmpty()) {
            fluidState.animateTick(this, pos, animateRandom);
            ParticleOptions dripParticle = fluidState.getDripParticle();
            if (dripParticle != null && this.random.nextInt(10) == 0) {
                boolean hasWatertightBottom = state.isFaceSturdy(this, pos, Direction.DOWN);
                BlockPos below = pos.below();
                this.trySpawnDripParticles(below, this.getBlockState(below), dripParticle, hasWatertightBottom);
            }
        }
 
        if (markerParticleTarget == state.getBlock()) {
            this.addParticle(new BlockParticleOption(ParticleTypes.BLOCK_MARKER, state), x + 0.5, y + 0.5, z + 0.5, 0.0, 0.0, 0.0);
        }
 
        if (!state.isCollisionShapeFullBlock(this, pos)) {
            for (AmbientParticle particle : this.environmentAttributes().getValue(EnvironmentAttributes.AMBIENT_PARTICLES, pos)) {
                if (particle.canSpawn(this.random)) {
                    this.addParticle(
                        particle.particle(),
                        pos.getX() + this.random.nextDouble(),
                        pos.getY() + this.random.nextDouble(),
                        pos.getZ() + this.random.nextDouble(),
                        0.0,
                        0.0,
                        0.0
                    );
                }
            }
        }
    }
 
    private void trySpawnDripParticles(BlockPos pos, BlockState state, ParticleOptions dripParticle, boolean isTopSolid) {
        if (state.getFluidState().isEmpty()) {
            VoxelShape collisionShape = state.getCollisionShape(this, pos);
            double topSideHeight = collisionShape.max(Direction.Axis.Y);
            if (topSideHeight < 1.0) {
                if (isTopSolid) {
                    this.spawnFluidParticle(pos.getX(), pos.getX() + 1, pos.getZ(), pos.getZ() + 1, pos.getY() + 1 - 0.05, dripParticle);
                }
            } else if (!state.is(BlockTags.IMPERMEABLE)) {
                double bottomSideHeight = collisionShape.min(Direction.Axis.Y);
                if (bottomSideHeight > 0.0) {
                    this.spawnParticle(pos, dripParticle, collisionShape, pos.getY() + bottomSideHeight - 0.05);
                } else {
                    BlockPos below = pos.below();
                    BlockState belowState = this.getBlockState(below);
                    VoxelShape belowShape = belowState.getCollisionShape(this, below);
                    double belowTopSideHeight = belowShape.max(Direction.Axis.Y);
                    if (belowTopSideHeight < 1.0 && belowState.getFluidState().isEmpty()) {
                        this.spawnParticle(pos, dripParticle, collisionShape, pos.getY() - 0.05);
                    }
                }
            }
        }
    }
 
    private void spawnParticle(BlockPos pos, ParticleOptions dripParticle, VoxelShape dripShape, double height) {
        this.spawnFluidParticle(
            pos.getX() + dripShape.min(Direction.Axis.X),
            pos.getX() + dripShape.max(Direction.Axis.X),
            pos.getZ() + dripShape.min(Direction.Axis.Z),
            pos.getZ() + dripShape.max(Direction.Axis.Z),
            height,
            dripParticle
        );
    }
 
    private void spawnFluidParticle(double x1, double x2, double z1, double z2, double y, ParticleOptions dripParticle) {
        this.addParticle(dripParticle, Mth.lerp(this.random.nextDouble(), x1, x2), y, Mth.lerp(this.random.nextDouble(), z1, z2), 0.0, 0.0, 0.0);
    }
 
    @Override
    public CrashReportCategory fillReportDetails(CrashReport report) {
        CrashReportCategory category = super.fillReportDetails(report);
        category.setDetail("Server brand", () -> this.minecraft.player.connection.serverBrand());
        category.setDetail(
            "Server type", () -> this.minecraft.getSingleplayerServer() == null ? "Non-integrated multiplayer server" : "Integrated singleplayer server"
        );
        category.setDetail("Tracked entity count", () -> String.valueOf(this.getEntityCount()));
        category.setDetail("Client weather", () -> String.format(Locale.ROOT, "Raining: %b, thundering: %b", this.isRaining(), this.isThundering()));
        return category;
    }
 
    @Override
    public void playSeededSound(
        @Nullable Entity except, double x, double y, double z, Holder<SoundEvent> sound, SoundSource source, float volume, float pitch, long seed
    ) {
        if (except == this.minecraft.player) {
            this.playSound(x, y, z, sound.value(), source, volume, pitch, false, seed);
        }
    }
 
    @Override
    public void playSeededSound(
        @Nullable Entity except, Entity sourceEntity, Holder<SoundEvent> sound, SoundSource source, float volume, float pitch, long seed
    ) {
        if (except == this.minecraft.player) {
            this.minecraft.getSoundManager().play(new EntityBoundSoundInstance(sound.value(), source, volume, pitch, sourceEntity, seed));
        }
    }
 
    @Override
    public void playLocalSound(Entity sourceEntity, SoundEvent sound, SoundSource source, float volume, float pitch) {
        this.minecraft.getSoundManager().play(new EntityBoundSoundInstance(sound, source, volume, pitch, sourceEntity, this.random.nextLong()));
    }
 
    @Override
    public void playPlayerSound(SoundEvent sound, SoundSource source, float volume, float pitch) {
        if (this.minecraft.player != null) {
            this.minecraft.getSoundManager().play(new EntityBoundSoundInstance(sound, source, volume, pitch, this.minecraft.player, this.random.nextLong()));
        }
    }
 
    @Override
    public void playLocalSound(double x, double y, double z, SoundEvent sound, SoundSource source, float volume, float pitch, boolean distanceDelay) {
        this.playSound(x, y, z, sound, source, volume, pitch, distanceDelay, this.random.nextLong());
    }
 
    private void playSound(double x, double y, double z, SoundEvent sound, SoundSource source, float volume, float pitch, boolean distanceDelay, long seed) {
        double distanceToSqr = this.minecraft.gameRenderer.getMainCamera().position().distanceToSqr(x, y, z);
        SimpleSoundInstance instance = new SimpleSoundInstance(sound, source, volume, pitch, RandomSource.create(seed), x, y, z);
        if (distanceDelay && distanceToSqr > 100.0) {
            double delayInSeconds = Math.sqrt(distanceToSqr) / 40.0;
            this.minecraft.getSoundManager().playDelayed(instance, (int)(delayInSeconds * 20.0));
        } else {
            this.minecraft.getSoundManager().play(instance);
        }
    }
 
    @Override
    public void createFireworks(double x, double y, double z, double xd, double yd, double zd, List<FireworkExplosion> explosions) {
        if (explosions.isEmpty()) {
            for (int i = 0; i < this.random.nextInt(3) + 2; i++) {
                this.addParticle(ParticleTypes.POOF, x, y, z, this.random.nextGaussian() * 0.05, 0.005, this.random.nextGaussian() * 0.05);
            }
        } else {
            this.minecraft.particleEngine.add(new FireworkParticles.Starter(this, x, y, z, xd, yd, zd, this.minecraft.particleEngine, explosions));
        }
    }
 
    @Override
    public void sendPacketToServer(Packet<?> packet) {
        this.connection.send(packet);
    }
 
    @Override
    public WorldBorder getWorldBorder() {
        return this.worldBorder;
    }
 
    @Override
    public RecipeAccess recipeAccess() {
        return this.connection.recipes();
    }
 
    @Override
    public TickRateManager tickRateManager() {
        return this.tickRateManager;
    }
 
    public ClientClockManager clockManager() {
        return this.connection.clockManager();
    }
 
    @Override
    public EnvironmentAttributeSystem environmentAttributes() {
        return this.environmentAttributes;
    }
 
    @Override
    public LevelTickAccess<Block> getBlockTicks() {
        return BlackholeTickAccess.emptyLevelList();
    }
 
    @Override
    public LevelTickAccess<Fluid> getFluidTicks() {
        return BlackholeTickAccess.emptyLevelList();
    }
 
    public ClientChunkCache getChunkSource() {
        return this.chunkSource;
    }
 
    @Override
    public @Nullable MapItemSavedData getMapData(MapId id) {
        return this.mapData.get(id);
    }
 
    public void overrideMapData(MapId id, MapItemSavedData data) {
        this.mapData.put(id, data);
    }
 
    @Override
    public Scoreboard getScoreboard() {
        return this.connection.scoreboard();
    }
 
    @Override
    public void sendBlockUpdated(BlockPos pos, BlockState old, BlockState current, @Block.UpdateFlags int updateFlags) {
        this.levelRenderer.blockChanged(this, pos, old, current, updateFlags);
    }
 
    @Override
    public void setBlocksDirty(BlockPos pos, BlockState oldState, BlockState newState) {
        this.levelRenderer.setBlockDirty(pos, oldState, newState);
    }
 
    public void setSectionDirtyWithNeighbors(int chunkX, int chunkY, int chunkZ) {
        this.levelRenderer.setSectionDirtyWithNeighbors(chunkX, chunkY, chunkZ);
    }
 
    public void setSectionRangeDirty(int minSectionX, int minSectionY, int minSectionZ, int maxSectionX, int maxSectionY, int maxSectionZ) {
        this.levelRenderer.setSectionRangeDirty(minSectionX, minSectionY, minSectionZ, maxSectionX, maxSectionY, maxSectionZ);
    }
 
    @Override
    public void destroyBlockProgress(int id, BlockPos blockPos, int progress) {
        this.levelRenderer.destroyBlockProgress(id, blockPos, progress);
    }
 
    @Override
    public void globalLevelEvent(int type, BlockPos pos, int data) {
        this.levelEventHandler.globalLevelEvent(type, pos, data);
    }
 
    @Override
    public void levelEvent(@Nullable Entity source, int type, BlockPos pos, int data) {
        try {
            this.levelEventHandler.levelEvent(type, pos, data);
        } catch (Throwable var8) {
            CrashReport report = CrashReport.forThrowable(var8, "Playing level event");
            CrashReportCategory category = report.addCategory("Level event being played");
            category.setDetail("Block coordinates", CrashReportCategory.formatLocation(this, pos));
            category.setDetail("Event source", source);
            category.setDetail("Event type", type);
            category.setDetail("Event data", data);
            throw new ReportedException(report);
        }
    }
 
    @Override
    public void addParticle(ParticleOptions particle, double x, double y, double z, double xd, double yd, double zd) {
        this.doAddParticle(particle, particle.getType().getOverrideLimiter(), false, x, y, z, xd, yd, zd);
    }
 
    @Override
    public void addParticle(
        ParticleOptions particle, boolean overrideLimiter, boolean alwaysShow, double x, double y, double z, double xd, double yd, double zd
    ) {
        this.doAddParticle(particle, particle.getType().getOverrideLimiter() || overrideLimiter, alwaysShow, x, y, z, xd, yd, zd);
    }
 
    @Override
    public void addAlwaysVisibleParticle(ParticleOptions particle, double x, double y, double z, double xd, double yd, double zd) {
        this.doAddParticle(particle, false, true, x, y, z, xd, yd, zd);
    }
 
    @Override
    public void addAlwaysVisibleParticle(ParticleOptions particle, boolean overrideLimiter, double x, double y, double z, double xd, double yd, double zd) {
        this.doAddParticle(particle, particle.getType().getOverrideLimiter() || overrideLimiter, true, x, y, z, xd, yd, zd);
    }
 
    private void doAddParticle(
        ParticleOptions particle, boolean overrideLimiter, boolean alwaysShowParticles, double x, double y, double z, double xd, double yd, double zd
    ) {
        try {
            Camera camera = this.minecraft.gameRenderer.getMainCamera();
            ParticleStatus particleLevel = this.calculateParticleLevel(alwaysShowParticles);
            if (overrideLimiter) {
                this.minecraft.particleEngine.createParticle(particle, x, y, z, xd, yd, zd);
            } else if (!(camera.position().distanceToSqr(x, y, z) > 1024.0)) {
                if (particleLevel != ParticleStatus.MINIMAL) {
                    this.minecraft.particleEngine.createParticle(particle, x, y, z, xd, yd, zd);
                }
            }
        } catch (Throwable var19) {
            CrashReport report = CrashReport.forThrowable(var19, "Exception while adding particle");
            CrashReportCategory category = report.addCategory("Particle being added");
            category.setDetail("ID", BuiltInRegistries.PARTICLE_TYPE.getKey(particle.getType()));
            category.setDetail(
                "Parameters", () -> ParticleTypes.CODEC.encodeStart(this.registryAccess().createSerializationContext(NbtOps.INSTANCE), particle).toString()
            );
            category.setDetail("Position", () -> CrashReportCategory.formatLocation(this, x, y, z));
            throw new ReportedException(report);
        }
    }
 
    private ParticleStatus calculateParticleLevel(boolean alwaysShowParticles) {
        ParticleStatus particleLevel = this.minecraft.options.particles().get();
        if (alwaysShowParticles && particleLevel == ParticleStatus.MINIMAL && this.random.nextInt(10) == 0) {
            particleLevel = ParticleStatus.DECREASED;
        }
 
        if (particleLevel == ParticleStatus.DECREASED && this.random.nextInt(3) == 0) {
            particleLevel = ParticleStatus.MINIMAL;
        }
 
        return particleLevel;
    }
 
    @Override
    public List<AbstractClientPlayer> players() {
        return this.players;
    }
 
    public List<EnderDragonPart> dragonParts() {
        return this.dragonParts;
    }
 
    @Override
    public Holder<Biome> getUncachedNoiseBiome(int quartX, int quartY, int quartZ) {
        return this.registryAccess().lookupOrThrow(Registries.BIOME).getOrThrow(Biomes.PLAINS);
    }
 
    private int getSkyFlashTime() {
        return this.minecraft.options.hideLightningFlash().get() ? 0 : this.skyFlashTime;
    }
 
    @Override
    public void setSkyFlashTime(int skyFlashTime) {
        this.skyFlashTime = skyFlashTime;
    }
 
    @Override
    public CardinalLighting cardinalLighting() {
        return this.dimensionType().cardinalLightType().get();
    }
 
    @Override
    public int getBlockTint(BlockPos pos, ColorResolver resolver) {
        BlockTintCache cache = this.tintCaches.get(resolver);
        return cache.getColor(pos);
    }
 
    public int calculateBlockTint(BlockPos pos, ColorResolver colorResolver) {
        int dist = Minecraft.getInstance().options.biomeBlendRadius().get();
        if (dist == 0) {
            return colorResolver.getColor(this.getBiome(pos).value(), pos.getX(), pos.getZ());
        } else {
            int count = (dist * 2 + 1) * (dist * 2 + 1);
            int totalRed = 0;
            int totalGreen = 0;
            int totalBlue = 0;
            Cursor3D cursor = new Cursor3D(pos.getX() - dist, pos.getY(), pos.getZ() - dist, pos.getX() + dist, pos.getY(), pos.getZ() + dist);
            BlockPos.MutableBlockPos nextPos = new BlockPos.MutableBlockPos();
 
            while (cursor.advance()) {
                nextPos.set(cursor.nextX(), cursor.nextY(), cursor.nextZ());
                int color = colorResolver.getColor(this.getBiome(nextPos).value(), nextPos.getX(), nextPos.getZ());
                totalRed += ARGB.red(color);
                totalGreen += ARGB.green(color);
                totalBlue += ARGB.blue(color);
            }
 
            return ARGB.color(totalRed / count, totalGreen / count, totalBlue / count);
        }
    }
 
    @Override
    public void setRespawnData(LevelData.RespawnData respawnData) {
        this.levelData.setSpawn(this.getWorldBorderAdjustedRespawnData(respawnData));
    }
 
    @Override
    public LevelData.RespawnData getRespawnData() {
        return this.levelData.getRespawnData();
    }
 
    @Override
    public String toString() {
        return "ClientLevel";
    }
 
    public ClientLevel.ClientLevelData getLevelData() {
        return this.clientLevelData;
    }
 
    @Override
    public void gameEvent(Holder<GameEvent> gameEvent, Vec3 pos, GameEvent.Context context) {
    }
 
    protected Map<MapId, MapItemSavedData> getAllMapData() {
        return ImmutableMap.copyOf(this.mapData);
    }
 
    protected void addMapData(Map<MapId, MapItemSavedData> mapData) {
        this.mapData.putAll(mapData);
    }
 
    @Override
    protected LevelEntityGetter<Entity> getEntities() {
        return this.entityStorage.getEntityGetter();
    }
 
    @Override
    public String gatherChunkSourceStats() {
        return "Chunks[C] W: " + this.chunkSource.gatherStats() + " E: " + this.entityStorage.gatherStats();
    }
 
    @Override
    public void addDestroyBlockEffect(BlockPos pos, BlockState blockState) {
        if (!blockState.isAir() && blockState.shouldSpawnTerrainParticles()) {
            VoxelShape shape = blockState.getShape(this, pos);
            double density = 0.25;
            shape.forAllBoxes(
                (x1, y1, z1, x2, y2, z2) -> {
                    double widthX = Math.min(1.0, x2 - x1);
                    double widthY = Math.min(1.0, y2 - y1);
                    double widthZ = Math.min(1.0, z2 - z1);
                    int countX = Math.max(2, Mth.ceil(widthX / 0.25));
                    int countY = Math.max(2, Mth.ceil(widthY / 0.25));
                    int countZ = Math.max(2, Mth.ceil(widthZ / 0.25));
 
                    for (int xx = 0; xx < countX; xx++) {
                        for (int yy = 0; yy < countY; yy++) {
                            for (int zz = 0; zz < countZ; zz++) {
                                double relX = (xx + 0.5) / countX;
                                double relY = (yy + 0.5) / countY;
                                double relZ = (zz + 0.5) / countZ;
                                double x = relX * widthX + x1;
                                double y = relY * widthY + y1;
                                double z = relZ * widthZ + z1;
                                this.minecraft
                                    .particleEngine
                                    .add(
                                        new TerrainParticle(
                                            this, pos.getX() + x, pos.getY() + y, pos.getZ() + z, relX - 0.5, relY - 0.5, relZ - 0.5, blockState, pos
                                        )
                                    );
                            }
                        }
                    }
                }
            );
        }
    }
 
    public void addBreakingBlockEffect(BlockPos pos, Direction direction) {
        BlockState blockState = this.getBlockState(pos);
        if (blockState.getRenderShape() != RenderShape.INVISIBLE && blockState.shouldSpawnTerrainParticles()) {
            int x = pos.getX();
            int y = pos.getY();
            int z = pos.getZ();
            float r = 0.1F;
            AABB shape = blockState.getShape(this, pos).bounds();
            double xp = x + this.random.nextDouble() * (shape.maxX - shape.minX - 0.2F) + 0.1F + shape.minX;
            double yp = y + this.random.nextDouble() * (shape.maxY - shape.minY - 0.2F) + 0.1F + shape.minY;
            double zp = z + this.random.nextDouble() * (shape.maxZ - shape.minZ - 0.2F) + 0.1F + shape.minZ;
            if (direction == Direction.DOWN) {
                yp = y + shape.minY - 0.1F;
            }
 
            if (direction == Direction.UP) {
                yp = y + shape.maxY + 0.1F;
            }
 
            if (direction == Direction.NORTH) {
                zp = z + shape.minZ - 0.1F;
            }
 
            if (direction == Direction.SOUTH) {
                zp = z + shape.maxZ + 0.1F;
            }
 
            if (direction == Direction.WEST) {
                xp = x + shape.minX - 0.1F;
            }
 
            if (direction == Direction.EAST) {
                xp = x + shape.maxX + 0.1F;
            }
 
            this.minecraft.particleEngine.add(new TerrainParticle(this, xp, yp, zp, 0.0, 0.0, 0.0, blockState, pos).setPower(0.2F).scale(0.6F));
        }
    }
 
    public void setServerSimulationDistance(int serverSimulationDistance) {
        this.serverSimulationDistance = serverSimulationDistance;
    }
 
    public int getServerSimulationDistance() {
        return this.serverSimulationDistance;
    }
 
    @Override
    public FeatureFlagSet enabledFeatures() {
        return this.connection.enabledFeatures();
    }
 
    @Override
    public PotionBrewing potionBrewing() {
        return this.connection.potionBrewing();
    }
 
    @Override
    public FuelValues fuelValues() {
        return this.connection.fuelValues();
    }
 
    @Override
    public void explode(
        @Nullable Entity source,
        @Nullable DamageSource damageSource,
        @Nullable ExplosionDamageCalculator damageCalculator,
        double x,
        double y,
        double z,
        float r,
        boolean fire,
        Level.ExplosionInteraction interactionType,
        ParticleOptions smallExplosionParticles,
        ParticleOptions largeExplosionParticles,
        WeightedList<ExplosionParticleInfo> secondaryParticles,
        Holder<SoundEvent> explosionSound
    ) {
    }
 
    @Override
    public int getSeaLevel() {
        return this.seaLevel;
    }
 
    @Override
    public int getClientLeafTintColor(BlockPos pos) {
        BlockState state = this.getBlockState(pos);
        BlockTintSource tintSource = Minecraft.getInstance().getBlockColors().getTintSource(state, 0);
        return tintSource != null ? tintSource.colorInWorld(state, this, pos) : -1;
    }
 
    @Override
    public void registerForCleaning(CacheSlot<ClientLevel, ?> slot) {
        this.connection.registerForCleaning(slot);
    }
 
    public void trackExplosionEffects(Vec3 center, float radius, int blockCount, WeightedList<ExplosionParticleInfo> blockParticles) {
        this.explosionTracker.track(center, radius, blockCount, blockParticles);
    }
 
    @OnlyIn(Dist.CLIENT)
    public static class ClientLevelData implements WritableLevelData {
        private final boolean hardcore;
        private final boolean isFlat;
        private LevelData.RespawnData respawnData;
        private long gameTime;
        private Difficulty difficulty;
        private boolean difficultyLocked;
 
        public ClientLevelData(Difficulty difficulty, boolean hardcore, boolean isFlat) {
            this.difficulty = difficulty;
            this.hardcore = hardcore;
            this.isFlat = isFlat;
        }
 
        @Override
        public LevelData.RespawnData getRespawnData() {
            return this.respawnData;
        }
 
        @Override
        public long getGameTime() {
            return this.gameTime;
        }
 
        public void setGameTime(long time) {
            this.gameTime = time;
        }
 
        @Override
        public void setSpawn(LevelData.RespawnData respawnData) {
            this.respawnData = respawnData;
        }
 
        @Override
        public boolean isHardcore() {
            return this.hardcore;
        }
 
        @Override
        public Difficulty getDifficulty() {
            return this.difficulty;
        }
 
        @Override
        public boolean isDifficultyLocked() {
            return this.difficultyLocked;
        }
 
        @Override
        public void fillCrashReportCategory(CrashReportCategory category, LevelHeightAccessor levelHeightAccessor) {
            WritableLevelData.super.fillCrashReportCategory(category, levelHeightAccessor);
        }
 
        public void setDifficulty(Difficulty difficulty) {
            this.difficulty = difficulty;
        }
 
        public void setDifficultyLocked(boolean locked) {
            this.difficultyLocked = locked;
        }
 
        public double getHorizonHeight(LevelHeightAccessor level) {
            return this.isFlat ? level.getMinY() : 63.0;
        }
 
        public float voidDarknessOnsetRange() {
            return this.isFlat ? 1.0F : 32.0F;
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    private final class EntityCallbacks implements LevelCallback<Entity> {
        private EntityCallbacks() {
            Objects.requireNonNull(ClientLevel.this);
            super();
        }
 
        public void onCreated(Entity entity) {
        }
 
        public void onDestroyed(Entity entity) {
        }
 
        public void onTickingStart(Entity entity) {
            ClientLevel.this.tickingEntities.add(entity);
        }
 
        public void onTickingEnd(Entity entity) {
            ClientLevel.this.tickingEntities.remove(entity);
        }
 
        public void onTrackingStart(Entity entity) {
            switch (entity) {
                case AbstractClientPlayer player:
                    ClientLevel.this.players.add(player);
                    break;
                case EnderDragon dragon:
                    ClientLevel.this.dragonParts.addAll(Arrays.asList(dragon.getSubEntities()));
                    break;
                default:
            }
        }
 
        public void onTrackingEnd(Entity entity) {
            entity.unRide();
            switch (entity) {
                case AbstractClientPlayer player:
                    ClientLevel.this.players.remove(player);
                    break;
                case EnderDragon dragon:
                    ClientLevel.this.dragonParts.removeAll(Arrays.asList(dragon.getSubEntities()));
                    break;
                default:
            }
        }
 
        public void onSectionChange(Entity entity) {
        }
    }
}

引用的其他类