ServerLevel.java
net.minecraft.server.level.ServerLevel
信息
- 全限定名:net.minecraft.server.level.ServerLevel
- 类型:public class
- 包:net.minecraft.server.level
- 源码路径:src/main/java/net/minecraft/server/level/ServerLevel.java
- 起始行号:L185
- 继承:Level
- 实现:WorldGenLevel, ServerEntityGetter
- 职责:
TODO
字段/常量
-
END_SPAWN_POINT- 类型:
BlockPos - 修饰符:
public static final - 源码定位:
L186 - 说明:
TODO
- 类型:
-
RAIN_DELAY- 类型:
IntProvider - 修饰符:
public static final - 源码定位:
L187 - 说明:
TODO
- 类型:
-
RAIN_DURATION- 类型:
IntProvider - 修饰符:
public static final - 源码定位:
L188 - 说明:
TODO
- 类型:
-
THUNDER_DELAY- 类型:
IntProvider - 修饰符:
private static final - 源码定位:
L189 - 说明:
TODO
- 类型:
-
THUNDER_DURATION- 类型:
IntProvider - 修饰符:
public static final - 源码定位:
L190 - 说明:
TODO
- 类型:
-
LOGGER- 类型:
Logger - 修饰符:
private static final - 源码定位:
L191 - 说明:
TODO
- 类型:
-
EMPTY_TIME_NO_TICK- 类型:
int - 修饰符:
private static final - 源码定位:
L192 - 说明:
TODO
- 类型:
-
MAX_SCHEDULED_TICKS_PER_TICK- 类型:
int - 修饰符:
private static final - 源码定位:
L193 - 说明:
TODO
- 类型:
-
players- 类型:
List<ServerPlayer> - 修饰符:
private final - 源码定位:
L194 - 说明:
TODO
- 类型:
-
chunkSource- 类型:
ServerChunkCache - 修饰符:
private final - 源码定位:
L195 - 说明:
TODO
- 类型:
-
server- 类型:
MinecraftServer - 修饰符:
private final - 源码定位:
L196 - 说明:
TODO
- 类型:
-
serverLevelData- 类型:
ServerLevelData - 修饰符:
private final - 源码定位:
L197 - 说明:
TODO
- 类型:
-
entityTickList- 类型:
EntityTickList - 修饰符:
private final - 源码定位:
L198 - 说明:
TODO
- 类型:
-
waypointManager- 类型:
ServerWaypointManager - 修饰符:
private final - 源码定位:
L199 - 说明:
TODO
- 类型:
-
environmentAttributes- 类型:
EnvironmentAttributeSystem - 修饰符:
private - 源码定位:
L200 - 说明:
TODO
- 类型:
-
entityManager- 类型:
PersistentEntitySectionManager<Entity> - 修饰符:
private final - 源码定位:
L201 - 说明:
TODO
- 类型:
-
gameEventDispatcher- 类型:
GameEventDispatcher - 修饰符:
private final - 源码定位:
L202 - 说明:
TODO
- 类型:
-
noSave- 类型:
boolean - 修饰符:
public - 源码定位:
L203 - 说明:
TODO
- 类型:
-
sleepStatus- 类型:
SleepStatus - 修饰符:
private final - 源码定位:
L204 - 说明:
TODO
- 类型:
-
emptyTime- 类型:
int - 修饰符:
private - 源码定位:
L205 - 说明:
TODO
- 类型:
-
portalForcer- 类型:
PortalForcer - 修饰符:
private final - 源码定位:
L206 - 说明:
TODO
- 类型:
-
blockTicks- 类型:
LevelTicks<Block> - 修饰符:
private final - 源码定位:
L207 - 说明:
TODO
- 类型:
-
fluidTicks- 类型:
LevelTicks<Fluid> - 修饰符:
private final - 源码定位:
L208 - 说明:
TODO
- 类型:
-
pathTypesByPosCache- 类型:
PathTypeCache - 修饰符:
private final - 源码定位:
L209 - 说明:
TODO
- 类型:
-
navigatingMobs- 类型:
Set<Mob> - 修饰符:
private final - 源码定位:
L210 - 说明:
TODO
- 类型:
-
isUpdatingNavigations- 类型:
boolean - 修饰符:
private volatile - 源码定位:
L211 - 说明:
TODO
- 类型:
-
raids- 类型:
Raids - 修饰符:
protected final - 源码定位:
L212 - 说明:
TODO
- 类型:
-
blockEvents- 类型:
ObjectLinkedOpenHashSet<BlockEventData> - 修饰符:
private final - 源码定位:
L213 - 说明:
TODO
- 类型:
-
blockEventsToReschedule- 类型:
List<BlockEventData> - 修饰符:
private final - 源码定位:
L214 - 说明:
TODO
- 类型:
-
handlingTick- 类型:
boolean - 修饰符:
private - 源码定位:
L215 - 说明:
TODO
- 类型:
-
customSpawners- 类型:
List<CustomSpawner> - 修饰符:
private final - 源码定位:
L216 - 说明:
TODO
- 类型:
-
dragonFight- 类型:
EnderDragonFight - 修饰符:
private - 源码定位:
L217 - 说明:
TODO
- 类型:
-
dragonParts- 类型:
Int2ObjectMap<EnderDragonPart> - 修饰符:
private final - 源码定位:
L218 - 说明:
TODO
- 类型:
-
structureManager- 类型:
StructureManager - 修饰符:
private final - 源码定位:
L219 - 说明:
TODO
- 类型:
-
structureCheck- 类型:
StructureCheck - 修饰符:
private final - 源码定位:
L220 - 说明:
TODO
- 类型:
-
tickTime- 类型:
boolean - 修饰符:
private final - 源码定位:
L221 - 说明:
TODO
- 类型:
-
debugSynchronizers- 类型:
LevelDebugSynchronizers - 修饰符:
private final - 源码定位:
L222 - 说明:
TODO
- 类型:
内部类/嵌套类型
-
net.minecraft.server.level.ServerLevel.=- 类型:
record - 修饰符:
package-private - 源码定位:
L1490 - 说明:
TODO
- 类型:
-
net.minecraft.server.level.ServerLevel.=- 类型:
record - 修饰符:
package-private - 源码定位:
L1491 - 说明:
TODO
- 类型:
-
net.minecraft.server.level.ServerLevel.=.)- 类型:
record - 修饰符:
package-private - 源码定位:
L1492 - 说明:
TODO
- 类型:
-
net.minecraft.server.level.ServerLevel.EntityCallbacks- 类型:
class - 修饰符:
private final - 源码定位:
L1855 - 说明:
TODO
- 类型:
构造器
public ServerLevel(MinecraftServer server, Executor executor, LevelStorageSource.LevelStorageAccess levelStorage, ServerLevelData levelData, ResourceKey<Level> dimension, LevelStem levelStem, boolean isDebug, long biomeZoomSeed, List<CustomSpawner> customSpawners, boolean tickTime) @ L224
- 构造器名:ServerLevel
- 源码定位:L224
- 修饰符:public
参数:
- server: MinecraftServer
- executor: Executor
- levelStorage: LevelStorageSource.LevelStorageAccess
- levelData: ServerLevelData
- dimension: ResourceKey
- levelStem: LevelStem
- isDebug: boolean
- biomeZoomSeed: long
- customSpawners: List
- tickTime: boolean
说明:
TODO
方法
下面的方法块按源码顺序生成。
public void setDragonFight(EnderDragonFight fight) @ L308
- 方法名:setDragonFight
- 源码定位:L308
- 返回类型:void
- 修饰符:public
参数:
- fight: EnderDragonFight
说明:
TODO
public Holder<Biome> getUncachedNoiseBiome(int quartX, int quartY, int quartZ) @ L314
- 方法名:getUncachedNoiseBiome
- 源码定位:L314
- 返回类型:Holder
- 修饰符:public
参数:
- quartX: int
- quartY: int
- quartZ: int
说明:
TODO
public StructureManager structureManager() @ L319
- 方法名:structureManager
- 源码定位:L319
- 返回类型:StructureManager
- 修饰符:public
参数:
- 无
说明:
TODO
public ServerClockManager clockManager() @ L323
- 方法名:clockManager
- 源码定位:L323
- 返回类型:ServerClockManager
- 修饰符:public
参数:
- 无
说明:
TODO
public EnvironmentAttributeSystem environmentAttributes() @ L327
- 方法名:environmentAttributes
- 源码定位:L327
- 返回类型:EnvironmentAttributeSystem
- 修饰符:public
参数:
- 无
说明:
TODO
public EnvironmentAttributeSystem setEnvironmentAttributes(EnvironmentAttributeSystem environmentAttributes) @ L332
- 方法名:setEnvironmentAttributes
- 源码定位:L332
- 返回类型:EnvironmentAttributeSystem
- 修饰符:public
参数:
- environmentAttributes: EnvironmentAttributeSystem
说明:
TODO
public void tick(BooleanSupplier haveTime) @ L340
- 方法名:tick
- 源码定位:L340
- 返回类型:void
- 修饰符:public
参数:
- haveTime: BooleanSupplier
说明:
TODO
public boolean shouldTickBlocksAt(long chunkPos) @ L460
- 方法名:shouldTickBlocksAt
- 源码定位:L460
- 返回类型:boolean
- 修饰符:public
参数:
- chunkPos: long
说明:
TODO
protected void tickTime() @ L465
- 方法名:tickTime
- 源码定位:L465
- 返回类型:void
- 修饰符:protected
参数:
- 无
说明:
TODO
public void tickCustomSpawners(boolean spawnEnemies) @ L475
- 方法名:tickCustomSpawners
- 源码定位:L475
- 返回类型:void
- 修饰符:public
参数:
- spawnEnemies: boolean
说明:
TODO
private void wakeUpAllPlayers() @ L481
- 方法名:wakeUpAllPlayers
- 源码定位:L481
- 返回类型:void
- 修饰符:private
参数:
- 无
说明:
TODO
public void tickChunk(LevelChunk chunk, int tickSpeed) @ L486
- 方法名:tickChunk
- 源码定位:L486
- 返回类型:void
- 修饰符:public
参数:
- chunk: LevelChunk
- tickSpeed: int
说明:
TODO
public void tickThunder(LevelChunk chunk) @ L531
- 方法名:tickThunder
- 源码定位:L531
- 返回类型:void
- 修饰符:public
参数:
- chunk: LevelChunk
说明:
TODO
public void tickPrecipitation(BlockPos pos) @ L567
- 方法名:tickPrecipitation
- 源码定位:L567
- 返回类型:void
- 修饰符:public
参数:
- pos: BlockPos
说明:
TODO
private Optional<BlockPos> findLightningRod(BlockPos center) @ L600
- 方法名:findLightningRod
- 源码定位:L600
- 返回类型:Optional
- 修饰符:private
参数:
- center: BlockPos
说明:
TODO
protected BlockPos findLightningTargetAround(BlockPos pos) @ L612
- 方法名:findLightningTargetAround
- 源码定位:L612
- 返回类型:BlockPos
- 修饰符:protected
参数:
- pos: BlockPos
说明:
TODO
public boolean isHandlingTick() @ L632
- 方法名:isHandlingTick
- 源码定位:L632
- 返回类型:boolean
- 修饰符:public
参数:
- 无
说明:
TODO
public boolean canSleepThroughNights() @ L636
- 方法名:canSleepThroughNights
- 源码定位:L636
- 返回类型:boolean
- 修饰符:public
参数:
- 无
说明:
TODO
private void announceSleepStatus() @ L640
- 方法名:announceSleepStatus
- 源码定位:L640
- 返回类型:void
- 修饰符:private
参数:
- 无
说明:
TODO
public void updateSleepingPlayerList() @ L658
- 方法名:updateSleepingPlayerList
- 源码定位:L658
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
public ServerScoreboard getScoreboard() @ L664
- 方法名:getScoreboard
- 源码定位:L664
- 返回类型:ServerScoreboard
- 修饰符:public
参数:
- 无
说明:
TODO
public ServerWaypointManager getWaypointManager() @ L668
- 方法名:getWaypointManager
- 源码定位:L668
- 返回类型:ServerWaypointManager
- 修饰符:public
参数:
- 无
说明:
TODO
public DifficultyInstance getCurrentDifficultyAt(BlockPos pos) @ L672
- 方法名:getCurrentDifficultyAt
- 源码定位:L672
- 返回类型:DifficultyInstance
- 修饰符:public
参数:
- pos: BlockPos
说明:
TODO
public float getMoonBrightness(BlockPos pos) @ L685
- 方法名:getMoonBrightness
- 源码定位:L685
- 返回类型:float
- 修饰符:public
参数:
- pos: BlockPos
说明:
TODO
private void prepareWeather(WeatherData weatherData) @ L690
- 方法名:prepareWeather
- 源码定位:L690
- 返回类型:void
- 修饰符:private
参数:
- weatherData: WeatherData
说明:
TODO
private void advanceWeatherCycle() @ L699
- 方法名:advanceWeatherCycle
- 源码定位:L699
- 返回类型:void
- 修饰符:private
参数:
- 无
说明:
TODO
public void resetWeatherCycle() @ L786
- 方法名:resetWeatherCycle
- 源码定位:L786
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
public void resetEmptyTime() @ L795
- 方法名:resetEmptyTime
- 源码定位:L795
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
private void tickFluid(BlockPos pos, Fluid type) @ L799
- 方法名:tickFluid
- 源码定位:L799
- 返回类型:void
- 修饰符:private
参数:
- pos: BlockPos
- type: Fluid
说明:
TODO
private void tickBlock(BlockPos pos, Block type) @ L807
- 方法名:tickBlock
- 源码定位:L807
- 返回类型:void
- 修饰符:private
参数:
- pos: BlockPos
- type: Block
说明:
TODO
public void tickNonPassenger(Entity entity) @ L814
- 方法名:tickNonPassenger
- 源码定位:L814
- 返回类型:void
- 修饰符:public
参数:
- entity: Entity
说明:
TODO
private void tickPassenger(Entity vehicle, Entity entity) @ L828
- 方法名:tickPassenger
- 源码定位:L828
- 返回类型:void
- 修饰符:private
参数:
- vehicle: Entity
- entity: Entity
说明:
TODO
public void updateNeighboursOnBlockSet(BlockPos pos, BlockState oldState) @ L846
- 方法名:updateNeighboursOnBlockSet
- 源码定位:L846
- 返回类型:void
- 修饰符:public
参数:
- pos: BlockPos
- oldState: BlockState
说明:
TODO
public boolean mayInteract(Entity entity, BlockPos pos) @ L860
- 方法名:mayInteract
- 源码定位:L860
- 返回类型:boolean
- 修饰符:public
参数:
- entity: Entity
- pos: BlockPos
说明:
TODO
public void save(ProgressListener progressListener, boolean flush, boolean noSave) @ L865
- 方法名:save
- 源码定位:L865
- 返回类型:void
- 修饰符:public
参数:
- progressListener: ProgressListener
- flush: boolean
- noSave: boolean
说明:
TODO
private void saveLevelData(boolean sync) @ L886
- 方法名:saveLevelData
- 源码定位:L886
- 返回类型:void
- 修饰符:private
参数:
- sync: boolean
说明:
TODO
public <T extends Entity> List<?extends T> getEntities(EntityTypeTest<Entity,T> type, Predicate<?super T> selector) @ L895
- 方法名:getEntities
- 源码定位:L895
- 返回类型:
List<?extends T> - 修饰符:public
参数:
- type: EntityTypeTest<Entity,T>
- selector: Predicate<?super T>
说明:
TODO
public <T extends Entity> void getEntities(EntityTypeTest<Entity,T> type, Predicate<?super T> selector, List<?super T> result) @ L901
- 方法名:getEntities
- 源码定位:L901
- 返回类型:
void - 修饰符:public
参数:
- type: EntityTypeTest<Entity,T>
- selector: Predicate<?super T>
- result: List<?super T>
说明:
TODO
public <T extends Entity> void getEntities(EntityTypeTest<Entity,T> type, Predicate<?super T> selector, List<?super T> result, int maxResults) @ L905
- 方法名:getEntities
- 源码定位:L905
- 返回类型:
void - 修饰符:public
参数:
- type: EntityTypeTest<Entity,T>
- selector: Predicate<?super T>
- result: List<?super T>
- maxResults: int
说明:
TODO
public List<?extends EnderDragon> getDragons() @ L918
- 方法名:getDragons
- 源码定位:L918
- 返回类型:List<?extends EnderDragon>
- 修饰符:public
参数:
- 无
说明:
TODO
public List<ServerPlayer> getPlayers(Predicate<?super ServerPlayer> selector) @ L922
- 方法名:getPlayers
- 源码定位:L922
- 返回类型:List
- 修饰符:public
参数:
- selector: Predicate<?super ServerPlayer>
说明:
TODO
public List<ServerPlayer> getPlayers(Predicate<?super ServerPlayer> selector, int maxResults) @ L926
- 方法名:getPlayers
- 源码定位:L926
- 返回类型:List
- 修饰符:public
参数:
- selector: Predicate<?super ServerPlayer>
- maxResults: int
说明:
TODO
public ServerPlayer getRandomPlayer() @ L941
- 方法名:getRandomPlayer
- 源码定位:L941
- 返回类型:ServerPlayer
- 修饰符:public
参数:
- 无
说明:
TODO
public boolean addFreshEntity(Entity entity) @ L946
- 方法名:addFreshEntity
- 源码定位:L946
- 返回类型:boolean
- 修饰符:public
参数:
- entity: Entity
说明:
TODO
public boolean addWithUUID(Entity entity) @ L951
- 方法名:addWithUUID
- 源码定位:L951
- 返回类型:boolean
- 修饰符:public
参数:
- entity: Entity
说明:
TODO
public void addDuringTeleport(Entity entity) @ L955
- 方法名:addDuringTeleport
- 源码定位:L955
- 返回类型:void
- 修饰符:public
参数:
- entity: Entity
说明:
TODO
public void addNewPlayer(ServerPlayer player) @ L963
- 方法名:addNewPlayer
- 源码定位:L963
- 返回类型:void
- 修饰符:public
参数:
- player: ServerPlayer
说明:
TODO
public void addRespawnedPlayer(ServerPlayer player) @ L967
- 方法名:addRespawnedPlayer
- 源码定位:L967
- 返回类型:void
- 修饰符:public
参数:
- player: ServerPlayer
说明:
TODO
private void addPlayer(ServerPlayer player) @ L971
- 方法名:addPlayer
- 源码定位:L971
- 返回类型:void
- 修饰符:private
参数:
- player: ServerPlayer
说明:
TODO
private boolean addEntity(Entity entity) @ L982
- 方法名:addEntity
- 源码定位:L982
- 返回类型:boolean
- 修饰符:private
参数:
- entity: Entity
说明:
TODO
public boolean tryAddFreshEntityWithPassengers(Entity entity) @ L991
- 方法名:tryAddFreshEntityWithPassengers
- 源码定位:L991
- 返回类型:boolean
- 修饰符:public
参数:
- entity: Entity
说明:
TODO
public void unload(LevelChunk levelChunk) @ L1000
- 方法名:unload
- 源码定位:L1000
- 返回类型:void
- 修饰符:public
参数:
- levelChunk: LevelChunk
说明:
TODO
public void removePlayerImmediately(ServerPlayer player, Entity.RemovalReason reason) @ L1006
- 方法名:removePlayerImmediately
- 源码定位:L1006
- 返回类型:void
- 修饰符:public
参数:
- player: ServerPlayer
- reason: Entity.RemovalReason
说明:
TODO
public void destroyBlockProgress(int id, BlockPos blockPos, int progress) @ L1010
- 方法名:destroyBlockProgress
- 源码定位:L1010
- 返回类型:void
- 修饰符:public
参数:
- id: int
- blockPos: BlockPos
- progress: int
说明:
TODO
public void playSeededSound(Entity except, double x, double y, double z, Holder<SoundEvent> sound, SoundSource source, float volume, float pitch, long seed) @ L1024
- 方法名:playSeededSound
- 源码定位:L1024
- 返回类型: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) @ L1041
- 方法名:playSeededSound
- 源码定位:L1041
- 返回类型:void
- 修饰符:public
参数:
- except: Entity
- sourceEntity: Entity
- sound: Holder
- source: SoundSource
- volume: float
- pitch: float
- seed: long
说明:
TODO
public void globalLevelEvent(int type, BlockPos pos, int data) @ L1058
- 方法名:globalLevelEvent
- 源码定位:L1058
- 返回类型:void
- 修饰符:public
参数:
- type: int
- pos: BlockPos
- data: int
说明:
TODO
public void levelEvent(Entity source, int type, BlockPos pos, int data) @ L1082
- 方法名:levelEvent
- 源码定位:L1082
- 返回类型:void
- 修饰符:public
参数:
- source: Entity
- type: int
- pos: BlockPos
- data: int
说明:
TODO
public int getLogicalHeight() @ L1097
- 方法名:getLogicalHeight
- 源码定位:L1097
- 返回类型:int
- 修饰符:public
参数:
- 无
说明:
TODO
public void gameEvent(Holder<GameEvent> gameEvent, Vec3 position, GameEvent.Context context) @ L1101
- 方法名:gameEvent
- 源码定位:L1101
- 返回类型:void
- 修饰符:public
参数:
- gameEvent: Holder
- position: Vec3
- context: GameEvent.Context
说明:
TODO
public void sendBlockUpdated(BlockPos pos, BlockState old, BlockState current, int updateFlags) @ L1106
- 方法名:sendBlockUpdated
- 源码定位:L1106
- 返回类型:void
- 修饰符:public
参数:
- pos: BlockPos
- old: BlockState
- current: BlockState
- updateFlags: int
说明:
TODO
public void updateNeighborsAt(BlockPos pos, Block sourceBlock) @ L1139
- 方法名:updateNeighborsAt
- 源码定位:L1139
- 返回类型:void
- 修饰符:public
参数:
- pos: BlockPos
- sourceBlock: Block
说明:
TODO
public void updateNeighborsAt(BlockPos pos, Block sourceBlock, Orientation orientation) @ L1144
- 方法名:updateNeighborsAt
- 源码定位:L1144
- 返回类型:void
- 修饰符:public
参数:
- pos: BlockPos
- sourceBlock: Block
- orientation: Orientation
说明:
TODO
public void updateNeighborsAtExceptFromFacing(BlockPos pos, Block blockObject, Direction skipDirection, Orientation orientation) @ L1149
- 方法名:updateNeighborsAtExceptFromFacing
- 源码定位:L1149
- 返回类型:void
- 修饰符:public
参数:
- pos: BlockPos
- blockObject: Block
- skipDirection: Direction
- orientation: Orientation
说明:
TODO
public void neighborChanged(BlockPos pos, Block changedBlock, Orientation orientation) @ L1154
- 方法名:neighborChanged
- 源码定位:L1154
- 返回类型:void
- 修饰符:public
参数:
- pos: BlockPos
- changedBlock: Block
- orientation: Orientation
说明:
TODO
public void neighborChanged(BlockState state, BlockPos pos, Block changedBlock, Orientation orientation, boolean movedByPiston) @ L1159
- 方法名:neighborChanged
- 源码定位:L1159
- 返回类型:void
- 修饰符:public
参数:
- state: BlockState
- pos: BlockPos
- changedBlock: Block
- orientation: Orientation
- movedByPiston: boolean
说明:
TODO
public void broadcastEntityEvent(Entity entity, byte event) @ L1164
- 方法名:broadcastEntityEvent
- 源码定位:L1164
- 返回类型:void
- 修饰符:public
参数:
- entity: Entity
- event: byte
说明:
TODO
public void broadcastDamageEvent(Entity entity, DamageSource source) @ L1169
- 方法名:broadcastDamageEvent
- 源码定位:L1169
- 返回类型:void
- 修饰符:public
参数:
- entity: Entity
- source: DamageSource
说明:
TODO
public ServerChunkCache getChunkSource() @ L1174
- 方法名:getChunkSource
- 源码定位:L1174
- 返回类型:ServerChunkCache
- 修饰符: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> blockParticles, Holder<SoundEvent> explosionSound) @ L1178
- 方法名:explode
- 源码定位:L1178
- 返回类型: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
- blockParticles: WeightedList
- explosionSound: Holder
说明:
TODO
private Explosion.BlockInteraction getDestroyType(GameRule<Boolean> gameRule) @ L1216
- 方法名:getDestroyType
- 源码定位:L1216
- 返回类型:Explosion.BlockInteraction
- 修饰符:private
参数:
- gameRule: GameRule
说明:
TODO
public void blockEvent(BlockPos pos, Block block, int b0, int b1) @ L1220
- 方法名:blockEvent
- 源码定位:L1220
- 返回类型:void
- 修饰符:public
参数:
- pos: BlockPos
- block: Block
- b0: int
- b1: int
说明:
TODO
private void runBlockEvents() @ L1225
- 方法名:runBlockEvents
- 源码定位:L1225
- 返回类型:void
- 修饰符:private
参数:
- 无
说明:
TODO
private boolean doBlockEvent(BlockEventData eventData) @ L1252
- 方法名:doBlockEvent
- 源码定位:L1252
- 返回类型:boolean
- 修饰符:private
参数:
- eventData: BlockEventData
说明:
TODO
public LevelTicks<Block> getBlockTicks() @ L1257
- 方法名:getBlockTicks
- 源码定位:L1257
- 返回类型:LevelTicks
- 修饰符:public
参数:
- 无
说明:
TODO
public LevelTicks<Fluid> getFluidTicks() @ L1261
- 方法名:getFluidTicks
- 源码定位:L1261
- 返回类型:LevelTicks
- 修饰符:public
参数:
- 无
说明:
TODO
public MinecraftServer getServer() @ L1265
- 方法名:getServer
- 源码定位:L1265
- 返回类型:MinecraftServer
- 修饰符:public
参数:
- 无
说明:
TODO
public PortalForcer getPortalForcer() @ L1270
- 方法名:getPortalForcer
- 源码定位:L1270
- 返回类型:PortalForcer
- 修饰符:public
参数:
- 无
说明:
TODO
public StructureTemplateManager getStructureManager() @ L1274
- 方法名:getStructureManager
- 源码定位:L1274
- 返回类型:StructureTemplateManager
- 修饰符:public
参数:
- 无
说明:
TODO
public <T extends ParticleOptions> int sendParticles(T particle, double x, double y, double z, int count, double xDist, double yDist, double zDist, double speed) @ L1278
- 方法名:sendParticles
- 源码定位:L1278
- 返回类型:
int - 修饰符:public
参数:
- particle: T
- x: double
- y: double
- z: double
- count: int
- xDist: double
- yDist: double
- zDist: double
- speed: double
说明:
TODO
public <T extends ParticleOptions> int sendParticles(T particle, boolean overrideLimiter, boolean alwaysShow, double x, double y, double z, int count, double xDist, double yDist, double zDist, double speed) @ L1284
- 方法名:sendParticles
- 源码定位:L1284
- 返回类型:
int - 修饰符:public
参数:
- particle: T
- overrideLimiter: boolean
- alwaysShow: boolean
- x: double
- y: double
- z: double
- count: int
- xDist: double
- yDist: double
- zDist: double
- speed: double
说明:
TODO
public <T extends ParticleOptions> boolean sendParticles(ServerPlayer player, T particle, boolean overrideLimiter, boolean alwaysShow, double x, double y, double z, int count, double xDist, double yDist, double zDist, double speed) @ L1312
- 方法名:sendParticles
- 源码定位:L1312
- 返回类型:
boolean - 修饰符:public
参数:
- player: ServerPlayer
- particle: T
- overrideLimiter: boolean
- alwaysShow: boolean
- x: double
- y: double
- z: double
- count: int
- xDist: double
- yDist: double
- zDist: double
- speed: double
说明:
TODO
private boolean sendParticles(ServerPlayer player, boolean overrideLimiter, double x, double y, double z, Packet<?> packet) @ L1332
- 方法名:sendParticles
- 源码定位:L1332
- 返回类型:boolean
- 修饰符:private
参数:
- player: ServerPlayer
- overrideLimiter: boolean
- x: double
- y: double
- z: double
- packet: Packet<?>
说明:
TODO
public Entity getEntity(int id) @ L1346
- 方法名:getEntity
- 源码定位:L1346
- 返回类型:Entity
- 修饰符:public
参数:
- id: int
说明:
TODO
public Entity getEntityInAnyDimension(UUID uuid) @ L1351
- 方法名:getEntityInAnyDimension
- 源码定位:L1351
- 返回类型:Entity
- 修饰符:public
参数:
- uuid: UUID
说明:
TODO
public Player getPlayerInAnyDimension(UUID uuid) @ L1370
- 方法名:getPlayerInAnyDimension
- 源码定位:L1370
- 返回类型:Player
- 修饰符:public
参数:
- uuid: UUID
说明:
TODO
public Entity getEntityOrPart(int id) @ L1375
- 方法名:getEntityOrPart
- 源码定位:L1375
- 返回类型:Entity
- 修饰符:public
参数:
- id: int
说明:
TODO
public Collection<EnderDragonPart> dragonParts() @ L1381
- 方法名:dragonParts
- 源码定位:L1381
- 返回类型:Collection
- 修饰符:public
参数:
- 无
说明:
TODO
public BlockPos findNearestMapStructure(TagKey<Structure> structureTag, BlockPos origin, int maxSearchRadius, boolean createReference) @ L1386
- 方法名:findNearestMapStructure
- 源码定位:L1386
- 返回类型:BlockPos
- 修饰符:public
参数:
- structureTag: TagKey
- origin: BlockPos
- maxSearchRadius: int
- createReference: boolean
说明:
TODO
public Pair<BlockPos,Holder<Biome>> findClosestBiome3d(Predicate<Holder<Biome>> biomeTest, BlockPos origin, int maxSearchRadius, int sampleResolutionHorizontal, int sampleResolutionVertical) @ L1402
- 方法名:findClosestBiome3d
- 源码定位:L1402
- 返回类型:Pair<BlockPos,Holder
> - 修饰符:public
参数:
- biomeTest: Predicate<Holder
> - origin: BlockPos
- maxSearchRadius: int
- sampleResolutionHorizontal: int
- sampleResolutionVertical: int
说明:
TODO
public WorldBorder getWorldBorder() @ L1413
- 方法名:getWorldBorder
- 源码定位:L1413
- 返回类型:WorldBorder
- 修饰符:public
参数:
- 无
说明:
TODO
public RecipeManager recipeAccess() @ L1420
- 方法名:recipeAccess
- 源码定位:L1420
- 返回类型:RecipeManager
- 修饰符:public
参数:
- 无
说明:
TODO
public TickRateManager tickRateManager() @ L1424
- 方法名:tickRateManager
- 源码定位:L1424
- 返回类型:TickRateManager
- 修饰符:public
参数:
- 无
说明:
TODO
public boolean noSave() @ L1429
- 方法名:noSave
- 源码定位:L1429
- 返回类型:boolean
- 修饰符:public
参数:
- 无
说明:
TODO
public SavedDataStorage getDataStorage() @ L1434
- 方法名:getDataStorage
- 源码定位:L1434
- 返回类型:SavedDataStorage
- 修饰符:public
参数:
- 无
说明:
TODO
public MapItemSavedData getMapData(MapId id) @ L1438
- 方法名:getMapData
- 源码定位:L1438
- 返回类型:MapItemSavedData
- 修饰符:public
参数:
- id: MapId
说明:
TODO
public void setMapData(MapId id, MapItemSavedData data) @ L1443
- 方法名:setMapData
- 源码定位:L1443
- 返回类型:void
- 修饰符:public
参数:
- id: MapId
- data: MapItemSavedData
说明:
TODO
public MapId getFreeMapId() @ L1447
- 方法名:getFreeMapId
- 源码定位:L1447
- 返回类型:MapId
- 修饰符:public
参数:
- 无
说明:
TODO
public void setRespawnData(LevelData.RespawnData respawnData) @ L1451
- 方法名:setRespawnData
- 源码定位:L1451
- 返回类型:void
- 修饰符:public
参数:
- respawnData: LevelData.RespawnData
说明:
TODO
public LevelData.RespawnData getRespawnData() @ L1456
- 方法名:getRespawnData
- 源码定位:L1456
- 返回类型:LevelData.RespawnData
- 修饰符:public
参数:
- 无
说明:
TODO
public LongSet getForceLoadedChunks() @ L1461
- 方法名:getForceLoadedChunks
- 源码定位:L1461
- 返回类型:LongSet
- 修饰符:public
参数:
- 无
说明:
TODO
public boolean setChunkForced(int chunkX, int chunkZ, boolean forced) @ L1465
- 方法名:setChunkForced
- 源码定位:L1465
- 返回类型:boolean
- 修饰符:public
参数:
- chunkX: int
- chunkZ: int
- forced: boolean
说明:
TODO
public List<ServerPlayer> players() @ L1474
- 方法名:players
- 源码定位:L1474
- 返回类型:List
- 修饰符:public
参数:
- 无
说明:
TODO
public void updatePOIOnBlockStateChange(BlockPos pos, BlockState oldState, BlockState newState) @ L1479
- 方法名:updatePOIOnBlockStateChange
- 源码定位:L1479
- 返回类型:void
- 修饰符:public
参数:
- pos: BlockPos
- oldState: BlockState
- newState: BlockState
说明:
TODO
public PoiManager getPoiManager() @ L1498
- 方法名:getPoiManager
- 源码定位:L1498
- 返回类型:PoiManager
- 修饰符:public
参数:
- 无
说明:
TODO
public boolean isVillage(BlockPos pos) @ L1502
- 方法名:isVillage
- 源码定位:L1502
- 返回类型:boolean
- 修饰符:public
参数:
- pos: BlockPos
说明:
TODO
public boolean isVillage(SectionPos sectionPos) @ L1506
- 方法名:isVillage
- 源码定位:L1506
- 返回类型:boolean
- 修饰符:public
参数:
- sectionPos: SectionPos
说明:
TODO
public boolean isCloseToVillage(BlockPos pos, int sectionDistance) @ L1510
- 方法名:isCloseToVillage
- 源码定位:L1510
- 返回类型:boolean
- 修饰符:public
参数:
- pos: BlockPos
- sectionDistance: int
说明:
TODO
public int sectionsToVillage(SectionPos pos) @ L1514
- 方法名:sectionsToVillage
- 源码定位:L1514
- 返回类型:int
- 修饰符:public
参数:
- pos: SectionPos
说明:
TODO
public Raids getRaids() @ L1518
- 方法名:getRaids
- 源码定位:L1518
- 返回类型:Raids
- 修饰符:public
参数:
- 无
说明:
TODO
public Raid getRaidAt(BlockPos pos) @ L1522
- 方法名:getRaidAt
- 源码定位:L1522
- 返回类型:Raid
- 修饰符:public
参数:
- pos: BlockPos
说明:
TODO
public boolean isRaided(BlockPos pos) @ L1526
- 方法名:isRaided
- 源码定位:L1526
- 返回类型:boolean
- 修饰符:public
参数:
- pos: BlockPos
说明:
TODO
public void onReputationEvent(ReputationEventType type, Entity source, ReputationEventHandler target) @ L1530
- 方法名:onReputationEvent
- 源码定位:L1530
- 返回类型:void
- 修饰符:public
参数:
- type: ReputationEventType
- source: Entity
- target: ReputationEventHandler
说明:
TODO
public void saveDebugReport(Path rootDir) @ L1534
- 方法名:saveDebugReport
- 源码定位:L1534
- 返回类型:void
- 修饰符:public
参数:
- rootDir: Path
说明:
TODO
private static void dumpEntities(Writer output, Iterable<Entity> entities) @ L1586
- 方法名:dumpEntities
- 源码定位:L1586
- 返回类型:void
- 修饰符:private static
参数:
- output: Writer
- entities: Iterable
说明:
TODO
private void dumpBlockEntityTickers(Writer output) @ L1614
- 方法名:dumpBlockEntityTickers
- 源码定位:L1614
- 返回类型:void
- 修饰符:private
参数:
- output: Writer
说明:
TODO
public void clearBlockEvents(BoundingBox bb) @ L1623
- 方法名:clearBlockEvents
- 源码定位:L1623
- 返回类型:void
- 修饰符:public
参数:
- bb: BoundingBox
说明:
TODO
public Iterable<Entity> getAllEntities() @ L1628
- 方法名:getAllEntities
- 源码定位:L1628
- 返回类型:Iterable
- 修饰符:public
参数:
- 无
说明:
TODO
public String toString() @ L1632
- 方法名:toString
- 源码定位:L1632
- 返回类型:String
- 修饰符:public
参数:
- 无
说明:
TODO
public boolean isFlat() @ L1637
- 方法名:isFlat
- 源码定位:L1637
- 返回类型:boolean
- 修饰符:public
参数:
- 无
说明:
TODO
public long getSeed() @ L1641
- 方法名:getSeed
- 源码定位:L1641
- 返回类型:long
- 修饰符:public
参数:
- 无
说明:
TODO
public EnderDragonFight getDragonFight() @ L1646
- 方法名:getDragonFight
- 源码定位:L1646
- 返回类型:EnderDragonFight
- 修饰符:public
参数:
- 无
说明:
TODO
public WeatherData getWeatherData() @ L1650
- 方法名:getWeatherData
- 源码定位:L1650
- 返回类型:WeatherData
- 修饰符:public
参数:
- 无
说明:
TODO
public ServerLevel getLevel() @ L1654
- 方法名:getLevel
- 源码定位:L1654
- 返回类型:ServerLevel
- 修饰符:public
参数:
- 无
说明:
TODO
public String getWatchdogStats() @ L1659
- 方法名:getWatchdogStats
- 源码定位:L1659
- 返回类型:String
- 修饰符:public
参数:
- 无
说明:
TODO
private static <T> String getTypeCount(Iterable<T> values, Function<T,String> typeGetter) @ L1675
- 方法名:getTypeCount
- 源码定位:L1675
- 返回类型:
String - 修饰符:private static
参数:
- values: Iterable
- typeGetter: Function<T,String>
说明:
TODO
protected LevelEntityGetter<Entity> getEntities() @ L1696
- 方法名:getEntities
- 源码定位:L1696
- 返回类型:LevelEntityGetter
- 修饰符:protected
参数:
- 无
说明:
TODO
public void addLegacyChunkEntities(Stream<Entity> loaded) @ L1701
- 方法名:addLegacyChunkEntities
- 源码定位:L1701
- 返回类型:void
- 修饰符:public
参数:
- loaded: Stream
说明:
TODO
public void addWorldGenChunkEntities(Stream<Entity> loaded) @ L1705
- 方法名:addWorldGenChunkEntities
- 源码定位:L1705
- 返回类型:void
- 修饰符:public
参数:
- loaded: Stream
说明:
TODO
public void startTickingChunk(LevelChunk levelChunk) @ L1709
- 方法名:startTickingChunk
- 源码定位:L1709
- 返回类型:void
- 修饰符:public
参数:
- levelChunk: LevelChunk
说明:
TODO
public void onStructureStartsAvailable(ChunkAccess chunk) @ L1713
- 方法名:onStructureStartsAvailable
- 源码定位:L1713
- 返回类型:void
- 修饰符:public
参数:
- chunk: ChunkAccess
说明:
TODO
public PathTypeCache getPathTypeCache() @ L1717
- 方法名:getPathTypeCache
- 源码定位:L1717
- 返回类型:PathTypeCache
- 修饰符:public
参数:
- 无
说明:
TODO
public void waitForEntities(ChunkPos centerChunk, int radius) @ L1721
- 方法名:waitForEntities
- 源码定位:L1721
- 返回类型:void
- 修饰符:public
参数:
- centerChunk: ChunkPos
- radius: int
说明:
TODO
public boolean isSpawningMonsters() @ L1736
- 方法名:isSpawningMonsters
- 源码定位:L1736
- 返回类型:boolean
- 修饰符:public
参数:
- 无
说明:
TODO
public void close() @ L1742
- 方法名:close
- 源码定位:L1742
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
public String gatherChunkSourceStats() @ L1748
- 方法名:gatherChunkSourceStats
- 源码定位:L1748
- 返回类型:String
- 修饰符:public
参数:
- 无
说明:
TODO
public boolean areEntitiesLoaded(long chunkKey) @ L1753
- 方法名:areEntitiesLoaded
- 源码定位:L1753
- 返回类型:boolean
- 修饰符:public
参数:
- chunkKey: long
说明:
TODO
public boolean isPositionTickingWithEntitiesLoaded(long key) @ L1757
- 方法名:isPositionTickingWithEntitiesLoaded
- 源码定位:L1757
- 返回类型:boolean
- 修饰符:public
参数:
- key: long
说明:
TODO
public boolean isPositionEntityTicking(BlockPos pos) @ L1761
- 方法名:isPositionEntityTicking
- 源码定位:L1761
- 返回类型:boolean
- 修饰符:public
参数:
- pos: BlockPos
说明:
TODO
public boolean areEntitiesActuallyLoadedAndTicking(ChunkPos pos) @ L1765
- 方法名:areEntitiesActuallyLoadedAndTicking
- 源码定位:L1765
- 返回类型:boolean
- 修饰符:public
参数:
- pos: ChunkPos
说明:
TODO
public boolean anyPlayerCloseEnoughForSpawning(BlockPos pos) @ L1769
- 方法名:anyPlayerCloseEnoughForSpawning
- 源码定位:L1769
- 返回类型:boolean
- 修饰符:public
参数:
- pos: BlockPos
说明:
TODO
public boolean anyPlayerCloseEnoughForSpawning(ChunkPos pos) @ L1773
- 方法名:anyPlayerCloseEnoughForSpawning
- 源码定位:L1773
- 返回类型:boolean
- 修饰符:public
参数:
- pos: ChunkPos
说明:
TODO
public boolean canSpreadFireAround(BlockPos pos) @ L1777
- 方法名:canSpreadFireAround
- 源码定位:L1777
- 返回类型:boolean
- 修饰符:public
参数:
- pos: BlockPos
说明:
TODO
public boolean canSpawnEntitiesInChunk(ChunkPos pos) @ L1782
- 方法名:canSpawnEntitiesInChunk
- 源码定位:L1782
- 返回类型:boolean
- 修饰符:public
参数:
- pos: ChunkPos
说明:
TODO
public FeatureFlagSet enabledFeatures() @ L1786
- 方法名:enabledFeatures
- 源码定位:L1786
- 返回类型:FeatureFlagSet
- 修饰符:public
参数:
- 无
说明:
TODO
public PotionBrewing potionBrewing() @ L1791
- 方法名:potionBrewing
- 源码定位:L1791
- 返回类型:PotionBrewing
- 修饰符:public
参数:
- 无
说明:
TODO
public FuelValues fuelValues() @ L1796
- 方法名:fuelValues
- 源码定位:L1796
- 返回类型:FuelValues
- 修饰符:public
参数:
- 无
说明:
TODO
public GameRules getGameRules() @ L1801
- 方法名:getGameRules
- 源码定位:L1801
- 返回类型:GameRules
- 修饰符:public
参数:
- 无
说明:
TODO
public CrashReportCategory fillReportDetails(CrashReport report) @ L1805
- 方法名:fillReportDetails
- 源码定位:L1805
- 返回类型:CrashReportCategory
- 修饰符:public
参数:
- report: CrashReport
说明:
TODO
public int getSeaLevel() @ L1824
- 方法名:getSeaLevel
- 源码定位:L1824
- 返回类型:int
- 修饰符:public
参数:
- 无
说明:
TODO
public void onBlockEntityAdded(BlockEntity blockEntity) @ L1829
- 方法名:onBlockEntityAdded
- 源码定位:L1829
- 返回类型:void
- 修饰符:public
参数:
- blockEntity: BlockEntity
说明:
TODO
public LevelDebugSynchronizers debugSynchronizers() @ L1835
- 方法名:debugSynchronizers
- 源码定位:L1835
- 返回类型:LevelDebugSynchronizers
- 修饰符:public
参数:
- 无
说明:
TODO
public boolean isAllowedToEnterPortal(Level toLevel) @ L1839
- 方法名:isAllowedToEnterPortal
- 源码定位:L1839
- 返回类型:boolean
- 修饰符:public
参数:
- toLevel: Level
说明:
TODO
public boolean isPvpAllowed() @ L1843
- 方法名:isPvpAllowed
- 源码定位:L1843
- 返回类型:boolean
- 修饰符:public
参数:
- 无
说明:
TODO
public boolean isCommandBlockEnabled() @ L1847
- 方法名:isCommandBlockEnabled
- 源码定位:L1847
- 返回类型:boolean
- 修饰符:public
参数:
- 无
说明:
TODO
public boolean isSpawnerBlockEnabled() @ L1851
- 方法名:isSpawnerBlockEnabled
- 源码定位:L1851
- 返回类型:boolean
- 修饰符:public
参数:
- 无
说明:
TODO
代码
public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGetter {
public static final BlockPos END_SPAWN_POINT = new BlockPos(100, 50, 0);
public static final IntProvider RAIN_DELAY = UniformInt.of(12000, 180000);
public static final IntProvider RAIN_DURATION = UniformInt.of(12000, 24000);
private static final IntProvider THUNDER_DELAY = UniformInt.of(12000, 180000);
public static final IntProvider THUNDER_DURATION = UniformInt.of(3600, 15600);
private static final Logger LOGGER = LogUtils.getLogger();
private static final int EMPTY_TIME_NO_TICK = 300;
private static final int MAX_SCHEDULED_TICKS_PER_TICK = 65536;
private final List<ServerPlayer> players = Lists.newArrayList();
private final ServerChunkCache chunkSource;
private final MinecraftServer server;
private final ServerLevelData serverLevelData;
private final EntityTickList entityTickList = new EntityTickList();
private final ServerWaypointManager waypointManager;
private EnvironmentAttributeSystem environmentAttributes;
private final PersistentEntitySectionManager<Entity> entityManager;
private final GameEventDispatcher gameEventDispatcher;
public boolean noSave;
private final SleepStatus sleepStatus;
private int emptyTime;
private final PortalForcer portalForcer;
private final LevelTicks<Block> blockTicks = new LevelTicks<>(this::isPositionTickingWithEntitiesLoaded);
private final LevelTicks<Fluid> fluidTicks = new LevelTicks<>(this::isPositionTickingWithEntitiesLoaded);
private final PathTypeCache pathTypesByPosCache = new PathTypeCache();
private final Set<Mob> navigatingMobs = new ObjectOpenHashSet<>();
private volatile boolean isUpdatingNavigations;
protected final Raids raids;
private final ObjectLinkedOpenHashSet<BlockEventData> blockEvents = new ObjectLinkedOpenHashSet<>();
private final List<BlockEventData> blockEventsToReschedule = new ArrayList<>(64);
private boolean handlingTick;
private final List<CustomSpawner> customSpawners;
private @Nullable EnderDragonFight dragonFight;
private final Int2ObjectMap<EnderDragonPart> dragonParts = new Int2ObjectOpenHashMap<>();
private final StructureManager structureManager;
private final StructureCheck structureCheck;
private final boolean tickTime;
private final LevelDebugSynchronizers debugSynchronizers = new LevelDebugSynchronizers(this);
public ServerLevel(
MinecraftServer server,
Executor executor,
LevelStorageSource.LevelStorageAccess levelStorage,
ServerLevelData levelData,
ResourceKey<Level> dimension,
LevelStem levelStem,
boolean isDebug,
long biomeZoomSeed,
List<CustomSpawner> customSpawners,
boolean tickTime
) {
super(levelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates());
this.tickTime = tickTime;
this.server = server;
this.customSpawners = customSpawners;
this.serverLevelData = levelData;
ChunkGenerator generator = levelStem.generator();
boolean syncWrites = server.forceSynchronousWrites();
DataFixer fixerUpper = server.getFixerUpper();
EntityPersistentStorage<Entity> entityStorage = new EntityStorage(
new SimpleRegionStorage(
new RegionStorageInfo(levelStorage.getLevelId(), dimension, "entities"),
levelStorage.getDimensionPath(dimension).resolve("entities"),
fixerUpper,
syncWrites,
DataFixTypes.ENTITY_CHUNK
),
this,
server
);
this.entityManager = new PersistentEntitySectionManager<>(Entity.class, new ServerLevel.EntityCallbacks(), entityStorage);
this.chunkSource = new ServerChunkCache(
this,
levelStorage,
fixerUpper,
server.getStructureManager(),
executor,
generator,
server.getPlayerList().getViewDistance(),
server.getPlayerList().getSimulationDistance(),
syncWrites,
this.entityManager::updateChunkStatus,
() -> server.overworld().getDataStorage()
);
this.chunkSource.getGeneratorState().ensureStructuresGenerated();
this.portalForcer = new PortalForcer(this);
if (this.canHaveWeather()) {
this.prepareWeather(server.getWeatherData());
}
this.raids = this.getDataStorage().computeIfAbsent(Raids.TYPE);
if (!server.isSingleplayer()) {
levelData.setGameType(server.getDefaultGameType());
}
WorldGenSettings worldGenSettings = server.getWorldGenSettings();
WorldOptions options = worldGenSettings.options();
long seed = options.seed();
this.structureCheck = new StructureCheck(
this.chunkSource.chunkScanner(),
this.registryAccess(),
server.getStructureManager(),
dimension,
generator,
this.chunkSource.randomState(),
this,
generator.getBiomeSource(),
seed,
fixerUpper
);
this.structureManager = new StructureManager(this, options, this.structureCheck);
if (this.dimensionType().hasEnderDragonFight()) {
this.dragonFight = this.getDataStorage().computeIfAbsent(EnderDragonFight.TYPE);
this.dragonFight.init(this, seed, BlockPos.ZERO);
}
this.sleepStatus = new SleepStatus();
this.gameEventDispatcher = new GameEventDispatcher(this);
this.waypointManager = new ServerWaypointManager();
this.environmentAttributes = EnvironmentAttributeSystem.builder().addDefaultLayers(this).build();
this.updateSkyBrightness();
}
@Deprecated
@VisibleForTesting
public void setDragonFight(@Nullable EnderDragonFight fight) {
this.dragonFight = fight;
}
@Override
public Holder<Biome> getUncachedNoiseBiome(int quartX, int quartY, int quartZ) {
return this.getChunkSource().getGenerator().getBiomeSource().getNoiseBiome(quartX, quartY, quartZ, this.getChunkSource().randomState().sampler());
}
public StructureManager structureManager() {
return this.structureManager;
}
public ServerClockManager clockManager() {
return this.server.clockManager();
}
@Override
public EnvironmentAttributeSystem environmentAttributes() {
return this.environmentAttributes;
}
@Deprecated
@VisibleForTesting
public EnvironmentAttributeSystem setEnvironmentAttributes(EnvironmentAttributeSystem environmentAttributes) {
EnvironmentAttributeSystem previous = this.environmentAttributes;
this.environmentAttributes = environmentAttributes;
return previous;
}
public void tick(BooleanSupplier haveTime) {
ProfilerFiller profiler = Profiler.get();
this.handlingTick = true;
TickRateManager tickRateManager = this.tickRateManager();
boolean runs = tickRateManager.runsNormally();
if (runs) {
profiler.push("world border");
this.getWorldBorder().tick();
profiler.popPush("weather");
this.advanceWeatherCycle();
profiler.pop();
}
int percentage = this.getGameRules().get(GameRules.PLAYERS_SLEEPING_PERCENTAGE);
if (this.sleepStatus.areEnoughSleeping(percentage) && this.sleepStatus.areEnoughDeepSleeping(percentage, this.players)) {
Optional<Holder<WorldClock>> defaultClock = this.dimensionType().defaultClock();
if (this.getGameRules().get(GameRules.ADVANCE_TIME) && defaultClock.isPresent()) {
this.server.clockManager().moveToTimeMarker(defaultClock.get(), ClockTimeMarkers.WAKE_UP_FROM_SLEEP);
}
this.wakeUpAllPlayers();
if (this.getGameRules().get(GameRules.ADVANCE_WEATHER) && this.isRaining()) {
this.resetWeatherCycle();
}
}
this.updateSkyBrightness();
if (runs) {
this.tickTime();
}
profiler.push("tickPending");
if (!this.isDebug() && runs) {
long tick = this.getGameTime();
profiler.push("blockTicks");
this.blockTicks.tick(tick, 65536, this::tickBlock);
profiler.popPush("fluidTicks");
this.fluidTicks.tick(tick, 65536, this::tickFluid);
profiler.pop();
}
profiler.popPush("raid");
if (runs) {
this.raids.tick(this);
}
profiler.popPush("chunkSource");
this.getChunkSource().tick(haveTime, true);
profiler.popPush("blockEvents");
if (runs) {
this.runBlockEvents();
}
this.handlingTick = false;
profiler.pop();
boolean isActive = this.chunkSource.hasActiveTickets();
if (isActive) {
this.resetEmptyTime();
}
if (runs) {
this.emptyTime++;
}
if (this.emptyTime < 300) {
profiler.push("entities");
if (this.dragonFight != null && runs) {
profiler.push("dragonFight");
this.dragonFight.tick();
profiler.pop();
}
this.entityTickList
.forEach(
entity -> {
if (!entity.isRemoved()) {
if (!tickRateManager.isEntityFrozen(entity)) {
profiler.push("checkDespawn");
entity.checkDespawn();
profiler.pop();
if (entity instanceof ServerPlayer
|| this.chunkSource.chunkMap.getDistanceManager().inEntityTickingRange(entity.chunkPosition().pack())) {
Entity vehicle = entity.getVehicle();
if (vehicle != null) {
if (!vehicle.isRemoved() && vehicle.hasPassenger(entity)) {
return;
}
entity.stopRiding();
}
profiler.push("tick");
this.guardEntityTick(this::tickNonPassenger, entity);
profiler.pop();
}
}
}
}
);
profiler.popPush("blockEntities");
this.tickBlockEntities();
profiler.pop();
}
profiler.push("entityManagement");
this.entityManager.tick();
profiler.pop();
profiler.push("debugSynchronizers");
if (this.debugSynchronizers.hasAnySubscriberFor(DebugSubscriptions.NEIGHBOR_UPDATES)) {
this.neighborUpdater
.setDebugListener(blockPos -> this.debugSynchronizers.broadcastEventToTracking(blockPos, DebugSubscriptions.NEIGHBOR_UPDATES, blockPos));
} else {
this.neighborUpdater.setDebugListener(null);
}
this.debugSynchronizers.tick(this.server.debugSubscribers());
profiler.pop();
this.environmentAttributes().invalidateTickCache();
}
@Override
public boolean shouldTickBlocksAt(long chunkPos) {
return this.chunkSource.chunkMap.getDistanceManager().inBlockTickingRange(chunkPos);
}
protected void tickTime() {
if (this.tickTime) {
long time = this.levelData.getGameTime() + 1L;
this.serverLevelData.setGameTime(time);
Profiler.get().push("scheduledFunctions");
this.server.getScheduledEvents().tick(this.server, time);
Profiler.get().pop();
}
}
public void tickCustomSpawners(boolean spawnEnemies) {
for (CustomSpawner spawner : this.customSpawners) {
spawner.tick(this, spawnEnemies);
}
}
private void wakeUpAllPlayers() {
this.sleepStatus.removeAllSleepers();
this.players.stream().filter(LivingEntity::isSleeping).collect(Collectors.toList()).forEach(player -> player.stopSleepInBed(false, false));
}
public void tickChunk(LevelChunk chunk, int tickSpeed) {
ChunkPos chunkPos = chunk.getPos();
int minX = chunkPos.getMinBlockX();
int minZ = chunkPos.getMinBlockZ();
ProfilerFiller profiler = Profiler.get();
profiler.push("iceandsnow");
for (int i = 0; i < tickSpeed; i++) {
if (this.random.nextInt(48) == 0) {
this.tickPrecipitation(this.getBlockRandomPos(minX, 0, minZ, 15));
}
}
profiler.popPush("tickBlocks");
if (tickSpeed > 0) {
LevelChunkSection[] sections = chunk.getSections();
for (int sectionIndex = 0; sectionIndex < sections.length; sectionIndex++) {
LevelChunkSection section = sections[sectionIndex];
if (section.isRandomlyTicking()) {
int sectionY = chunk.getSectionYFromSectionIndex(sectionIndex);
int minYInSection = SectionPos.sectionToBlockCoord(sectionY);
for (int ix = 0; ix < tickSpeed; ix++) {
BlockPos pos = this.getBlockRandomPos(minX, minYInSection, minZ, 15);
profiler.push("randomTick");
BlockState blockState = section.getBlockState(pos.getX() - minX, pos.getY() - minYInSection, pos.getZ() - minZ);
if (blockState.isRandomlyTicking()) {
blockState.randomTick(this, pos, this.random);
}
FluidState fluidState = blockState.getFluidState();
if (fluidState.isRandomlyTicking()) {
fluidState.randomTick(this, pos, this.random);
}
profiler.pop();
}
}
}
}
profiler.pop();
}
public void tickThunder(LevelChunk chunk) {
ChunkPos chunkPos = chunk.getPos();
boolean raining = this.isRaining();
int minX = chunkPos.getMinBlockX();
int minZ = chunkPos.getMinBlockZ();
ProfilerFiller profiler = Profiler.get();
profiler.push("thunder");
if (raining && this.isThundering() && this.random.nextInt(100000) == 0) {
BlockPos pos = this.findLightningTargetAround(this.getBlockRandomPos(minX, 0, minZ, 15));
if (this.isRainingAt(pos)) {
DifficultyInstance difficulty = this.getCurrentDifficultyAt(pos);
boolean isTrap = this.getGameRules().get(GameRules.SPAWN_MOBS)
&& this.random.nextDouble() < difficulty.getEffectiveDifficulty() * 0.01
&& !this.getBlockState(pos.below()).is(BlockTags.LIGHTNING_RODS);
if (isTrap) {
SkeletonHorse horse = EntityType.SKELETON_HORSE.create(this, EntitySpawnReason.EVENT);
if (horse != null) {
horse.setTrap(true);
horse.setAge(0);
horse.setPos(pos.getX(), pos.getY(), pos.getZ());
this.addFreshEntity(horse);
}
}
LightningBolt bolt = EntityType.LIGHTNING_BOLT.create(this, EntitySpawnReason.EVENT);
if (bolt != null) {
bolt.snapTo(Vec3.atBottomCenterOf(pos));
bolt.setVisualOnly(isTrap);
this.addFreshEntity(bolt);
}
}
}
profiler.pop();
}
@VisibleForTesting
public void tickPrecipitation(BlockPos pos) {
BlockPos topPos = this.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, pos);
BlockPos belowPos = topPos.below();
Biome biome = this.getBiome(topPos).value();
if (biome.shouldFreeze(this, belowPos)) {
this.setBlockAndUpdate(belowPos, Blocks.ICE.defaultBlockState());
}
if (this.isRaining()) {
int maxHeight = this.getGameRules().get(GameRules.MAX_SNOW_ACCUMULATION_HEIGHT);
if (maxHeight > 0 && biome.shouldSnow(this, topPos)) {
BlockState state = this.getBlockState(topPos);
if (state.is(Blocks.SNOW)) {
int currentLayers = state.getValue(SnowLayerBlock.LAYERS);
if (currentLayers < Math.min(maxHeight, 8)) {
BlockState newState = state.setValue(SnowLayerBlock.LAYERS, currentLayers + 1);
Block.pushEntitiesUp(state, newState, this, topPos);
this.setBlockAndUpdate(topPos, newState);
}
} else {
this.setBlockAndUpdate(topPos, Blocks.SNOW.defaultBlockState());
}
}
Biome.Precipitation precipitation = biome.getPrecipitationAt(belowPos, this.getSeaLevel());
if (precipitation != Biome.Precipitation.NONE) {
BlockState belowState = this.getBlockState(belowPos);
belowState.getBlock().handlePrecipitation(belowState, this, belowPos, precipitation);
}
}
}
private Optional<BlockPos> findLightningRod(BlockPos center) {
Optional<BlockPos> nearbyLightningRod = this.getPoiManager()
.findClosest(
p -> p.is(PoiTypes.LIGHTNING_ROD),
lightningRodPos -> lightningRodPos.getY() == this.getHeight(Heightmap.Types.WORLD_SURFACE, lightningRodPos.getX(), lightningRodPos.getZ()) - 1,
center,
128,
PoiManager.Occupancy.ANY
);
return nearbyLightningRod.map(blockPos -> blockPos.above(1));
}
protected BlockPos findLightningTargetAround(BlockPos pos) {
BlockPos center = this.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, pos);
Optional<BlockPos> lightningRodTarget = this.findLightningRod(center);
if (lightningRodTarget.isPresent()) {
return lightningRodTarget.get();
} else {
AABB search = AABB.encapsulatingFullBlocks(center, center.atY(this.getMaxY() + 1)).inflate(3.0);
List<LivingEntity> entities = this.getEntitiesOfClass(LivingEntity.class, search, input -> input.isAlive() && this.canSeeSky(input.blockPosition()));
if (!entities.isEmpty()) {
return entities.get(this.random.nextInt(entities.size())).blockPosition();
} else {
if (center.getY() == this.getMinY() - 1) {
center = center.above(2);
}
return center;
}
}
}
public boolean isHandlingTick() {
return this.handlingTick;
}
public boolean canSleepThroughNights() {
return this.getGameRules().get(GameRules.PLAYERS_SLEEPING_PERCENTAGE) <= 100;
}
private void announceSleepStatus() {
if (this.canSleepThroughNights()) {
if (!this.getServer().isSingleplayer() || this.getServer().isPublished()) {
int percentage = this.getGameRules().get(GameRules.PLAYERS_SLEEPING_PERCENTAGE);
Component message;
if (this.sleepStatus.areEnoughSleeping(percentage)) {
message = Component.translatable("sleep.skipping_night");
} else {
message = Component.translatable("sleep.players_sleeping", this.sleepStatus.amountSleeping(), this.sleepStatus.sleepersNeeded(percentage));
}
for (ServerPlayer player : this.players) {
player.sendOverlayMessage(message);
}
}
}
}
public void updateSleepingPlayerList() {
if (!this.players.isEmpty() && this.sleepStatus.update(this.players)) {
this.announceSleepStatus();
}
}
public ServerScoreboard getScoreboard() {
return this.server.getScoreboard();
}
public ServerWaypointManager getWaypointManager() {
return this.waypointManager;
}
@Override
public DifficultyInstance getCurrentDifficultyAt(BlockPos pos) {
long localTime = 0L;
float moonBrightness = 0.0F;
ChunkAccess chunk = this.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ()), ChunkStatus.FULL, false);
if (chunk != null) {
localTime = chunk.getInhabitedTime();
moonBrightness = this.getMoonBrightness(pos);
}
return new DifficultyInstance(this.getDifficulty(), this.getOverworldClockTime(), localTime, moonBrightness);
}
public float getMoonBrightness(BlockPos pos) {
MoonPhase moonPhase = this.environmentAttributes.getValue(EnvironmentAttributes.MOON_PHASE, pos);
return DimensionType.MOON_BRIGHTNESS_PER_PHASE[moonPhase.index()];
}
private void prepareWeather(WeatherData weatherData) {
if (weatherData.isRaining()) {
this.rainLevel = 1.0F;
if (weatherData.isThundering()) {
this.thunderLevel = 1.0F;
}
}
}
private void advanceWeatherCycle() {
boolean wasRaining = this.isRaining();
if (this.canHaveWeather()) {
WeatherData weatherData = this.getWeatherData();
if (this.getGameRules().get(GameRules.ADVANCE_WEATHER)) {
int clearWeatherTime = weatherData.getClearWeatherTime();
int thunderTime = weatherData.getThunderTime();
int rainTime = weatherData.getRainTime();
boolean thundering = weatherData.isThundering();
boolean raining = weatherData.isRaining();
if (clearWeatherTime > 0) {
clearWeatherTime--;
thunderTime = thundering ? 0 : 1;
rainTime = raining ? 0 : 1;
thundering = false;
raining = false;
} else {
if (thunderTime > 0) {
if (--thunderTime == 0) {
thundering = !thundering;
}
} else if (thundering) {
thunderTime = THUNDER_DURATION.sample(this.random);
} else {
thunderTime = THUNDER_DELAY.sample(this.random);
}
if (rainTime > 0) {
if (--rainTime == 0) {
raining = !raining;
}
} else if (raining) {
rainTime = RAIN_DURATION.sample(this.random);
} else {
rainTime = RAIN_DELAY.sample(this.random);
}
}
weatherData.setThunderTime(thunderTime);
weatherData.setRainTime(rainTime);
weatherData.setClearWeatherTime(clearWeatherTime);
weatherData.setThundering(thundering);
weatherData.setRaining(raining);
}
this.oThunderLevel = this.thunderLevel;
if (weatherData.isThundering()) {
this.thunderLevel += 0.01F;
} else {
this.thunderLevel -= 0.01F;
}
this.thunderLevel = Mth.clamp(this.thunderLevel, 0.0F, 1.0F);
this.oRainLevel = this.rainLevel;
if (weatherData.isRaining()) {
this.rainLevel += 0.01F;
} else {
this.rainLevel -= 0.01F;
}
this.rainLevel = Mth.clamp(this.rainLevel, 0.0F, 1.0F);
}
if (this.oRainLevel != this.rainLevel) {
this.server
.getPlayerList()
.broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.RAIN_LEVEL_CHANGE, this.rainLevel), this.dimension());
}
if (this.oThunderLevel != this.thunderLevel) {
this.server
.getPlayerList()
.broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.THUNDER_LEVEL_CHANGE, this.thunderLevel), this.dimension());
}
if (wasRaining != this.isRaining()) {
if (wasRaining) {
this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.STOP_RAINING, 0.0F));
} else {
this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.START_RAINING, 0.0F));
}
this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.RAIN_LEVEL_CHANGE, this.rainLevel));
this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.THUNDER_LEVEL_CHANGE, this.thunderLevel));
}
}
@VisibleForTesting
public void resetWeatherCycle() {
WeatherData weatherData = this.getWeatherData();
weatherData.setRainTime(0);
weatherData.setRaining(false);
weatherData.setThunderTime(0);
weatherData.setThundering(false);
}
public void resetEmptyTime() {
this.emptyTime = 0;
}
private void tickFluid(BlockPos pos, Fluid type) {
BlockState blockState = this.getBlockState(pos);
FluidState fluidState = blockState.getFluidState();
if (fluidState.is(type)) {
fluidState.tick(this, pos, blockState);
}
}
private void tickBlock(BlockPos pos, Block type) {
BlockState state = this.getBlockState(pos);
if (state.is(type)) {
state.tick(this, pos, this.random);
}
}
public void tickNonPassenger(Entity entity) {
entity.setOldPosAndRot();
ProfilerFiller profiler = Profiler.get();
entity.tickCount++;
profiler.push(entity.typeHolder()::getRegisteredName);
profiler.incrementCounter("tickNonPassenger");
entity.tick();
profiler.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.entityTickList.contains(entity)) {
entity.setOldPosAndRot();
entity.tickCount++;
ProfilerFiller profiler = Profiler.get();
profiler.push(entity.typeHolder()::getRegisteredName);
profiler.incrementCounter("tickPassenger");
entity.rideTick();
profiler.pop();
for (Entity passenger : entity.getPassengers()) {
this.tickPassenger(entity, passenger);
}
}
}
public void updateNeighboursOnBlockSet(BlockPos pos, BlockState oldState) {
BlockState blockState = this.getBlockState(pos);
Block newBlock = blockState.getBlock();
boolean blockChanged = !oldState.is(newBlock);
if (blockChanged) {
oldState.affectNeighborsAfterRemoval(this, pos, false);
}
this.updateNeighborsAt(pos, blockState.getBlock());
if (blockState.hasAnalogOutputSignal()) {
this.updateNeighbourForOutputSignal(pos, newBlock);
}
}
@Override
public boolean mayInteract(Entity entity, BlockPos pos) {
return !(entity instanceof Player player && (this.server.isUnderSpawnProtection(this, pos, player) || !this.getWorldBorder().isWithinBounds(pos)));
}
public void save(@Nullable ProgressListener progressListener, boolean flush, boolean noSave) {
ServerChunkCache chunkSource = this.getChunkSource();
if (!noSave) {
if (progressListener != null) {
progressListener.progressStartNoAbort(Component.translatable("menu.savingLevel"));
}
this.saveLevelData(flush);
if (progressListener != null) {
progressListener.progressStage(Component.translatable("menu.savingChunks"));
}
chunkSource.save(flush);
if (flush) {
this.entityManager.saveAll();
} else {
this.entityManager.autoSave();
}
}
}
private void saveLevelData(boolean sync) {
SavedDataStorage savedDataStorage = this.getChunkSource().getDataStorage();
if (sync) {
savedDataStorage.saveAndJoin();
} else {
savedDataStorage.scheduleSave();
}
}
public <T extends Entity> List<? extends T> getEntities(EntityTypeTest<Entity, T> type, Predicate<? super T> selector) {
List<T> result = Lists.newArrayList();
this.getEntities(type, selector, result);
return result;
}
public <T extends Entity> void getEntities(EntityTypeTest<Entity, T> type, Predicate<? super T> selector, List<? super T> result) {
this.getEntities(type, selector, result, Integer.MAX_VALUE);
}
public <T extends Entity> void getEntities(EntityTypeTest<Entity, T> type, Predicate<? super T> selector, List<? super T> result, int maxResults) {
this.getEntities().get(type, entity -> {
if (selector.test(entity)) {
result.add(entity);
if (result.size() >= maxResults) {
return AbortableIterationConsumer.Continuation.ABORT;
}
}
return AbortableIterationConsumer.Continuation.CONTINUE;
});
}
public List<? extends EnderDragon> getDragons() {
return this.getEntities(EntityType.ENDER_DRAGON, LivingEntity::isAlive);
}
public List<ServerPlayer> getPlayers(Predicate<? super ServerPlayer> selector) {
return this.getPlayers(selector, Integer.MAX_VALUE);
}
public List<ServerPlayer> getPlayers(Predicate<? super ServerPlayer> selector, int maxResults) {
List<ServerPlayer> result = Lists.newArrayList();
for (ServerPlayer player : this.players) {
if (selector.test(player)) {
result.add(player);
if (result.size() >= maxResults) {
return result;
}
}
}
return result;
}
public @Nullable ServerPlayer getRandomPlayer() {
List<ServerPlayer> players = this.getPlayers(LivingEntity::isAlive);
return players.isEmpty() ? null : players.get(this.random.nextInt(players.size()));
}
@Override
public boolean addFreshEntity(Entity entity) {
return this.addEntity(entity);
}
public boolean addWithUUID(Entity entity) {
return this.addEntity(entity);
}
public void addDuringTeleport(Entity entity) {
if (entity instanceof ServerPlayer player) {
this.addPlayer(player);
} else {
this.addEntity(entity);
}
}
public void addNewPlayer(ServerPlayer player) {
this.addPlayer(player);
}
public void addRespawnedPlayer(ServerPlayer player) {
this.addPlayer(player);
}
private void addPlayer(ServerPlayer player) {
Entity existing = this.getEntity(player.getUUID());
if (existing != null) {
LOGGER.warn("Force-added player with duplicate UUID {}", player.getUUID());
existing.unRide();
this.removePlayerImmediately((ServerPlayer)existing, Entity.RemovalReason.DISCARDED);
}
this.entityManager.addNewEntity(player);
}
private boolean addEntity(Entity entity) {
if (entity.isRemoved()) {
LOGGER.warn("Tried to add entity {} but it was marked as removed already", entity.typeHolder().getRegisteredName());
return false;
} else {
return this.entityManager.addNewEntity(entity);
}
}
public boolean tryAddFreshEntityWithPassengers(Entity entity) {
if (entity.getSelfAndPassengers().map(Entity::getUUID).anyMatch(this.entityManager::isLoaded)) {
return false;
} else {
this.addFreshEntityWithPassengers(entity);
return true;
}
}
public void unload(LevelChunk levelChunk) {
levelChunk.clearAllBlockEntities();
levelChunk.unregisterTickContainerFromLevel(this);
this.debugSynchronizers.dropChunk(levelChunk.getPos());
}
public void removePlayerImmediately(ServerPlayer player, Entity.RemovalReason reason) {
player.remove(reason);
}
@Override
public void destroyBlockProgress(int id, BlockPos blockPos, int progress) {
for (ServerPlayer player : this.server.getPlayerList().getPlayers()) {
if (player.level() == this && player.getId() != id) {
double xd = blockPos.getX() - player.getX();
double yd = blockPos.getY() - player.getY();
double zd = blockPos.getZ() - player.getZ();
if (xd * xd + yd * yd + zd * zd < 1024.0) {
player.connection.send(new ClientboundBlockDestructionPacket(id, blockPos, progress));
}
}
}
}
@Override
public void playSeededSound(
@Nullable Entity except, double x, double y, double z, Holder<SoundEvent> sound, SoundSource source, float volume, float pitch, long seed
) {
this.server
.getPlayerList()
.broadcast(
except instanceof Player player ? player : null,
x,
y,
z,
sound.value().getRange(volume),
this.dimension(),
new ClientboundSoundPacket(sound, source, x, y, z, volume, pitch, seed)
);
}
@Override
public void playSeededSound(
@Nullable Entity except, Entity sourceEntity, Holder<SoundEvent> sound, SoundSource source, float volume, float pitch, long seed
) {
this.server
.getPlayerList()
.broadcast(
except instanceof Player player ? player : null,
sourceEntity.getX(),
sourceEntity.getY(),
sourceEntity.getZ(),
sound.value().getRange(volume),
this.dimension(),
new ClientboundSoundEntityPacket(sound, source, sourceEntity, volume, pitch, seed)
);
}
@Override
public void globalLevelEvent(int type, BlockPos pos, int data) {
if (this.getGameRules().get(GameRules.GLOBAL_SOUND_EVENTS)) {
this.server.getPlayerList().getPlayers().forEach(player -> {
Vec3 soundPos;
if (player.level() == this) {
Vec3 centerOfBlock = Vec3.atCenterOf(pos);
if (player.distanceToSqr(centerOfBlock) < Mth.square(32)) {
soundPos = centerOfBlock;
} else {
Vec3 directionToEvent = centerOfBlock.subtract(player.position()).normalize();
soundPos = player.position().add(directionToEvent.scale(32.0));
}
} else {
soundPos = player.position();
}
player.connection.send(new ClientboundLevelEventPacket(type, BlockPos.containing(soundPos), data, true));
});
} else {
this.levelEvent(null, type, pos, data);
}
}
@Override
public void levelEvent(@Nullable Entity source, int type, BlockPos pos, int data) {
this.server
.getPlayerList()
.broadcast(
source instanceof Player player ? player : null,
pos.getX(),
pos.getY(),
pos.getZ(),
64.0,
this.dimension(),
new ClientboundLevelEventPacket(type, pos, data, false)
);
}
public int getLogicalHeight() {
return this.dimensionType().logicalHeight();
}
@Override
public void gameEvent(Holder<GameEvent> gameEvent, Vec3 position, GameEvent.Context context) {
this.gameEventDispatcher.post(gameEvent, position, context);
}
@Override
public void sendBlockUpdated(BlockPos pos, BlockState old, BlockState current, int updateFlags) {
if (this.isUpdatingNavigations) {
String message = "recursive call to sendBlockUpdated";
Util.logAndPauseIfInIde("recursive call to sendBlockUpdated", new IllegalStateException("recursive call to sendBlockUpdated"));
}
this.getChunkSource().blockChanged(pos);
this.pathTypesByPosCache.invalidate(pos);
VoxelShape oldShape = old.getCollisionShape(this, pos);
VoxelShape newShape = current.getCollisionShape(this, pos);
if (Shapes.joinIsNotEmpty(oldShape, newShape, BooleanOp.NOT_SAME)) {
List<PathNavigation> navigationsToUpdate = new ObjectArrayList<>();
for (Mob navigatingMob : this.navigatingMobs) {
PathNavigation pathNavigation = navigatingMob.getNavigation();
if (pathNavigation.shouldRecomputePath(pos)) {
navigationsToUpdate.add(pathNavigation);
}
}
try {
this.isUpdatingNavigations = true;
for (PathNavigation navigation : navigationsToUpdate) {
navigation.recomputePath();
}
} finally {
this.isUpdatingNavigations = false;
}
}
}
@Override
public void updateNeighborsAt(BlockPos pos, Block sourceBlock) {
this.updateNeighborsAt(pos, sourceBlock, ExperimentalRedstoneUtils.initialOrientation(this, null, null));
}
@Override
public void updateNeighborsAt(BlockPos pos, Block sourceBlock, @Nullable Orientation orientation) {
this.neighborUpdater.updateNeighborsAtExceptFromFacing(pos, sourceBlock, null, orientation);
}
@Override
public void updateNeighborsAtExceptFromFacing(BlockPos pos, Block blockObject, Direction skipDirection, @Nullable Orientation orientation) {
this.neighborUpdater.updateNeighborsAtExceptFromFacing(pos, blockObject, skipDirection, orientation);
}
@Override
public void neighborChanged(BlockPos pos, Block changedBlock, @Nullable Orientation orientation) {
this.neighborUpdater.neighborChanged(pos, changedBlock, orientation);
}
@Override
public void neighborChanged(BlockState state, BlockPos pos, Block changedBlock, @Nullable Orientation orientation, boolean movedByPiston) {
this.neighborUpdater.neighborChanged(state, pos, changedBlock, orientation, movedByPiston);
}
@Override
public void broadcastEntityEvent(Entity entity, byte event) {
this.getChunkSource().sendToTrackingPlayersAndSelf(entity, new ClientboundEntityEventPacket(entity, event));
}
@Override
public void broadcastDamageEvent(Entity entity, DamageSource source) {
this.getChunkSource().sendToTrackingPlayersAndSelf(entity, new ClientboundDamageEventPacket(entity, source));
}
public ServerChunkCache getChunkSource() {
return this.chunkSource;
}
@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> blockParticles,
Holder<SoundEvent> explosionSound
) {
Explosion.BlockInteraction blockInteraction = switch (interactionType) {
case NONE -> Explosion.BlockInteraction.KEEP;
case BLOCK -> this.getDestroyType(GameRules.BLOCK_EXPLOSION_DROP_DECAY);
case MOB -> this.getGameRules().get(GameRules.MOB_GRIEFING)
? this.getDestroyType(GameRules.MOB_EXPLOSION_DROP_DECAY)
: Explosion.BlockInteraction.KEEP;
case TNT -> this.getDestroyType(GameRules.TNT_EXPLOSION_DROP_DECAY);
case TRIGGER -> Explosion.BlockInteraction.TRIGGER_BLOCK;
};
Vec3 center = new Vec3(x, y, z);
ServerExplosion explosion = new ServerExplosion(this, source, damageSource, damageCalculator, center, r, fire, blockInteraction);
int blockCount = explosion.explode();
ParticleOptions explosionParticle = explosion.isSmall() ? smallExplosionParticles : largeExplosionParticles;
for (ServerPlayer player : this.players) {
if (player.distanceToSqr(center) < 4096.0) {
Optional<Vec3> playerKnockback = Optional.ofNullable(explosion.getHitPlayers().get(player));
player.connection.send(new ClientboundExplodePacket(center, r, blockCount, playerKnockback, explosionParticle, explosionSound, blockParticles));
}
}
}
private Explosion.BlockInteraction getDestroyType(GameRule<Boolean> gameRule) {
return this.getGameRules().get(gameRule) ? Explosion.BlockInteraction.DESTROY_WITH_DECAY : Explosion.BlockInteraction.DESTROY;
}
@Override
public void blockEvent(BlockPos pos, Block block, int b0, int b1) {
this.blockEvents.add(new BlockEventData(pos, block, b0, b1));
}
private void runBlockEvents() {
this.blockEventsToReschedule.clear();
while (!this.blockEvents.isEmpty()) {
BlockEventData eventData = this.blockEvents.removeFirst();
if (this.shouldTickBlocksAt(eventData.pos())) {
if (this.doBlockEvent(eventData)) {
this.server
.getPlayerList()
.broadcast(
null,
eventData.pos().getX(),
eventData.pos().getY(),
eventData.pos().getZ(),
64.0,
this.dimension(),
new ClientboundBlockEventPacket(eventData.pos(), eventData.block(), eventData.paramA(), eventData.paramB())
);
}
} else {
this.blockEventsToReschedule.add(eventData);
}
}
this.blockEvents.addAll(this.blockEventsToReschedule);
}
private boolean doBlockEvent(BlockEventData eventData) {
BlockState state = this.getBlockState(eventData.pos());
return state.is(eventData.block()) ? state.triggerEvent(this, eventData.pos(), eventData.paramA(), eventData.paramB()) : false;
}
public LevelTicks<Block> getBlockTicks() {
return this.blockTicks;
}
public LevelTicks<Fluid> getFluidTicks() {
return this.fluidTicks;
}
@Override
public MinecraftServer getServer() {
return this.server;
}
public PortalForcer getPortalForcer() {
return this.portalForcer;
}
public StructureTemplateManager getStructureManager() {
return this.server.getStructureManager();
}
public <T extends ParticleOptions> int sendParticles(
T particle, double x, double y, double z, int count, double xDist, double yDist, double zDist, double speed
) {
return this.sendParticles(particle, false, false, x, y, z, count, xDist, yDist, zDist, speed);
}
public <T extends ParticleOptions> int sendParticles(
T particle,
boolean overrideLimiter,
boolean alwaysShow,
double x,
double y,
double z,
int count,
double xDist,
double yDist,
double zDist,
double speed
) {
ClientboundLevelParticlesPacket packet = new ClientboundLevelParticlesPacket(
particle, overrideLimiter, alwaysShow, x, y, z, (float)xDist, (float)yDist, (float)zDist, (float)speed, count
);
int result = 0;
for (int i = 0; i < this.players.size(); i++) {
ServerPlayer player = this.players.get(i);
if (this.sendParticles(player, overrideLimiter, x, y, z, packet)) {
result++;
}
}
return result;
}
public <T extends ParticleOptions> boolean sendParticles(
ServerPlayer player,
T particle,
boolean overrideLimiter,
boolean alwaysShow,
double x,
double y,
double z,
int count,
double xDist,
double yDist,
double zDist,
double speed
) {
Packet<?> packet = new ClientboundLevelParticlesPacket(
particle, overrideLimiter, alwaysShow, x, y, z, (float)xDist, (float)yDist, (float)zDist, (float)speed, count
);
return this.sendParticles(player, overrideLimiter, x, y, z, packet);
}
private boolean sendParticles(ServerPlayer player, boolean overrideLimiter, double x, double y, double z, Packet<?> packet) {
if (player.level() != this) {
return false;
} else {
BlockPos pos = player.blockPosition();
if (pos.closerToCenterThan(new Vec3(x, y, z), overrideLimiter ? 512.0 : 32.0)) {
player.connection.send(packet);
return true;
} else {
return false;
}
}
}
@Override
public @Nullable Entity getEntity(int id) {
return this.getEntities().get(id);
}
@Override
public @Nullable Entity getEntityInAnyDimension(UUID uuid) {
Entity entity = this.getEntity(uuid);
if (entity != null) {
return entity;
} else {
for (ServerLevel otherLevel : this.getServer().getAllLevels()) {
if (otherLevel != this) {
Entity otherEntity = otherLevel.getEntity(uuid);
if (otherEntity != null) {
return otherEntity;
}
}
}
return null;
}
}
@Override
public @Nullable Player getPlayerInAnyDimension(UUID uuid) {
return this.getServer().getPlayerList().getPlayer(uuid);
}
@Deprecated
public @Nullable Entity getEntityOrPart(int id) {
Entity entity = this.getEntities().get(id);
return entity != null ? entity : this.dragonParts.get(id);
}
@Override
public Collection<EnderDragonPart> dragonParts() {
return this.dragonParts.values();
}
public @Nullable BlockPos findNearestMapStructure(TagKey<Structure> structureTag, BlockPos origin, int maxSearchRadius, boolean createReference) {
if (!this.server.getWorldGenSettings().options().generateStructures()) {
return null;
} else {
Optional<HolderSet.Named<Structure>> tag = this.registryAccess().lookupOrThrow(Registries.STRUCTURE).get(structureTag);
if (tag.isEmpty()) {
return null;
} else {
Pair<BlockPos, Holder<Structure>> result = this.getChunkSource()
.getGenerator()
.findNearestMapStructure(this, tag.get(), origin, maxSearchRadius, createReference);
return result != null ? result.getFirst() : null;
}
}
}
public @Nullable Pair<BlockPos, Holder<Biome>> findClosestBiome3d(
Predicate<Holder<Biome>> biomeTest, BlockPos origin, int maxSearchRadius, int sampleResolutionHorizontal, int sampleResolutionVertical
) {
return this.getChunkSource()
.getGenerator()
.getBiomeSource()
.findClosestBiome3d(
origin, maxSearchRadius, sampleResolutionHorizontal, sampleResolutionVertical, biomeTest, this.getChunkSource().randomState().sampler(), this
);
}
@Override
public WorldBorder getWorldBorder() {
WorldBorder worldBorder = this.getDataStorage().computeIfAbsent(WorldBorder.TYPE);
worldBorder.applyInitialSettings(this.levelData.getGameTime());
return worldBorder;
}
public RecipeManager recipeAccess() {
return this.server.getRecipeManager();
}
@Override
public TickRateManager tickRateManager() {
return this.server.tickRateManager();
}
@Override
public boolean noSave() {
return this.noSave;
}
public SavedDataStorage getDataStorage() {
return this.getChunkSource().getDataStorage();
}
@Override
public @Nullable MapItemSavedData getMapData(MapId id) {
return this.getServer().getDataStorage().get(MapItemSavedData.type(id));
}
public void setMapData(MapId id, MapItemSavedData data) {
this.getServer().getDataStorage().set(MapItemSavedData.type(id), data);
}
public MapId getFreeMapId() {
return this.getServer().getDataStorage().computeIfAbsent(MapIndex.TYPE).getNextMapId();
}
@Override
public void setRespawnData(LevelData.RespawnData respawnData) {
this.getServer().setRespawnData(respawnData);
}
@Override
public LevelData.RespawnData getRespawnData() {
return this.getServer().getRespawnData();
}
public LongSet getForceLoadedChunks() {
return this.chunkSource.getForceLoadedChunks();
}
public boolean setChunkForced(int chunkX, int chunkZ, boolean forced) {
boolean updated = this.chunkSource.updateChunkForced(new ChunkPos(chunkX, chunkZ), forced);
if (forced && updated) {
this.getChunk(chunkX, chunkZ);
}
return updated;
}
@Override
public List<ServerPlayer> players() {
return this.players;
}
@Override
public void updatePOIOnBlockStateChange(BlockPos pos, BlockState oldState, BlockState newState) {
Optional<Holder<PoiType>> oldType = PoiTypes.forState(oldState);
Optional<Holder<PoiType>> newType = PoiTypes.forState(newState);
if (!Objects.equals(oldType, newType)) {
BlockPos immutable = pos.immutable();
oldType.ifPresent(poiType -> this.getServer().execute(() -> {
this.getPoiManager().remove(immutable);
this.debugSynchronizers.dropPoi(immutable);
}));
newType.ifPresent(poiType -> this.getServer().execute(() -> {
PoiRecord record = this.getPoiManager().add(immutable, (Holder<PoiType>)poiType);
if (record != null) {
this.debugSynchronizers.registerPoi(record);
}
}));
}
}
public PoiManager getPoiManager() {
return this.getChunkSource().getPoiManager();
}
public boolean isVillage(BlockPos pos) {
return this.isCloseToVillage(pos, 1);
}
public boolean isVillage(SectionPos sectionPos) {
return this.isVillage(sectionPos.center());
}
public boolean isCloseToVillage(BlockPos pos, int sectionDistance) {
return sectionDistance > 6 ? false : this.sectionsToVillage(SectionPos.of(pos)) <= sectionDistance;
}
public int sectionsToVillage(SectionPos pos) {
return this.getPoiManager().sectionsToVillage(pos);
}
public Raids getRaids() {
return this.raids;
}
public @Nullable Raid getRaidAt(BlockPos pos) {
return this.raids.getNearbyRaid(pos, 9216);
}
public boolean isRaided(BlockPos pos) {
return this.getRaidAt(pos) != null;
}
public void onReputationEvent(ReputationEventType type, Entity source, ReputationEventHandler target) {
target.onReputationEventFrom(type, source);
}
public void saveDebugReport(Path rootDir) throws IOException {
ChunkMap chunkMap = this.getChunkSource().chunkMap;
try (Writer output = Files.newBufferedWriter(rootDir.resolve("stats.txt"))) {
output.write(String.format(Locale.ROOT, "spawning_chunks: %d\n", chunkMap.getDistanceManager().getNaturalSpawnChunkCount()));
NaturalSpawner.SpawnState lastSpawnState = this.getChunkSource().getLastSpawnState();
if (lastSpawnState != null) {
for (Entry<MobCategory> entry : lastSpawnState.getMobCategoryCounts().object2IntEntrySet()) {
output.write(String.format(Locale.ROOT, "spawn_count.%s: %d\n", entry.getKey().getName(), entry.getIntValue()));
}
}
output.write(String.format(Locale.ROOT, "entities: %s\n", this.entityManager.gatherStats()));
output.write(String.format(Locale.ROOT, "block_entity_tickers: %d\n", this.blockEntityTickers.size()));
output.write(String.format(Locale.ROOT, "block_ticks: %d\n", this.getBlockTicks().count()));
output.write(String.format(Locale.ROOT, "fluid_ticks: %d\n", this.getFluidTicks().count()));
output.write("distance_manager: " + chunkMap.getDistanceManager().getDebugStatus() + "\n");
output.write(String.format(Locale.ROOT, "pending_tasks: %d\n", this.getChunkSource().getPendingTasksCount()));
}
CrashReport test = new CrashReport("Level dump", new Exception("dummy"));
this.fillReportDetails(test);
try (Writer output = Files.newBufferedWriter(rootDir.resolve("example_crash.txt"))) {
output.write(test.getFriendlyReport(ReportType.TEST));
}
Path chunks = rootDir.resolve("chunks.csv");
try (Writer output = Files.newBufferedWriter(chunks)) {
chunkMap.dumpChunks(output);
}
Path entityChunks = rootDir.resolve("entity_chunks.csv");
try (Writer output = Files.newBufferedWriter(entityChunks)) {
this.entityManager.dumpSections(output);
}
Path entities = rootDir.resolve("entities.csv");
try (Writer output = Files.newBufferedWriter(entities)) {
dumpEntities(output, this.getEntities().getAll());
}
Path blockEntities = rootDir.resolve("block_entities.csv");
try (Writer output = Files.newBufferedWriter(blockEntities)) {
this.dumpBlockEntityTickers(output);
}
}
private static void dumpEntities(Writer output, Iterable<Entity> entities) throws IOException {
CsvOutput csvOutput = CsvOutput.builder()
.addColumn("x")
.addColumn("y")
.addColumn("z")
.addColumn("uuid")
.addColumn("type")
.addColumn("alive")
.addColumn("display_name")
.addColumn("custom_name")
.build(output);
for (Entity entity : entities) {
Component customName = entity.getCustomName();
Component displayName = entity.getDisplayName();
csvOutput.writeRow(
entity.getX(),
entity.getY(),
entity.getZ(),
entity.getUUID(),
entity.typeHolder().getRegisteredName(),
entity.isAlive(),
displayName.getString(),
customName != null ? customName.getString() : null
);
}
}
private void dumpBlockEntityTickers(Writer output) throws IOException {
CsvOutput csvOutput = CsvOutput.builder().addColumn("x").addColumn("y").addColumn("z").addColumn("type").build(output);
for (TickingBlockEntity ticker : this.blockEntityTickers) {
BlockPos blockPos = ticker.getPos();
csvOutput.writeRow(blockPos.getX(), blockPos.getY(), blockPos.getZ(), ticker.getType());
}
}
@VisibleForTesting
public void clearBlockEvents(BoundingBox bb) {
this.blockEvents.removeIf(e -> bb.isInside(e.pos()));
}
public Iterable<Entity> getAllEntities() {
return this.getEntities().getAll();
}
@Override
public String toString() {
return "ServerLevel[" + this.serverLevelData.getLevelName() + "]";
}
public boolean isFlat() {
return this.server.getWorldData().isFlatWorld();
}
@Override
public long getSeed() {
return this.server.getWorldGenSettings().options().seed();
}
public @Nullable EnderDragonFight getDragonFight() {
return this.dragonFight;
}
public WeatherData getWeatherData() {
return this.server.getWeatherData();
}
@Override
public ServerLevel getLevel() {
return this;
}
@VisibleForTesting
public String getWatchdogStats() {
return String.format(
Locale.ROOT,
"players: %s, entities: %s [%s], block_entities: %d [%s], block_ticks: %d, fluid_ticks: %d, chunk_source: %s",
this.players.size(),
this.entityManager.gatherStats(),
getTypeCount(this.entityManager.getEntityGetter().getAll(), e -> e.typeHolder().getRegisteredName()),
this.blockEntityTickers.size(),
getTypeCount(this.blockEntityTickers, TickingBlockEntity::getType),
this.getBlockTicks().count(),
this.getFluidTicks().count(),
this.gatherChunkSourceStats()
);
}
private static <T> String getTypeCount(Iterable<T> values, Function<T, String> typeGetter) {
try {
Object2IntOpenHashMap<String> countByType = new Object2IntOpenHashMap<>();
for (T e : values) {
String type = typeGetter.apply(e);
countByType.addTo(type, 1);
}
Comparator<Entry<String>> compareByCount = Comparator.comparingInt(Entry::getIntValue);
return countByType.object2IntEntrySet()
.stream()
.sorted(compareByCount.reversed())
.limit(5L)
.map(ex -> (String)ex.getKey() + ":" + ex.getIntValue())
.collect(Collectors.joining(","));
} catch (Exception var6) {
return "";
}
}
@Override
protected LevelEntityGetter<Entity> getEntities() {
return this.entityManager.getEntityGetter();
}
public void addLegacyChunkEntities(Stream<Entity> loaded) {
this.entityManager.addLegacyChunkEntities(loaded);
}
public void addWorldGenChunkEntities(Stream<Entity> loaded) {
this.entityManager.addWorldGenChunkEntities(loaded);
}
public void startTickingChunk(LevelChunk levelChunk) {
levelChunk.unpackTicks(this.getGameTime());
}
public void onStructureStartsAvailable(ChunkAccess chunk) {
this.server.execute(() -> this.structureCheck.onStructureLoad(chunk.getPos(), chunk.getAllStarts()));
}
public PathTypeCache getPathTypeCache() {
return this.pathTypesByPosCache;
}
public void waitForEntities(ChunkPos centerChunk, int radius) {
List<ChunkPos> chunks = ChunkPos.rangeClosed(centerChunk, radius).toList();
this.server.managedBlock(() -> {
this.entityManager.processPendingLoads();
for (ChunkPos chunk : chunks) {
if (!this.areEntitiesLoaded(chunk.pack())) {
return false;
}
}
return true;
});
}
public boolean isSpawningMonsters() {
return this.getLevelData().getDifficulty() != Difficulty.PEACEFUL
&& this.getGameRules().get(GameRules.SPAWN_MOBS)
&& this.getGameRules().get(GameRules.SPAWN_MONSTERS);
}
@Override
public void close() throws IOException {
super.close();
this.entityManager.close();
}
@Override
public String gatherChunkSourceStats() {
return "Chunks[S] W: " + this.chunkSource.gatherStats() + " E: " + this.entityManager.gatherStats();
}
public boolean areEntitiesLoaded(long chunkKey) {
return this.entityManager.areEntitiesLoaded(chunkKey);
}
public boolean isPositionTickingWithEntitiesLoaded(long key) {
return this.areEntitiesLoaded(key) && this.chunkSource.isPositionTicking(key);
}
public boolean isPositionEntityTicking(BlockPos pos) {
return this.entityManager.canPositionTick(pos) && this.chunkSource.chunkMap.getDistanceManager().inEntityTickingRange(ChunkPos.pack(pos));
}
public boolean areEntitiesActuallyLoadedAndTicking(ChunkPos pos) {
return this.entityManager.isTicking(pos) && this.entityManager.areEntitiesLoaded(pos.pack());
}
public boolean anyPlayerCloseEnoughForSpawning(BlockPos pos) {
return this.anyPlayerCloseEnoughForSpawning(ChunkPos.containing(pos));
}
public boolean anyPlayerCloseEnoughForSpawning(ChunkPos pos) {
return this.chunkSource.chunkMap.anyPlayerCloseEnoughForSpawning(pos);
}
public boolean canSpreadFireAround(BlockPos pos) {
int spreadRadius = this.getGameRules().get(GameRules.FIRE_SPREAD_RADIUS_AROUND_PLAYER);
return spreadRadius == -1 || this.chunkSource.chunkMap.anyPlayerCloseEnoughTo(pos, spreadRadius);
}
public boolean canSpawnEntitiesInChunk(ChunkPos pos) {
return this.entityManager.canPositionTick(pos) && this.getWorldBorder().isWithinBounds(pos);
}
@Override
public FeatureFlagSet enabledFeatures() {
return this.server.getWorldData().enabledFeatures();
}
@Override
public PotionBrewing potionBrewing() {
return this.server.potionBrewing();
}
@Override
public FuelValues fuelValues() {
return this.server.fuelValues();
}
public GameRules getGameRules() {
return this.server.getGameRules();
}
@Override
public CrashReportCategory fillReportDetails(CrashReport report) {
CrashReportCategory category = super.fillReportDetails(report);
WeatherData weatherData = this.getWeatherData();
category.setDetail("Loaded entity count", () -> String.valueOf(this.entityManager.count()));
category.setDetail(
"Server weather",
() -> String.format(
Locale.ROOT,
"Rain time: %d (now: %b), thunder time: %d (now: %b)",
weatherData.getRainTime(),
this.isRaining(),
weatherData.getThunderTime(),
this.isThundering()
)
);
return category;
}
@Override
public int getSeaLevel() {
return this.chunkSource.getGenerator().getSeaLevel();
}
@Override
public void onBlockEntityAdded(BlockEntity blockEntity) {
super.onBlockEntityAdded(blockEntity);
this.debugSynchronizers.registerBlockEntity(blockEntity);
}
public LevelDebugSynchronizers debugSynchronizers() {
return this.debugSynchronizers;
}
public boolean isAllowedToEnterPortal(Level toLevel) {
return toLevel.dimension() == Level.NETHER ? this.getGameRules().get(GameRules.ALLOW_ENTERING_NETHER_USING_PORTALS) : true;
}
public boolean isPvpAllowed() {
return this.getGameRules().get(GameRules.PVP);
}
public boolean isCommandBlockEnabled() {
return this.getGameRules().get(GameRules.COMMAND_BLOCKS_WORK);
}
public boolean isSpawnerBlockEnabled() {
return this.getGameRules().get(GameRules.SPAWNER_BLOCKS_WORK);
}
private final class EntityCallbacks implements LevelCallback<Entity> {
private EntityCallbacks() {
Objects.requireNonNull(ServerLevel.this);
super();
}
public void onCreated(Entity entity) {
if (entity instanceof WaypointTransmitter waypoint && waypoint.isTransmittingWaypoint()) {
ServerLevel.this.getWaypointManager().trackWaypoint(waypoint);
}
}
public void onDestroyed(Entity entity) {
if (entity instanceof WaypointTransmitter waypoint) {
ServerLevel.this.getWaypointManager().untrackWaypoint(waypoint);
}
ServerLevel.this.getScoreboard().entityRemoved(entity);
}
public void onTickingStart(Entity entity) {
ServerLevel.this.entityTickList.add(entity);
}
public void onTickingEnd(Entity entity) {
ServerLevel.this.entityTickList.remove(entity);
}
public void onTrackingStart(Entity entity) {
ServerLevel.this.getChunkSource().addEntity(entity);
if (entity instanceof ServerPlayer player) {
ServerLevel.this.players.add(player);
if (player.isReceivingWaypoints()) {
ServerLevel.this.getWaypointManager().addPlayer(player);
}
ServerLevel.this.updateSleepingPlayerList();
}
if (entity instanceof WaypointTransmitter waypoint && waypoint.isTransmittingWaypoint()) {
ServerLevel.this.getWaypointManager().trackWaypoint(waypoint);
}
if (entity instanceof Mob mob) {
if (ServerLevel.this.isUpdatingNavigations) {
String message = "onTrackingStart called during navigation iteration";
Util.logAndPauseIfInIde(
"onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration")
);
}
ServerLevel.this.navigatingMobs.add(mob);
}
if (entity instanceof EnderDragon dragon) {
for (EnderDragonPart subEntity : dragon.getSubEntities()) {
ServerLevel.this.dragonParts.put(subEntity.getId(), subEntity);
}
}
entity.updateDynamicGameEventListener(DynamicGameEventListener::add);
}
public void onTrackingEnd(Entity entity) {
ServerLevel.this.getChunkSource().removeEntity(entity);
if (entity instanceof ServerPlayer player) {
ServerLevel.this.players.remove(player);
ServerLevel.this.getWaypointManager().removePlayer(player);
ServerLevel.this.updateSleepingPlayerList();
}
if (entity instanceof Mob mob) {
if (ServerLevel.this.isUpdatingNavigations) {
String message = "onTrackingStart called during navigation iteration";
Util.logAndPauseIfInIde(
"onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration")
);
}
ServerLevel.this.navigatingMobs.remove(mob);
}
if (entity instanceof EnderDragon dragon) {
for (EnderDragonPart subEntity : dragon.getSubEntities()) {
ServerLevel.this.dragonParts.remove(subEntity.getId());
}
}
entity.updateDynamicGameEventListener(DynamicGameEventListener::remove);
ServerLevel.this.debugSynchronizers.dropEntity(entity);
}
public void onSectionChange(Entity entity) {
entity.updateDynamicGameEventListener(DynamicGameEventListener::move);
}
}
}引用的其他类
-
- 引用位置:
参数/构造调用 - 关联成员:
CrashReport()
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
参数/字段/方法调用/构造调用/返回值 - 关联成员:
BlockPos(), BlockPos.containing()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数/返回值
- 引用位置:
-
- 引用位置:
参数/方法调用 - 关联成员:
SectionPos.blockToSectionCoord(), SectionPos.of(), SectionPos.sectionToBlockCoord()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数/返回值
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Component.translatable()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
ClientboundBlockDestructionPacket
- 引用位置:
构造调用 - 关联成员:
ClientboundBlockDestructionPacket()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
ClientboundBlockEventPacket()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
ClientboundDamageEventPacket()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
ClientboundEntityEventPacket()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
ClientboundExplodePacket()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
ClientboundGameEventPacket()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
ClientboundLevelEventPacket()
- 引用位置:
-
ClientboundLevelParticlesPacket
- 引用位置:
构造调用 - 关联成员:
ClientboundLevelParticlesPacket()
- 引用位置:
-
ClientboundPlayerInfoUpdatePacket
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
ClientboundSoundEntityPacket()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
ClientboundSoundPacket()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数/字段/返回值
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
字段/构造调用/返回值 - 关联成员:
ServerChunkCache()
- 引用位置:
-
- 引用位置:
实现
- 引用位置:
-
- 引用位置:
参数/字段/返回值
- 引用位置:
-
- 引用位置:
字段/构造调用 - 关联成员:
SleepStatus()
- 引用位置:
-
- 引用位置:
字段/构造调用/返回值 - 关联成员:
ServerWaypointManager()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
CsvOutput.builder()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Mth.clamp(), Mth.square()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Util.logAndPauseIfInIde()
- 引用位置:
-
- 引用位置:
字段/构造调用/返回值 - 关联成员:
LevelDebugSynchronizers()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Profiler.get()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
字段
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
UniformInt.of()
- 引用位置:
-
- 引用位置:
构造调用/返回值 - 关联成员:
DifficultyInstance()
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
参数/字段/方法调用/返回值 - 关联成员:
EnvironmentAttributeSystem.builder()
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数/字段/返回值
- 引用位置:
-
- 引用位置:
字段
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
PoiTypes.forState()
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
字段/返回值
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
字段/返回值
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
参数/字段/构造调用 - 关联成员:
BlockEventData()
- 引用位置:
-
- 引用位置:
参数/方法调用/构造调用 - 关联成员:
ChunkPos(), ChunkPos.containing(), ChunkPos.pack(), ChunkPos.rangeClosed()
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数/继承
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
ServerExplosion()
- 引用位置:
-
- 引用位置:
字段/构造调用/返回值 - 关联成员:
StructureManager()
- 引用位置:
-
- 引用位置:
实现
- 引用位置:
-
- 引用位置:
参数/返回值
- 引用位置:
-
- 引用位置:
参数/字段/方法调用/返回值 - 关联成员:
Block.pushEntitiesUp()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
EntityStorage()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
RegionStorageInfo()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
SimpleRegionStorage()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数/字段/返回值
- 引用位置:
-
- 引用位置:
字段/构造调用 - 关联成员:
EntityTickList()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
PersistentEntitySectionManager
- 引用位置:
字段
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
字段/构造调用 - 关联成员:
GameEventDispatcher()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
字段/构造调用 - 关联成员:
StructureCheck()
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
参数/字段/返回值
- 引用位置:
-
- 引用位置:
字段/构造调用/返回值 - 关联成员:
PathTypeCache()
- 引用位置:
-
- 引用位置:
字段/构造调用/返回值 - 关联成员:
PortalForcer()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
ExperimentalRedstoneUtils.initialOrientation()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数/返回值
- 引用位置:
-
- 引用位置:
参数/返回值
- 引用位置:
-
- 引用位置:
参数/方法调用/返回值 - 关联成员:
MapItemSavedData.type()
- 引用位置:
-
- 引用位置:
参数/返回值
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
AABB.encapsulatingFullBlocks()
- 引用位置:
-
- 引用位置:
参数/方法调用/构造调用 - 关联成员:
Vec3(), Vec3.atBottomCenterOf(), Vec3.atCenterOf()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Shapes.joinIsNotEmpty()
- 引用位置:
-
- 引用位置:
字段/返回值
- 引用位置: