mirror of
https://github.com/PaperMC/Paper.git
synced 2025-01-07 19:12:22 +01:00
08698c4642
* Only send global sounds to same world if limiting radius * respect global sound events gamerule Co-authored-by: Evan McCarthy <evanmccarthy@outlook.com> Co-authored-by: lexikiq <noellekiq@gmail.com> Co-authored-by: Aikar <aikar@aikar.co>
987 lines
52 KiB
Diff
987 lines
52 KiB
Diff
--- a/net/minecraft/server/level/ServerLevel.java
|
|
+++ b/net/minecraft/server/level/ServerLevel.java
|
|
@@ -58,7 +58,6 @@
|
|
import net.minecraft.network.protocol.game.ClientboundDamageEventPacket;
|
|
import net.minecraft.network.protocol.game.ClientboundEntityEventPacket;
|
|
import net.minecraft.network.protocol.game.ClientboundExplodePacket;
|
|
-import net.minecraft.network.protocol.game.ClientboundGameEventPacket;
|
|
import net.minecraft.network.protocol.game.ClientboundLevelEventPacket;
|
|
import net.minecraft.network.protocol.game.ClientboundLevelParticlesPacket;
|
|
import net.minecraft.network.protocol.game.ClientboundSetDefaultSpawnPositionPacket;
|
|
@@ -124,6 +123,7 @@
|
|
import net.minecraft.world.level.StructureManager;
|
|
import net.minecraft.world.level.WorldGenLevel;
|
|
import net.minecraft.world.level.biome.Biome;
|
|
+import net.minecraft.world.level.biome.BiomeSource;
|
|
import net.minecraft.world.level.block.Block;
|
|
import net.minecraft.world.level.block.Blocks;
|
|
import net.minecraft.world.level.block.SnowLayerBlock;
|
|
@@ -149,7 +149,9 @@
|
|
import net.minecraft.world.level.gameevent.DynamicGameEventListener;
|
|
import net.minecraft.world.level.gameevent.GameEvent;
|
|
import net.minecraft.world.level.gameevent.GameEventDispatcher;
|
|
+import net.minecraft.world.level.levelgen.FlatLevelSource;
|
|
import net.minecraft.world.level.levelgen.Heightmap;
|
|
+import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
|
|
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
|
import net.minecraft.world.level.levelgen.structure.Structure;
|
|
import net.minecraft.world.level.levelgen.structure.StructureCheck;
|
|
@@ -165,7 +167,7 @@
|
|
import net.minecraft.world.level.saveddata.maps.MapItemSavedData;
|
|
import net.minecraft.world.level.storage.DimensionDataStorage;
|
|
import net.minecraft.world.level.storage.LevelStorageSource;
|
|
-import net.minecraft.world.level.storage.ServerLevelData;
|
|
+import net.minecraft.world.level.storage.PrimaryLevelData;
|
|
import net.minecraft.world.phys.AABB;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import net.minecraft.world.phys.shapes.BooleanOp;
|
|
@@ -173,6 +175,16 @@
|
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
|
import net.minecraft.world.ticks.LevelTicks;
|
|
import org.slf4j.Logger;
|
|
+import org.bukkit.Bukkit;
|
|
+import org.bukkit.WeatherType;
|
|
+import org.bukkit.craftbukkit.event.CraftEventFactory;
|
|
+import org.bukkit.craftbukkit.generator.CustomWorldChunkManager;
|
|
+import org.bukkit.craftbukkit.util.WorldUUID;
|
|
+import org.bukkit.event.entity.CreatureSpawnEvent;
|
|
+import org.bukkit.event.server.MapInitializeEvent;
|
|
+import org.bukkit.event.weather.LightningStrikeEvent;
|
|
+import org.bukkit.event.world.TimeSkipEvent;
|
|
+// CraftBukkit end
|
|
|
|
public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLevel {
|
|
|
|
@@ -187,7 +199,7 @@
|
|
final List<ServerPlayer> players = Lists.newArrayList();
|
|
public final ServerChunkCache chunkSource;
|
|
private final MinecraftServer server;
|
|
- public final ServerLevelData serverLevelData;
|
|
+ public final PrimaryLevelData serverLevelData; // CraftBukkit - type
|
|
private int lastSpawnChunkRadius;
|
|
final EntityTickList entityTickList = new EntityTickList();
|
|
public final PersistentEntitySectionManager<Entity> entityManager;
|
|
@@ -214,52 +226,185 @@
|
|
private final boolean tickTime;
|
|
private final RandomSequences randomSequences;
|
|
|
|
- public ServerLevel(MinecraftServer server, Executor workerExecutor, LevelStorageSource.LevelStorageAccess session, ServerLevelData properties, ResourceKey<Level> worldKey, LevelStem dimensionOptions, ChunkProgressListener worldGenerationProgressListener, boolean debugWorld, long seed, List<CustomSpawner> spawners, boolean shouldTickTime, @Nullable RandomSequences randomSequencesState) {
|
|
- super(properties, worldKey, server.registryAccess(), dimensionOptions.type(), false, debugWorld, seed, server.getMaxChainedNeighborUpdates());
|
|
- this.tickTime = shouldTickTime;
|
|
- this.server = server;
|
|
- this.customSpawners = spawners;
|
|
- this.serverLevelData = properties;
|
|
- ChunkGenerator chunkgenerator = dimensionOptions.generator();
|
|
- boolean flag2 = server.forceSynchronousWrites();
|
|
- DataFixer datafixer = server.getFixerUpper();
|
|
- EntityPersistentStorage<Entity> entitypersistentstorage = new EntityStorage(new SimpleRegionStorage(new RegionStorageInfo(session.getLevelId(), worldKey, "entities"), session.getDimensionPath(worldKey).resolve("entities"), datafixer, flag2, DataFixTypes.ENTITY_CHUNK), this, server);
|
|
+ // CraftBukkit start
|
|
+ public final LevelStorageSource.LevelStorageAccess convertable;
|
|
+ public final UUID uuid;
|
|
+ public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent
|
|
|
|
+ public LevelChunk getChunkIfLoaded(int x, int z) {
|
|
+ return this.chunkSource.getChunk(x, z, false);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ResourceKey<LevelStem> getTypeKey() {
|
|
+ return this.convertable.dimensionType;
|
|
+ }
|
|
+
|
|
+ // Paper start
|
|
+ public final boolean areChunksLoadedForMove(AABB axisalignedbb) {
|
|
+ // copied code from collision methods, so that we can guarantee that they wont load chunks (we don't override
|
|
+ // ICollisionAccess methods for VoxelShapes)
|
|
+ // be more strict too, add a block (dumb plugins in move events?)
|
|
+ int minBlockX = Mth.floor(axisalignedbb.minX - 1.0E-7D) - 3;
|
|
+ int maxBlockX = Mth.floor(axisalignedbb.maxX + 1.0E-7D) + 3;
|
|
+
|
|
+ int minBlockZ = Mth.floor(axisalignedbb.minZ - 1.0E-7D) - 3;
|
|
+ int maxBlockZ = Mth.floor(axisalignedbb.maxZ + 1.0E-7D) + 3;
|
|
+
|
|
+ int minChunkX = minBlockX >> 4;
|
|
+ int maxChunkX = maxBlockX >> 4;
|
|
+
|
|
+ int minChunkZ = minBlockZ >> 4;
|
|
+ int maxChunkZ = maxBlockZ >> 4;
|
|
+
|
|
+ ServerChunkCache chunkProvider = this.getChunkSource();
|
|
+
|
|
+ for (int cx = minChunkX; cx <= maxChunkX; ++cx) {
|
|
+ for (int cz = minChunkZ; cz <= maxChunkZ; ++cz) {
|
|
+ if (chunkProvider.getChunkAtIfLoadedImmediately(cx, cz) == null) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ public final void loadChunksForMoveAsync(AABB axisalignedbb, ca.spottedleaf.concurrentutil.util.Priority priority,
|
|
+ java.util.function.Consumer<List<net.minecraft.world.level.chunk.ChunkAccess>> onLoad) {
|
|
+ if (Thread.currentThread() != this.thread) {
|
|
+ this.getChunkSource().mainThreadProcessor.execute(() -> {
|
|
+ this.loadChunksForMoveAsync(axisalignedbb, priority, onLoad);
|
|
+ });
|
|
+ return;
|
|
+ }
|
|
+ int minBlockX = Mth.floor(axisalignedbb.minX - 1.0E-7D) - 3;
|
|
+ int minBlockZ = Mth.floor(axisalignedbb.minZ - 1.0E-7D) - 3;
|
|
+
|
|
+ int maxBlockX = Mth.floor(axisalignedbb.maxX + 1.0E-7D) + 3;
|
|
+ int maxBlockZ = Mth.floor(axisalignedbb.maxZ + 1.0E-7D) + 3;
|
|
+
|
|
+ int minChunkX = minBlockX >> 4;
|
|
+ int minChunkZ = minBlockZ >> 4;
|
|
+
|
|
+ int maxChunkX = maxBlockX >> 4;
|
|
+ int maxChunkZ = maxBlockZ >> 4;
|
|
+
|
|
+ this.loadChunks(minChunkX, minChunkZ, maxChunkX, maxChunkZ, priority, onLoad);
|
|
+ }
|
|
+
|
|
+ public final void loadChunks(int minChunkX, int minChunkZ, int maxChunkX, int maxChunkZ,
|
|
+ ca.spottedleaf.concurrentutil.util.Priority priority,
|
|
+ java.util.function.Consumer<List<net.minecraft.world.level.chunk.ChunkAccess>> onLoad) {
|
|
+ List<net.minecraft.world.level.chunk.ChunkAccess> ret = new java.util.ArrayList<>();
|
|
+ it.unimi.dsi.fastutil.ints.IntArrayList ticketLevels = new it.unimi.dsi.fastutil.ints.IntArrayList();
|
|
+ ServerChunkCache chunkProvider = this.getChunkSource();
|
|
+
|
|
+ int requiredChunks = (maxChunkX - minChunkX + 1) * (maxChunkZ - minChunkZ + 1);
|
|
+ int[] loadedChunks = new int[1];
|
|
+
|
|
+ Long holderIdentifier = Long.valueOf(chunkProvider.chunkFutureAwaitCounter++);
|
|
+
|
|
+ java.util.function.Consumer<net.minecraft.world.level.chunk.ChunkAccess> consumer = (net.minecraft.world.level.chunk.ChunkAccess chunk) -> {
|
|
+ if (chunk != null) {
|
|
+ int ticketLevel = Math.max(33, chunkProvider.chunkMap.getUpdatingChunkIfPresent(chunk.getPos().toLong()).getTicketLevel());
|
|
+ ret.add(chunk);
|
|
+ ticketLevels.add(ticketLevel);
|
|
+ chunkProvider.addTicketAtLevel(TicketType.FUTURE_AWAIT, chunk.getPos(), ticketLevel, holderIdentifier);
|
|
+ }
|
|
+ if (++loadedChunks[0] == requiredChunks) {
|
|
+ try {
|
|
+ onLoad.accept(java.util.Collections.unmodifiableList(ret));
|
|
+ } finally {
|
|
+ for (int i = 0, len = ret.size(); i < len; ++i) {
|
|
+ ChunkPos chunkPos = ret.get(i).getPos();
|
|
+ int ticketLevel = ticketLevels.getInt(i);
|
|
+
|
|
+ chunkProvider.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, ticketLevel, chunkPos);
|
|
+ chunkProvider.removeTicketAtLevel(TicketType.FUTURE_AWAIT, chunkPos, ticketLevel, holderIdentifier);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ };
|
|
+
|
|
+ for (int cx = minChunkX; cx <= maxChunkX; ++cx) {
|
|
+ for (int cz = minChunkZ; cz <= maxChunkZ; ++cz) {
|
|
+ ca.spottedleaf.moonrise.common.util.ChunkSystem.scheduleChunkLoad(
|
|
+ this, cx, cz, net.minecraft.world.level.chunk.status.ChunkStatus.FULL, true, priority, consumer
|
|
+ );
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Paper end
|
|
+
|
|
+ // Add env and gen to constructor, IWorldDataServer -> WorldDataServer
|
|
+ public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey<Level> resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List<CustomSpawner> list, boolean flag1, @Nullable RandomSequences randomsequences, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) {
|
|
+ super(iworlddataserver, resourcekey, minecraftserver.registryAccess(), worlddimension.type(), false, flag, i, minecraftserver.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> minecraftserver.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(convertable_conversionsession.levelDirectory.path(), iworlddataserver.getLevelName(), resourcekey.location(), spigotConfig, minecraftserver.registryAccess(), iworlddataserver.getGameRules()))); // Paper - create paper world configs
|
|
+ this.pvpMode = minecraftserver.isPvpAllowed();
|
|
+ this.convertable = convertable_conversionsession;
|
|
+ this.uuid = WorldUUID.getUUID(convertable_conversionsession.levelDirectory.path().toFile());
|
|
+ // CraftBukkit end
|
|
+ this.tickTime = flag1;
|
|
+ this.server = minecraftserver;
|
|
+ this.customSpawners = list;
|
|
+ this.serverLevelData = iworlddataserver;
|
|
+ ChunkGenerator chunkgenerator = worlddimension.generator();
|
|
+ // CraftBukkit start
|
|
+ this.serverLevelData.setWorld(this);
|
|
+
|
|
+ if (biomeProvider != null) {
|
|
+ BiomeSource worldChunkManager = new CustomWorldChunkManager(this.getWorld(), biomeProvider, this.server.registryAccess().lookupOrThrow(Registries.BIOME));
|
|
+ if (chunkgenerator instanceof NoiseBasedChunkGenerator cga) {
|
|
+ chunkgenerator = new NoiseBasedChunkGenerator(worldChunkManager, cga.settings);
|
|
+ } else if (chunkgenerator instanceof FlatLevelSource cpf) {
|
|
+ chunkgenerator = new FlatLevelSource(cpf.settings(), worldChunkManager);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (gen != null) {
|
|
+ chunkgenerator = new org.bukkit.craftbukkit.generator.CustomChunkGenerator(this, chunkgenerator, gen);
|
|
+ }
|
|
+ // CraftBukkit end
|
|
+ boolean flag2 = minecraftserver.forceSynchronousWrites();
|
|
+ DataFixer datafixer = minecraftserver.getFixerUpper();
|
|
+ EntityPersistentStorage<Entity> entitypersistentstorage = new EntityStorage(new SimpleRegionStorage(new RegionStorageInfo(convertable_conversionsession.getLevelId(), resourcekey, "entities"), convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), datafixer, flag2, DataFixTypes.ENTITY_CHUNK), this, minecraftserver);
|
|
+
|
|
this.entityManager = new PersistentEntitySectionManager<>(Entity.class, new ServerLevel.EntityCallbacks(), entitypersistentstorage);
|
|
- StructureTemplateManager structuretemplatemanager = server.getStructureManager();
|
|
- int j = server.getPlayerList().getViewDistance();
|
|
- int k = server.getPlayerList().getSimulationDistance();
|
|
+ StructureTemplateManager structuretemplatemanager = minecraftserver.getStructureManager();
|
|
+ int j = this.spigotConfig.viewDistance; // Spigot
|
|
+ int k = this.spigotConfig.simulationDistance; // Spigot
|
|
PersistentEntitySectionManager persistententitysectionmanager = this.entityManager;
|
|
|
|
Objects.requireNonNull(this.entityManager);
|
|
- this.chunkSource = new ServerChunkCache(this, session, datafixer, structuretemplatemanager, workerExecutor, chunkgenerator, j, k, flag2, worldGenerationProgressListener, persistententitysectionmanager::updateChunkStatus, () -> {
|
|
- return server.overworld().getDataStorage();
|
|
+ this.chunkSource = new ServerChunkCache(this, convertable_conversionsession, datafixer, structuretemplatemanager, executor, chunkgenerator, j, k, flag2, worldloadlistener, persistententitysectionmanager::updateChunkStatus, () -> {
|
|
+ return minecraftserver.overworld().getDataStorage();
|
|
});
|
|
this.chunkSource.getGeneratorState().ensureStructuresGenerated();
|
|
this.portalForcer = new PortalForcer(this);
|
|
this.updateSkyBrightness();
|
|
this.prepareWeather();
|
|
- this.getWorldBorder().setAbsoluteMaxSize(server.getAbsoluteMaxWorldSize());
|
|
+ this.getWorldBorder().setAbsoluteMaxSize(minecraftserver.getAbsoluteMaxWorldSize());
|
|
this.raids = (Raids) this.getDataStorage().computeIfAbsent(Raids.factory(this), Raids.getFileId(this.dimensionTypeRegistration()));
|
|
- if (!server.isSingleplayer()) {
|
|
- properties.setGameType(server.getDefaultGameType());
|
|
+ if (!minecraftserver.isSingleplayer()) {
|
|
+ iworlddataserver.setGameType(minecraftserver.getDefaultGameType());
|
|
}
|
|
|
|
- long l = server.getWorldData().worldGenOptions().seed();
|
|
+ long l = minecraftserver.getWorldData().worldGenOptions().seed();
|
|
|
|
- this.structureCheck = new StructureCheck(this.chunkSource.chunkScanner(), this.registryAccess(), server.getStructureManager(), worldKey, chunkgenerator, this.chunkSource.randomState(), this, chunkgenerator.getBiomeSource(), l, datafixer);
|
|
- this.structureManager = new StructureManager(this, server.getWorldData().worldGenOptions(), this.structureCheck);
|
|
- if (this.dimension() == Level.END && this.dimensionTypeRegistration().is(BuiltinDimensionTypes.END)) {
|
|
- this.dragonFight = new EndDragonFight(this, l, server.getWorldData().endDragonFightData());
|
|
+ this.structureCheck = new StructureCheck(this.chunkSource.chunkScanner(), this.registryAccess(), minecraftserver.getStructureManager(), this.getTypeKey(), chunkgenerator, this.chunkSource.randomState(), this, chunkgenerator.getBiomeSource(), l, datafixer); // Paper - Fix missing CB diff
|
|
+ this.structureManager = new StructureManager(this, this.serverLevelData.worldGenOptions(), this.structureCheck); // CraftBukkit
|
|
+ if ((this.dimension() == Level.END && this.dimensionTypeRegistration().is(BuiltinDimensionTypes.END)) || env == org.bukkit.World.Environment.THE_END) { // CraftBukkit - Allow to create EnderDragonBattle in default and custom END
|
|
+ this.dragonFight = new EndDragonFight(this, this.serverLevelData.worldGenOptions().seed(), this.serverLevelData.endDragonFightData()); // CraftBukkit
|
|
} else {
|
|
this.dragonFight = null;
|
|
}
|
|
|
|
this.sleepStatus = new SleepStatus();
|
|
this.gameEventDispatcher = new GameEventDispatcher(this);
|
|
- this.randomSequences = (RandomSequences) Objects.requireNonNullElseGet(randomSequencesState, () -> {
|
|
+ this.randomSequences = (RandomSequences) Objects.requireNonNullElseGet(randomsequences, () -> {
|
|
return (RandomSequences) this.getDataStorage().computeIfAbsent(RandomSequences.factory(l), "random_sequences");
|
|
});
|
|
+ this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit
|
|
}
|
|
|
|
/** @deprecated */
|
|
@@ -305,12 +450,20 @@
|
|
long j;
|
|
|
|
if (this.sleepStatus.areEnoughSleeping(i) && this.sleepStatus.areEnoughDeepSleeping(i, this.players)) {
|
|
+ // CraftBukkit start
|
|
+ j = this.levelData.getDayTime() + 24000L;
|
|
+ TimeSkipEvent event = new TimeSkipEvent(this.getWorld(), TimeSkipEvent.SkipReason.NIGHT_SKIP, (j - j % 24000L) - this.getDayTime());
|
|
if (this.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)) {
|
|
- j = this.levelData.getDayTime() + 24000L;
|
|
- this.setDayTime(j - j % 24000L);
|
|
+ this.getCraftServer().getPluginManager().callEvent(event);
|
|
+ if (!event.isCancelled()) {
|
|
+ this.setDayTime(this.getDayTime() + event.getSkipAmount());
|
|
+ }
|
|
}
|
|
|
|
- this.wakeUpAllPlayers();
|
|
+ if (!event.isCancelled()) {
|
|
+ this.wakeUpAllPlayers();
|
|
+ }
|
|
+ // CraftBukkit end
|
|
if (this.getGameRules().getBoolean(GameRules.RULE_WEATHER_CYCLE) && this.isRaining()) {
|
|
this.resetWeatherCycle();
|
|
}
|
|
@@ -345,7 +498,7 @@
|
|
|
|
this.handlingTick = false;
|
|
gameprofilerfiller.pop();
|
|
- boolean flag1 = !this.players.isEmpty() || !this.getForcedChunks().isEmpty();
|
|
+ boolean flag1 = true || !this.players.isEmpty() || !this.getForcedChunks().isEmpty(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players
|
|
|
|
if (flag1) {
|
|
this.resetEmptyTime();
|
|
@@ -359,6 +512,7 @@
|
|
gameprofilerfiller.pop();
|
|
}
|
|
|
|
+ org.spigotmc.ActivationRange.activateEntities(this); // Spigot
|
|
this.entityTickList.forEach((entity) -> {
|
|
if (!entity.isRemoved()) {
|
|
if (!tickratemanager.isEntityFrozen(entity)) {
|
|
@@ -429,7 +583,7 @@
|
|
|
|
private void wakeUpAllPlayers() {
|
|
this.sleepStatus.removeAllSleepers();
|
|
- ((List) this.players.stream().filter(LivingEntity::isSleeping).collect(Collectors.toList())).forEach((entityplayer) -> {
|
|
+ (this.players.stream().filter(LivingEntity::isSleeping).collect(Collectors.toList())).forEach((entityplayer) -> { // CraftBukkit - decompile error
|
|
entityplayer.stopSleepInBed(false, false);
|
|
});
|
|
}
|
|
@@ -442,12 +596,12 @@
|
|
ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
|
|
gameprofilerfiller.push("thunder");
|
|
- if (flag && this.isThundering() && this.random.nextInt(100000) == 0) {
|
|
+ if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - Option to disable thunder
|
|
BlockPos blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15));
|
|
|
|
if (this.isRainingAt(blockposition)) {
|
|
DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition);
|
|
- boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * 0.01D && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD);
|
|
+ boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * this.paperConfig().entities.spawning.skeletonHorseThunderSpawnChance.or(0.01D) && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD); // Paper - Configurable spawn chances for skeleton horses
|
|
|
|
if (flag1) {
|
|
SkeletonHorse entityhorseskeleton = (SkeletonHorse) EntityType.SKELETON_HORSE.create(this, EntitySpawnReason.EVENT);
|
|
@@ -456,7 +610,7 @@
|
|
entityhorseskeleton.setTrap(true);
|
|
entityhorseskeleton.setAge(0);
|
|
entityhorseskeleton.setPos((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ());
|
|
- this.addFreshEntity(entityhorseskeleton);
|
|
+ this.addFreshEntity(entityhorseskeleton, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING); // CraftBukkit
|
|
}
|
|
}
|
|
|
|
@@ -465,18 +619,20 @@
|
|
if (entitylightning != null) {
|
|
entitylightning.moveTo(Vec3.atBottomCenterOf(blockposition));
|
|
entitylightning.setVisualOnly(flag1);
|
|
- this.addFreshEntity(entitylightning);
|
|
+ this.strikeLightning(entitylightning, org.bukkit.event.weather.LightningStrikeEvent.Cause.WEATHER); // CraftBukkit
|
|
}
|
|
}
|
|
}
|
|
|
|
gameprofilerfiller.popPush("iceandsnow");
|
|
|
|
+ if (!this.paperConfig().environment.disableIceAndSnow) { // Paper - Option to disable ice and snow
|
|
for (int l = 0; l < randomTickSpeed; ++l) {
|
|
if (this.random.nextInt(48) == 0) {
|
|
this.tickPrecipitation(this.getBlockRandomPos(j, 0, k, 15));
|
|
}
|
|
}
|
|
+ } // Paper - Option to disable ice and snow
|
|
|
|
gameprofilerfiller.popPush("tickBlocks");
|
|
if (randomTickSpeed > 0) {
|
|
@@ -521,7 +677,7 @@
|
|
Biome biomebase = (Biome) this.getBiome(blockposition1).value();
|
|
|
|
if (biomebase.shouldFreeze(this, blockposition2)) {
|
|
- this.setBlockAndUpdate(blockposition2, Blocks.ICE.defaultBlockState());
|
|
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition2, Blocks.ICE.defaultBlockState(), null); // CraftBukkit
|
|
}
|
|
|
|
if (this.isRaining()) {
|
|
@@ -537,10 +693,10 @@
|
|
BlockState iblockdata1 = (BlockState) iblockdata.setValue(SnowLayerBlock.LAYERS, j + 1);
|
|
|
|
Block.pushEntitiesUp(iblockdata, iblockdata1, this, blockposition1);
|
|
- this.setBlockAndUpdate(blockposition1, iblockdata1);
|
|
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition1, iblockdata1, null); // CraftBukkit
|
|
}
|
|
} else {
|
|
- this.setBlockAndUpdate(blockposition1, Blocks.SNOW.defaultBlockState());
|
|
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition1, Blocks.SNOW.defaultBlockState(), null); // CraftBukkit
|
|
}
|
|
}
|
|
|
|
@@ -701,33 +857,67 @@
|
|
this.rainLevel = Mth.clamp(this.rainLevel, 0.0F, 1.0F);
|
|
}
|
|
|
|
+ /* CraftBukkit start
|
|
if (this.oRainLevel != this.rainLevel) {
|
|
- this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.RAIN_LEVEL_CHANGE, this.rainLevel), this.dimension());
|
|
+ this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.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());
|
|
+ this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.THUNDER_LEVEL_CHANGE, this.thunderLevel), this.dimension());
|
|
}
|
|
|
|
if (flag != this.isRaining()) {
|
|
if (flag) {
|
|
- this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.STOP_RAINING, 0.0F));
|
|
+ this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.STOP_RAINING, 0.0F));
|
|
} else {
|
|
- this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.START_RAINING, 0.0F));
|
|
+ this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.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));
|
|
+ this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.RAIN_LEVEL_CHANGE, this.rainLevel));
|
|
+ this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.THUNDER_LEVEL_CHANGE, this.thunderLevel));
|
|
}
|
|
+ // */
|
|
+ for (int idx = 0; idx < this.players.size(); ++idx) {
|
|
+ if (((ServerPlayer) this.players.get(idx)).level() == this) {
|
|
+ ((ServerPlayer) this.players.get(idx)).tickWeather();
|
|
+ }
|
|
+ }
|
|
|
|
+ if (flag != this.isRaining()) {
|
|
+ // Only send weather packets to those affected
|
|
+ for (int idx = 0; idx < this.players.size(); ++idx) {
|
|
+ if (((ServerPlayer) this.players.get(idx)).level() == this) {
|
|
+ ((ServerPlayer) this.players.get(idx)).setPlayerWeather((!flag ? WeatherType.DOWNFALL : WeatherType.CLEAR), false);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ for (int idx = 0; idx < this.players.size(); ++idx) {
|
|
+ if (((ServerPlayer) this.players.get(idx)).level() == this) {
|
|
+ ((ServerPlayer) this.players.get(idx)).updateWeather(this.oRainLevel, this.rainLevel, this.oThunderLevel, this.thunderLevel);
|
|
+ }
|
|
+ }
|
|
+ // CraftBukkit end
|
|
+
|
|
}
|
|
|
|
@VisibleForTesting
|
|
public void resetWeatherCycle() {
|
|
- this.serverLevelData.setRainTime(0);
|
|
+ // CraftBukkit start
|
|
this.serverLevelData.setRaining(false);
|
|
- this.serverLevelData.setThunderTime(0);
|
|
+ // If we stop due to everyone sleeping we should reset the weather duration to some other random value.
|
|
+ // Not that everyone ever manages to get the whole server to sleep at the same time....
|
|
+ if (!this.serverLevelData.isRaining()) {
|
|
+ this.serverLevelData.setRainTime(0);
|
|
+ }
|
|
+ // CraftBukkit end
|
|
this.serverLevelData.setThundering(false);
|
|
+ // CraftBukkit start
|
|
+ // If we stop due to everyone sleeping we should reset the weather duration to some other random value.
|
|
+ // Not that everyone ever manages to get the whole server to sleep at the same time....
|
|
+ if (!this.serverLevelData.isThundering()) {
|
|
+ this.serverLevelData.setThunderTime(0);
|
|
+ }
|
|
+ // CraftBukkit end
|
|
}
|
|
|
|
public void resetEmptyTime() {
|
|
@@ -754,6 +944,13 @@
|
|
}
|
|
|
|
public void tickNonPassenger(Entity entity) {
|
|
+ // Spigot start
|
|
+ if (!org.spigotmc.ActivationRange.checkIfActive(entity)) {
|
|
+ entity.tickCount++;
|
|
+ entity.inactiveTick();
|
|
+ return;
|
|
+ }
|
|
+ // Spigot end
|
|
entity.setOldPosAndRot();
|
|
ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
|
|
@@ -763,6 +960,7 @@
|
|
});
|
|
gameprofilerfiller.incrementCounter("tickNonPassenger");
|
|
entity.tick();
|
|
+ entity.postTick(); // CraftBukkit
|
|
gameprofilerfiller.pop();
|
|
Iterator iterator = entity.getPassengers().iterator();
|
|
|
|
@@ -786,6 +984,7 @@
|
|
});
|
|
gameprofilerfiller.incrementCounter("tickPassenger");
|
|
passenger.rideTick();
|
|
+ passenger.postTick(); // CraftBukkit
|
|
gameprofilerfiller.pop();
|
|
Iterator iterator = passenger.getPassengers().iterator();
|
|
|
|
@@ -810,6 +1009,7 @@
|
|
ServerChunkCache chunkproviderserver = this.getChunkSource();
|
|
|
|
if (!savingDisabled) {
|
|
+ org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(this.getWorld())); // CraftBukkit
|
|
if (progressListener != null) {
|
|
progressListener.progressStartNoAbort(Component.translatable("menu.savingLevel"));
|
|
}
|
|
@@ -827,11 +1027,19 @@
|
|
}
|
|
|
|
}
|
|
+
|
|
+ // CraftBukkit start - moved from MinecraftServer.saveChunks
|
|
+ ServerLevel worldserver1 = this;
|
|
+
|
|
+ this.serverLevelData.setWorldBorder(worldserver1.getWorldBorder().createSettings());
|
|
+ this.serverLevelData.setCustomBossEvents(this.server.getCustomBossEvents().save(this.registryAccess()));
|
|
+ this.convertable.saveDataTag(this.server.registryAccess(), this.serverLevelData, this.server.getPlayerList().getSingleplayerData());
|
|
+ // CraftBukkit end
|
|
}
|
|
|
|
private void saveLevelData(boolean flush) {
|
|
if (this.dragonFight != null) {
|
|
- this.server.getWorldData().setEndDragonFightData(this.dragonFight.saveData());
|
|
+ this.serverLevelData.setEndDragonFightData(this.dragonFight.saveData()); // CraftBukkit
|
|
}
|
|
|
|
DimensionDataStorage worldpersistentdata = this.getChunkSource().getDataStorage();
|
|
@@ -903,18 +1111,40 @@
|
|
|
|
@Override
|
|
public boolean addFreshEntity(Entity entity) {
|
|
- return this.addEntity(entity);
|
|
+ // CraftBukkit start
|
|
+ return this.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.DEFAULT);
|
|
}
|
|
|
|
+ @Override
|
|
+ public boolean addFreshEntity(Entity entity, CreatureSpawnEvent.SpawnReason reason) {
|
|
+ return this.addEntity(entity, reason);
|
|
+ // CraftBukkit end
|
|
+ }
|
|
+
|
|
public boolean addWithUUID(Entity entity) {
|
|
- return this.addEntity(entity);
|
|
+ // CraftBukkit start
|
|
+ return this.addWithUUID(entity, CreatureSpawnEvent.SpawnReason.DEFAULT);
|
|
}
|
|
|
|
+ public boolean addWithUUID(Entity entity, CreatureSpawnEvent.SpawnReason reason) {
|
|
+ return this.addEntity(entity, reason);
|
|
+ // CraftBukkit end
|
|
+ }
|
|
+
|
|
public void addDuringTeleport(Entity entity) {
|
|
+ // CraftBukkit start
|
|
+ // SPIGOT-6415: Don't call spawn event for entities which travel trough worlds,
|
|
+ // since it is only an implementation detail, that a new entity is created when
|
|
+ // they are traveling between worlds.
|
|
+ this.addDuringTeleport(entity, null);
|
|
+ }
|
|
+
|
|
+ public void addDuringTeleport(Entity entity, CreatureSpawnEvent.SpawnReason reason) {
|
|
+ // CraftBukkit end
|
|
if (entity instanceof ServerPlayer entityplayer) {
|
|
this.addPlayer(entityplayer);
|
|
} else {
|
|
- this.addEntity(entity);
|
|
+ this.addEntity(entity, reason); // CraftBukkit
|
|
}
|
|
|
|
}
|
|
@@ -939,41 +1169,86 @@
|
|
this.entityManager.addNewEntity(player);
|
|
}
|
|
|
|
- private boolean addEntity(Entity entity) {
|
|
+ // CraftBukkit start
|
|
+ private boolean addEntity(Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) {
|
|
+ org.spigotmc.AsyncCatcher.catchOp("entity add"); // Spigot
|
|
if (entity.isRemoved()) {
|
|
- ServerLevel.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityType.getKey(entity.getType()));
|
|
+ // WorldServer.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityTypes.getKey(entity.getType())); // CraftBukkit
|
|
return false;
|
|
} else {
|
|
+ // SPIGOT-6415: Don't call spawn event when reason is null. For example when an entity teleports to a new world.
|
|
+ if (spawnReason != null && !CraftEventFactory.doEntityAddEventCalling(this, entity, spawnReason)) {
|
|
+ return false;
|
|
+ }
|
|
+ // CraftBukkit end
|
|
+
|
|
return this.entityManager.addNewEntity(entity);
|
|
}
|
|
}
|
|
|
|
public boolean tryAddFreshEntityWithPassengers(Entity entity) {
|
|
- Stream stream = entity.getSelfAndPassengers().map(Entity::getUUID);
|
|
+ // CraftBukkit start
|
|
+ return this.tryAddFreshEntityWithPassengers(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT);
|
|
+ }
|
|
+
|
|
+ public boolean tryAddFreshEntityWithPassengers(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) {
|
|
+ // CraftBukkit end
|
|
+ Stream<UUID> stream = entity.getSelfAndPassengers().map(Entity::getUUID); // CraftBukkit - decompile error
|
|
PersistentEntitySectionManager persistententitysectionmanager = this.entityManager;
|
|
|
|
Objects.requireNonNull(this.entityManager);
|
|
if (stream.anyMatch(persistententitysectionmanager::isLoaded)) {
|
|
return false;
|
|
} else {
|
|
- this.addFreshEntityWithPassengers(entity);
|
|
+ this.addFreshEntityWithPassengers(entity, reason); // CraftBukkit
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public void unload(LevelChunk chunk) {
|
|
+ // Spigot Start
|
|
+ for (net.minecraft.world.level.block.entity.BlockEntity tileentity : chunk.getBlockEntities().values()) {
|
|
+ if (tileentity instanceof net.minecraft.world.Container) {
|
|
+ for (org.bukkit.entity.HumanEntity h : Lists.newArrayList(((net.minecraft.world.Container) tileentity).getViewers())) {
|
|
+ h.closeInventory();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Spigot End
|
|
chunk.clearAllBlockEntities();
|
|
chunk.unregisterTickContainerFromLevel(this);
|
|
}
|
|
|
|
public void removePlayerImmediately(ServerPlayer player, Entity.RemovalReason reason) {
|
|
- player.remove(reason);
|
|
+ player.remove(reason, null); // CraftBukkit - add Bukkit remove cause
|
|
}
|
|
|
|
+ // CraftBukkit start
|
|
+ public boolean strikeLightning(Entity entitylightning) {
|
|
+ return this.strikeLightning(entitylightning, LightningStrikeEvent.Cause.UNKNOWN);
|
|
+ }
|
|
+
|
|
+ public boolean strikeLightning(Entity entitylightning, LightningStrikeEvent.Cause cause) {
|
|
+ LightningStrikeEvent lightning = CraftEventFactory.callLightningStrikeEvent((org.bukkit.entity.LightningStrike) entitylightning.getBukkitEntity(), cause);
|
|
+
|
|
+ if (lightning.isCancelled()) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ return this.addFreshEntity(entitylightning);
|
|
+ }
|
|
+ // CraftBukkit end
|
|
+
|
|
@Override
|
|
public void destroyBlockProgress(int entityId, BlockPos pos, int progress) {
|
|
Iterator iterator = this.server.getPlayerList().getPlayers().iterator();
|
|
|
|
+ // CraftBukkit start
|
|
+ Player entityhuman = null;
|
|
+ Entity entity = this.getEntity(entityId);
|
|
+ if (entity instanceof Player) entityhuman = (Player) entity;
|
|
+ // CraftBukkit end
|
|
+
|
|
while (iterator.hasNext()) {
|
|
ServerPlayer entityplayer = (ServerPlayer) iterator.next();
|
|
|
|
@@ -982,6 +1257,12 @@
|
|
double d1 = (double) pos.getY() - entityplayer.getY();
|
|
double d2 = (double) pos.getZ() - entityplayer.getZ();
|
|
|
|
+ // CraftBukkit start
|
|
+ if (entityhuman != null && !entityplayer.getBukkitEntity().canSee(entityhuman.getBukkitEntity())) {
|
|
+ continue;
|
|
+ }
|
|
+ // CraftBukkit end
|
|
+
|
|
if (d0 * d0 + d1 * d1 + d2 * d2 < 1024.0D) {
|
|
entityplayer.connection.send(new ClientboundBlockDestructionPacket(entityId, pos, progress));
|
|
}
|
|
@@ -1030,7 +1311,7 @@
|
|
|
|
@Override
|
|
public void levelEvent(@Nullable Player player, int eventId, BlockPos pos, int data) {
|
|
- this.server.getPlayerList().broadcast(player, (double) pos.getX(), (double) pos.getY(), (double) pos.getZ(), 64.0D, this.dimension(), new ClientboundLevelEventPacket(eventId, pos, data, false));
|
|
+ this.server.getPlayerList().broadcast(player, (double) pos.getX(), (double) pos.getY(), (double) pos.getZ(), 64.0D, this.dimension(), new ClientboundLevelEventPacket(eventId, pos, data, false)); // Paper - diff on change (the 64.0 distance is used as defaults for sound ranges in spigot config for ender dragon, end portal and wither)
|
|
}
|
|
|
|
public int getLogicalHeight() {
|
|
@@ -1060,7 +1341,18 @@
|
|
Iterator iterator = this.navigatingMobs.iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
- Mob entityinsentient = (Mob) iterator.next();
|
|
+ // CraftBukkit start - fix SPIGOT-6362
|
|
+ Mob entityinsentient;
|
|
+ try {
|
|
+ entityinsentient = (Mob) iterator.next();
|
|
+ } catch (java.util.ConcurrentModificationException ex) {
|
|
+ // This can happen because the pathfinder update below may trigger a chunk load, which in turn may cause more navigators to register
|
|
+ // In this case we just run the update again across all the iterators as the chunk will then be loaded
|
|
+ // As this is a relative edge case it is much faster than copying navigators (on either read or write)
|
|
+ this.sendBlockUpdated(pos, oldState, newState, flags);
|
|
+ return;
|
|
+ }
|
|
+ // CraftBukkit end
|
|
PathNavigation navigationabstract = entityinsentient.getNavigation();
|
|
|
|
if (navigationabstract.shouldRecomputePath(pos)) {
|
|
@@ -1086,11 +1378,13 @@
|
|
|
|
@Override
|
|
public void updateNeighborsAt(BlockPos pos, Block block) {
|
|
+ if (captureBlockStates) { return; } // Paper - Cancel all physics during placement
|
|
this.updateNeighborsAt(pos, block, ExperimentalRedstoneUtils.initialOrientation(this, (Direction) null, (Direction) null));
|
|
}
|
|
|
|
@Override
|
|
public void updateNeighborsAt(BlockPos pos, Block sourceBlock, @Nullable Orientation orientation) {
|
|
+ if (captureBlockStates) { return; } // Paper - Cancel all physics during placement
|
|
this.neighborUpdater.updateNeighborsAtExceptFromFacing(pos, sourceBlock, (Direction) null, orientation);
|
|
}
|
|
|
|
@@ -1126,9 +1420,15 @@
|
|
|
|
@Override
|
|
public void explode(@Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, double x, double y, double z, float power, boolean createFire, Level.ExplosionInteraction explosionSourceType, ParticleOptions smallParticle, ParticleOptions largeParticle, Holder<SoundEvent> soundEvent) {
|
|
+ // CraftBukkit start
|
|
+ this.explode0(entity, damageSource, behavior, x, y, z, power, createFire, explosionSourceType, smallParticle, largeParticle, soundEvent);
|
|
+ }
|
|
+
|
|
+ public ServerExplosion explode0(@Nullable Entity entity, @Nullable DamageSource damagesource, @Nullable ExplosionDamageCalculator explosiondamagecalculator, double d0, double d1, double d2, float f, boolean flag, Level.ExplosionInteraction world_a, ParticleOptions particleparam, ParticleOptions particleparam1, Holder<SoundEvent> holder) {
|
|
+ // CraftBukkit end
|
|
Explosion.BlockInteraction explosion_effect;
|
|
|
|
- switch (explosionSourceType) {
|
|
+ switch (world_a) {
|
|
case NONE:
|
|
explosion_effect = Explosion.BlockInteraction.KEEP;
|
|
break;
|
|
@@ -1144,16 +1444,26 @@
|
|
case TRIGGER:
|
|
explosion_effect = Explosion.BlockInteraction.TRIGGER_BLOCK;
|
|
break;
|
|
+ // CraftBukkit start - handle custom explosion type
|
|
+ case STANDARD:
|
|
+ explosion_effect = Explosion.BlockInteraction.DESTROY;
|
|
+ break;
|
|
+ // CraftBukkit end
|
|
default:
|
|
throw new MatchException((String) null, (Throwable) null);
|
|
}
|
|
|
|
Explosion.BlockInteraction explosion_effect1 = explosion_effect;
|
|
- Vec3 vec3d = new Vec3(x, y, z);
|
|
- ServerExplosion serverexplosion = new ServerExplosion(this, entity, damageSource, behavior, vec3d, power, createFire, explosion_effect1);
|
|
+ Vec3 vec3d = new Vec3(d0, d1, d2);
|
|
+ ServerExplosion serverexplosion = new ServerExplosion(this, entity, damagesource, explosiondamagecalculator, vec3d, f, flag, explosion_effect1);
|
|
|
|
serverexplosion.explode();
|
|
- ParticleOptions particleparam2 = serverexplosion.isSmall() ? smallParticle : largeParticle;
|
|
+ // CraftBukkit start
|
|
+ if (serverexplosion.wasCanceled) {
|
|
+ return serverexplosion;
|
|
+ }
|
|
+ // CraftBukkit end
|
|
+ ParticleOptions particleparam2 = serverexplosion.isSmall() ? particleparam : particleparam1;
|
|
Iterator iterator = this.players.iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
@@ -1162,10 +1472,11 @@
|
|
if (entityplayer.distanceToSqr(vec3d) < 4096.0D) {
|
|
Optional<Vec3> optional = Optional.ofNullable((Vec3) serverexplosion.getHitPlayers().get(entityplayer));
|
|
|
|
- entityplayer.connection.send(new ClientboundExplodePacket(vec3d, optional, particleparam2, soundEvent));
|
|
+ entityplayer.connection.send(new ClientboundExplodePacket(vec3d, optional, particleparam2, holder));
|
|
}
|
|
}
|
|
|
|
+ return serverexplosion; // CraftBukkit
|
|
}
|
|
|
|
private Explosion.BlockInteraction getDestroyType(GameRules.Key<GameRules.BooleanValue> decayRule) {
|
|
@@ -1226,17 +1537,24 @@
|
|
}
|
|
|
|
public <T extends ParticleOptions> int sendParticles(T parameters, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double speed) {
|
|
- return this.sendParticles(parameters, false, false, x, y, z, count, offsetX, offsetY, offsetZ, speed);
|
|
+ return this.sendParticlesSource(null, parameters, false, false, x, y, z, count, offsetX, offsetY, offsetZ, speed); // CraftBukkit - visibility api support
|
|
}
|
|
|
|
public <T extends ParticleOptions> int sendParticles(T parameters, boolean force, boolean important, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double speed) {
|
|
- ClientboundLevelParticlesPacket packetplayoutworldparticles = new ClientboundLevelParticlesPacket(parameters, force, important, x, y, z, (float) offsetX, (float) offsetY, (float) offsetZ, (float) speed, count);
|
|
+ return this.sendParticlesSource(null, parameters, force, important, x, y, z, count, offsetX, offsetY, offsetZ, speed); // CraftBukkit - visibility api support
|
|
+ }
|
|
+
|
|
+ // CraftBukkit start - visibility api support
|
|
+ public <T extends ParticleOptions> int sendParticlesSource(ServerPlayer sender, T t0, boolean flag, boolean flag1, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6) {
|
|
+ // CraftBukkit end
|
|
+ ClientboundLevelParticlesPacket packetplayoutworldparticles = new ClientboundLevelParticlesPacket(t0, flag, flag1, d0, d1, d2, (float) d3, (float) d4, (float) d5, (float) d6, i);
|
|
int j = 0;
|
|
|
|
for (int k = 0; k < this.players.size(); ++k) {
|
|
ServerPlayer entityplayer = (ServerPlayer) this.players.get(k);
|
|
+ if (sender != null && !entityplayer.getBukkitEntity().canSee(sender.getBukkitEntity())) continue; // CraftBukkit
|
|
|
|
- if (this.sendParticles(entityplayer, force, x, y, z, packetplayoutworldparticles)) {
|
|
+ if (this.sendParticles(entityplayer, flag, d0, d1, d2, packetplayoutworldparticles)) {
|
|
++j;
|
|
}
|
|
}
|
|
@@ -1292,7 +1610,7 @@
|
|
|
|
@Nullable
|
|
public BlockPos findNearestMapStructure(TagKey<Structure> structureTag, BlockPos pos, int radius, boolean skipReferencedStructures) {
|
|
- if (!this.server.getWorldData().worldGenOptions().generateStructures()) {
|
|
+ if (!this.serverLevelData.worldGenOptions().generateStructures()) { // CraftBukkit
|
|
return null;
|
|
} else {
|
|
Optional<HolderSet.Named<Structure>> optional = this.registryAccess().lookupOrThrow(Registries.STRUCTURE).get(structureTag);
|
|
@@ -1334,11 +1652,22 @@
|
|
@Nullable
|
|
@Override
|
|
public MapItemSavedData getMapData(MapId id) {
|
|
- return (MapItemSavedData) this.getServer().overworld().getDataStorage().get(MapItemSavedData.factory(), id.key());
|
|
+ // CraftBukkit start
|
|
+ MapItemSavedData worldmap = (MapItemSavedData) this.getServer().overworld().getDataStorage().get(MapItemSavedData.factory(), id.key());
|
|
+ if (worldmap != null) {
|
|
+ worldmap.id = id;
|
|
+ }
|
|
+ return worldmap;
|
|
+ // CraftBukkit end
|
|
}
|
|
|
|
@Override
|
|
public void setMapData(MapId id, MapItemSavedData state) {
|
|
+ // CraftBukkit start
|
|
+ state.id = id;
|
|
+ MapInitializeEvent event = new MapInitializeEvent(state.mapView);
|
|
+ Bukkit.getServer().getPluginManager().callEvent(event);
|
|
+ // CraftBukkit end
|
|
this.getServer().overworld().getDataStorage().set(id.key(), state);
|
|
}
|
|
|
|
@@ -1649,6 +1978,11 @@
|
|
@Override
|
|
public void blockUpdated(BlockPos pos, Block block) {
|
|
if (!this.isDebug()) {
|
|
+ // CraftBukkit start
|
|
+ if (this.populating) {
|
|
+ return;
|
|
+ }
|
|
+ // CraftBukkit end
|
|
this.updateNeighborsAt(pos, block);
|
|
}
|
|
|
|
@@ -1668,12 +2002,12 @@
|
|
}
|
|
|
|
public boolean isFlat() {
|
|
- return this.server.getWorldData().isFlatWorld();
|
|
+ return this.serverLevelData.isFlatWorld(); // CraftBukkit
|
|
}
|
|
|
|
@Override
|
|
public long getSeed() {
|
|
- return this.server.getWorldData().worldGenOptions().seed();
|
|
+ return this.serverLevelData.worldGenOptions().seed(); // CraftBukkit
|
|
}
|
|
|
|
@Nullable
|
|
@@ -1696,7 +2030,7 @@
|
|
private static <T> String getTypeCount(Iterable<T> items, Function<T, String> classifier) {
|
|
try {
|
|
Object2IntOpenHashMap<String> object2intopenhashmap = new Object2IntOpenHashMap();
|
|
- Iterator iterator = items.iterator();
|
|
+ Iterator<T> iterator = items.iterator(); // CraftBukkit - decompile error
|
|
|
|
while (iterator.hasNext()) {
|
|
T t0 = iterator.next();
|
|
@@ -1705,7 +2039,7 @@
|
|
object2intopenhashmap.addTo(s, 1);
|
|
}
|
|
|
|
- return (String) object2intopenhashmap.object2IntEntrySet().stream().sorted(Comparator.comparing(Entry::getIntValue).reversed()).limit(5L).map((entry) -> {
|
|
+ return (String) object2intopenhashmap.object2IntEntrySet().stream().sorted(Comparator.comparing(Entry<String>::getIntValue).reversed()).limit(5L).map((entry) -> { // CraftBukkit - decompile error
|
|
String s1 = (String) entry.getKey();
|
|
|
|
return s1 + ":" + entry.getIntValue();
|
|
@@ -1717,6 +2051,7 @@
|
|
|
|
@Override
|
|
public LevelEntityGetter<Entity> getEntities() {
|
|
+ org.spigotmc.AsyncCatcher.catchOp("Chunk getEntities call"); // Spigot
|
|
return this.entityManager.getEntityGetter();
|
|
}
|
|
|
|
@@ -1802,6 +2137,17 @@
|
|
return this.serverLevelData.getGameRules();
|
|
}
|
|
|
|
+ // Paper start - respect global sound events gamerule
|
|
+ public List<net.minecraft.server.level.ServerPlayer> getPlayersForGlobalSoundGamerule() {
|
|
+ return this.getGameRules().getBoolean(GameRules.RULE_GLOBAL_SOUND_EVENTS) ? ((ServerLevel) this).getServer().getPlayerList().players : ((ServerLevel) this).players();
|
|
+ }
|
|
+
|
|
+ public double getGlobalSoundRangeSquared(java.util.function.Function<org.spigotmc.SpigotWorldConfig, Integer> rangeFunction) {
|
|
+ final double range = rangeFunction.apply(this.spigotConfig);
|
|
+ return range <= 0 ? 64.0 * 64.0 : range * range; // 64 is taken from default in ServerLevel#levelEvent
|
|
+ }
|
|
+ // Paper end - respect global sound events gamerule
|
|
+
|
|
@Override
|
|
public CrashReportCategory fillReportDetails(CrashReport report) {
|
|
CrashReportCategory crashreportsystemdetails = super.fillReportDetails(report);
|
|
@@ -1836,6 +2182,7 @@
|
|
}
|
|
|
|
public void onTrackingStart(Entity entity) {
|
|
+ org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot
|
|
ServerLevel.this.getChunkSource().addEntity(entity);
|
|
if (entity instanceof ServerPlayer entityplayer) {
|
|
ServerLevel.this.players.add(entityplayer);
|
|
@@ -1864,9 +2211,52 @@
|
|
}
|
|
|
|
entity.updateDynamicGameEventListener(DynamicGameEventListener::add);
|
|
+ entity.inWorld = true; // CraftBukkit - Mark entity as in world
|
|
+ entity.valid = true; // CraftBukkit
|
|
+ // Paper start - Entity origin API
|
|
+ if (entity.getOriginVector() == null) {
|
|
+ entity.setOrigin(entity.getBukkitEntity().getLocation());
|
|
+ }
|
|
+ // Default to current world if unknown, gross assumption but entities rarely change world
|
|
+ if (entity.getOriginWorld() == null) {
|
|
+ entity.setOrigin(entity.getOriginVector().toLocation(getWorld()));
|
|
+ }
|
|
+ // Paper end - Entity origin API
|
|
+ new com.destroystokyo.paper.event.entity.EntityAddToWorldEvent(entity.getBukkitEntity(), ServerLevel.this.getWorld()).callEvent(); // Paper - fire while valid
|
|
}
|
|
|
|
public void onTrackingEnd(Entity entity) {
|
|
+ org.spigotmc.AsyncCatcher.catchOp("entity unregister"); // Spigot
|
|
+ // Spigot start
|
|
+ if ( entity instanceof Player )
|
|
+ {
|
|
+ com.google.common.collect.Streams.stream( ServerLevel.this.getServer().getAllLevels() ).map( ServerLevel::getDataStorage ).forEach( (worldData) ->
|
|
+ {
|
|
+ for (Object o : worldData.cache.values() )
|
|
+ {
|
|
+ if ( o instanceof MapItemSavedData )
|
|
+ {
|
|
+ MapItemSavedData map = (MapItemSavedData) o;
|
|
+ map.carriedByPlayers.remove( (Player) entity );
|
|
+ for ( Iterator<MapItemSavedData.HoldingPlayer> iter = (Iterator<MapItemSavedData.HoldingPlayer>) map.carriedBy.iterator(); iter.hasNext(); )
|
|
+ {
|
|
+ if ( iter.next().player == entity )
|
|
+ {
|
|
+ iter.remove();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ } );
|
|
+ }
|
|
+ // Spigot end
|
|
+ // Spigot Start
|
|
+ if (entity.getBukkitEntity() instanceof org.bukkit.inventory.InventoryHolder && (!(entity instanceof ServerPlayer) || entity.getRemovalReason() != Entity.RemovalReason.KILLED)) { // SPIGOT-6876: closeInventory clears death message
|
|
+ for (org.bukkit.entity.HumanEntity h : Lists.newArrayList(((org.bukkit.inventory.InventoryHolder) entity.getBukkitEntity()).getInventory().getViewers())) {
|
|
+ h.closeInventory();
|
|
+ }
|
|
+ }
|
|
+ // Spigot End
|
|
ServerLevel.this.getChunkSource().removeEntity(entity);
|
|
if (entity instanceof ServerPlayer entityplayer) {
|
|
ServerLevel.this.players.remove(entityplayer);
|
|
@@ -1895,6 +2285,15 @@
|
|
}
|
|
|
|
entity.updateDynamicGameEventListener(DynamicGameEventListener::remove);
|
|
+ // CraftBukkit start
|
|
+ entity.valid = false;
|
|
+ if (!(entity instanceof ServerPlayer)) {
|
|
+ for (ServerPlayer player : ServerLevel.this.players) {
|
|
+ player.getBukkitEntity().onEntityRemove(entity);
|
|
+ }
|
|
+ }
|
|
+ // CraftBukkit end
|
|
+ new com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent(entity.getBukkitEntity(), ServerLevel.this.getWorld()).callEvent(); // Paper - fire while valid
|
|
}
|
|
|
|
public void onSectionChange(Entity entity) {
|