geforkt von Mirrors/Paper
net/minecraft/world/level
Dieser Commit ist enthalten in:
Ursprung
5deb3e9671
Commit
767215bf9b
@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/world/level/BaseCommandBlock.java
|
||||
+++ b/net/minecraft/world/level/BaseCommandBlock.java
|
||||
@@ -33,6 +33,10 @@
|
||||
@@ -32,6 +_,11 @@
|
||||
private String command = "";
|
||||
@Nullable
|
||||
private Component customName;
|
||||
@ -8,27 +8,28 @@
|
||||
+ @Override
|
||||
+ public abstract org.bukkit.command.CommandSender getBukkitSender(CommandSourceStack wrapper);
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
|
||||
public BaseCommandBlock() {}
|
||||
|
||||
@@ -132,7 +136,7 @@
|
||||
|
||||
});
|
||||
|
||||
- minecraftserver.getCommands().performPrefixedCommand(commandlistenerwrapper, this.command);
|
||||
+ minecraftserver.getCommands().dispatchServerCommand(commandlistenerwrapper, this.command); // CraftBukkit
|
||||
} catch (Throwable throwable) {
|
||||
CrashReport crashreport = CrashReport.forThrowable(throwable, "Executing command block");
|
||||
CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Command to be executed");
|
||||
@@ -174,6 +178,7 @@
|
||||
public int getSuccessCount() {
|
||||
return this.successCount;
|
||||
@@ -126,7 +_,7 @@
|
||||
this.successCount++;
|
||||
}
|
||||
});
|
||||
- server.getCommands().performPrefixedCommand(commandSourceStack, this.command);
|
||||
+ server.getCommands().dispatchServerCommand(commandSourceStack, this.command); // CraftBukkit
|
||||
} catch (Throwable var6) {
|
||||
CrashReport crashReport = CrashReport.forThrowable(var6, "Executing command block");
|
||||
CrashReportCategory crashReportCategory = crashReport.addCategory("Command to be executed");
|
||||
@@ -162,6 +_,7 @@
|
||||
@Override
|
||||
public void sendSystemMessage(Component message) {
|
||||
public void sendSystemMessage(Component component) {
|
||||
if (this.trackOutput) {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("sendSystemMessage to a command block"); // Paper - Don't broadcast messages to command blocks
|
||||
SimpleDateFormat simpledateformat = BaseCommandBlock.TIME_FORMAT;
|
||||
Date date = new Date();
|
||||
|
||||
@@ -200,7 +205,7 @@
|
||||
this.lastOutput = Component.literal("[" + TIME_FORMAT.format(new Date()) + "] ").append(component);
|
||||
this.onUpdated();
|
||||
}
|
||||
@@ -184,7 +_,7 @@
|
||||
}
|
||||
|
||||
public InteractionResult usedBy(Player player) {
|
@ -0,0 +1,156 @@
|
||||
--- a/net/minecraft/world/level/BaseSpawner.java
|
||||
+++ b/net/minecraft/world/level/BaseSpawner.java
|
||||
@@ -44,9 +_,11 @@
|
||||
public int maxNearbyEntities = 6;
|
||||
public int requiredPlayerRange = 16;
|
||||
public int spawnRange = 4;
|
||||
+ private int tickDelay = 0; // Paper - Configurable mob spawner tick rate
|
||||
|
||||
public void setEntityId(EntityType<?> type, @Nullable Level level, RandomSource random, BlockPos pos) {
|
||||
this.getOrCreateNextSpawnData(level, random, pos).getEntityToSpawn().putString("id", BuiltInRegistries.ENTITY_TYPE.getKey(type).toString());
|
||||
+ this.spawnPotentials = SimpleWeightedRandomList.empty(); // CraftBukkit - SPIGOT-3496, MC-92282
|
||||
}
|
||||
|
||||
public boolean isNearPlayer(Level level, BlockPos pos) {
|
||||
@@ -73,13 +_,19 @@
|
||||
}
|
||||
|
||||
public void serverTick(ServerLevel serverLevel, BlockPos pos) {
|
||||
+ if (spawnCount <= 0 || maxNearbyEntities <= 0) return; // Paper - Ignore impossible spawn tick
|
||||
+ // Paper start - Configurable mob spawner tick rate
|
||||
+ if (spawnDelay > 0 && --tickDelay > 0) return;
|
||||
+ tickDelay = serverLevel.paperConfig().tickRates.mobSpawner;
|
||||
+ if (tickDelay == -1) { return; } // If disabled
|
||||
+ // Paper end - Configurable mob spawner tick rate
|
||||
if (this.isNearPlayer(serverLevel, pos)) {
|
||||
- if (this.spawnDelay == -1) {
|
||||
+ if (this.spawnDelay < -tickDelay) { // Paper - Configurable mob spawner tick rate
|
||||
this.delay(serverLevel, pos);
|
||||
}
|
||||
|
||||
if (this.spawnDelay > 0) {
|
||||
- this.spawnDelay--;
|
||||
+ this.spawnDelay -= tickDelay; // Paper - Configurable mob spawner tick rate
|
||||
} else {
|
||||
boolean flag = false;
|
||||
RandomSource random = serverLevel.getRandom();
|
||||
@@ -113,6 +_,21 @@
|
||||
continue;
|
||||
}
|
||||
|
||||
+ // Paper start - PreCreatureSpawnEvent
|
||||
+ com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent event = new com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent(
|
||||
+ io.papermc.paper.util.MCUtil.toLocation(serverLevel, d, d1, d2),
|
||||
+ org.bukkit.craftbukkit.entity.CraftEntityType.minecraftToBukkit(optional.get()),
|
||||
+ io.papermc.paper.util.MCUtil.toLocation(serverLevel, pos)
|
||||
+ );
|
||||
+ if (!event.callEvent()) {
|
||||
+ flag = true;
|
||||
+ if (event.shouldAbortSpawn()) {
|
||||
+ break;
|
||||
+ }
|
||||
+ continue;
|
||||
+ }
|
||||
+ // Paper end - PreCreatureSpawnEvent
|
||||
+
|
||||
Entity entity = EntityType.loadEntityRecursive(entityToSpawn, serverLevel, EntitySpawnReason.SPAWNER, entity1 -> {
|
||||
entity1.moveTo(d, d1, d2, entity1.getYRot(), entity1.getXRot());
|
||||
return entity1;
|
||||
@@ -133,6 +_,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
+ entity.preserveMotion = true; // Paper - Fix Entity Teleportation and cancel velocity if teleported; preserve entity motion from tag
|
||||
entity.moveTo(entity.getX(), entity.getY(), entity.getZ(), random.nextFloat() * 360.0F, 0.0F);
|
||||
if (entity instanceof Mob mob) {
|
||||
if (nextSpawnData.getCustomSpawnRules().isEmpty() && !mob.checkSpawnRules(serverLevel, EntitySpawnReason.SPAWNER)
|
||||
@@ -147,9 +_,22 @@
|
||||
}
|
||||
|
||||
nextSpawnData.getEquipment().ifPresent(mob::equip);
|
||||
+ // Spigot Start
|
||||
+ if (mob.level().spigotConfig.nerfSpawnerMobs) {
|
||||
+ mob.aware = false;
|
||||
+ }
|
||||
+ // Spigot End
|
||||
}
|
||||
|
||||
- if (!serverLevel.tryAddFreshEntityWithPassengers(entity)) {
|
||||
+ entity.spawnedViaMobSpawner = true; // Paper
|
||||
+ entity.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER; // Paper - Entity#getEntitySpawnReason
|
||||
+ flag = true; // Paper
|
||||
+ // CraftBukkit start
|
||||
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callSpawnerSpawnEvent(entity, pos).isCancelled()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (!serverLevel.tryAddFreshEntityWithPassengers(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER)) {
|
||||
+ // CraftBukkit end
|
||||
this.delay(serverLevel, pos);
|
||||
return;
|
||||
}
|
||||
@@ -160,7 +_,7 @@
|
||||
((Mob)entity).spawnAnim();
|
||||
}
|
||||
|
||||
- flag = true;
|
||||
+ //flag = true; // Paper - moved up above cancellable event
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +_,13 @@
|
||||
}
|
||||
|
||||
public void load(@Nullable Level level, BlockPos pos, CompoundTag tag) {
|
||||
- this.spawnDelay = tag.getShort("Delay");
|
||||
+ // Paper start - use larger int if set
|
||||
+ if (tag.contains("Paper.Delay")) {
|
||||
+ this.spawnDelay = tag.getInt("Paper.Delay");
|
||||
+ } else {
|
||||
+ this.spawnDelay = tag.getShort("Delay");
|
||||
+ }
|
||||
+ // Paper end
|
||||
boolean flag = tag.contains("SpawnData", 10);
|
||||
if (flag) {
|
||||
SpawnData spawnData = SpawnData.CODEC
|
||||
@@ -205,9 +_,15 @@
|
||||
this.spawnPotentials = SimpleWeightedRandomList.single(this.nextSpawnData != null ? this.nextSpawnData : new SpawnData());
|
||||
}
|
||||
|
||||
+ // Paper start - use ints if set
|
||||
+ if (tag.contains("Paper.MinSpawnDelay", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) {
|
||||
+ this.minSpawnDelay = tag.getInt("Paper.MinSpawnDelay");
|
||||
+ this.maxSpawnDelay = tag.getInt("Paper.MaxSpawnDelay");
|
||||
+ this.spawnCount = tag.getShort("SpawnCount");
|
||||
+ } else // Paper end
|
||||
if (tag.contains("MinSpawnDelay", 99)) {
|
||||
- this.minSpawnDelay = tag.getShort("MinSpawnDelay");
|
||||
- this.maxSpawnDelay = tag.getShort("MaxSpawnDelay");
|
||||
+ this.minSpawnDelay = tag.getInt("MinSpawnDelay"); // Paper - short -> int
|
||||
+ this.maxSpawnDelay = tag.getInt("MaxSpawnDelay"); // Paper - short -> int
|
||||
this.spawnCount = tag.getShort("SpawnCount");
|
||||
}
|
||||
|
||||
@@ -224,9 +_,20 @@
|
||||
}
|
||||
|
||||
public CompoundTag save(CompoundTag tag) {
|
||||
- tag.putShort("Delay", (short)this.spawnDelay);
|
||||
- tag.putShort("MinSpawnDelay", (short)this.minSpawnDelay);
|
||||
- tag.putShort("MaxSpawnDelay", (short)this.maxSpawnDelay);
|
||||
+ // Paper start
|
||||
+ if (spawnDelay > Short.MAX_VALUE) {
|
||||
+ tag.putInt("Paper.Delay", this.spawnDelay);
|
||||
+ }
|
||||
+ tag.putShort("Delay", (short) Math.min(Short.MAX_VALUE, this.spawnDelay));
|
||||
+
|
||||
+ if (minSpawnDelay > Short.MAX_VALUE || maxSpawnDelay > Short.MAX_VALUE) {
|
||||
+ tag.putInt("Paper.MinSpawnDelay", this.minSpawnDelay);
|
||||
+ tag.putInt("Paper.MaxSpawnDelay", this.maxSpawnDelay);
|
||||
+ }
|
||||
+
|
||||
+ tag.putShort("MinSpawnDelay", (short) Math.min(Short.MAX_VALUE, this.minSpawnDelay));
|
||||
+ tag.putShort("MaxSpawnDelay", (short) Math.min(Short.MAX_VALUE, this.maxSpawnDelay));
|
||||
+ // Paper end
|
||||
tag.putShort("SpawnCount", (short)this.spawnCount);
|
||||
tag.putShort("MaxNearbyEntities", (short)this.maxNearbyEntities);
|
||||
tag.putShort("RequiredPlayerRange", (short)this.requiredPlayerRange);
|
@ -0,0 +1,76 @@
|
||||
--- a/net/minecraft/world/level/BlockGetter.java
|
||||
+++ b/net/minecraft/world/level/BlockGetter.java
|
||||
@@ -11,6 +_,7 @@
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.util.Mth;
|
||||
+import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
@@ -33,6 +_,16 @@
|
||||
|
||||
BlockState getBlockState(BlockPos pos);
|
||||
|
||||
+ // Paper start - if loaded util
|
||||
+ @Nullable BlockState getBlockStateIfLoaded(BlockPos blockposition);
|
||||
+
|
||||
+ default @Nullable Block getBlockIfLoaded(BlockPos blockposition) {
|
||||
+ BlockState type = this.getBlockStateIfLoaded(blockposition);
|
||||
+ return type == null ? null : type.getBlock();
|
||||
+ }
|
||||
+ @Nullable FluidState getFluidIfLoaded(BlockPos blockposition);
|
||||
+ // Paper end
|
||||
+
|
||||
FluidState getFluidState(BlockPos pos);
|
||||
|
||||
default int getLightEmission(BlockPos pos) {
|
||||
@@ -66,10 +_,25 @@
|
||||
);
|
||||
}
|
||||
|
||||
- default BlockHitResult clip(ClipContext context) {
|
||||
- return traverseBlocks(context.getFrom(), context.getTo(), context, (traverseContext, traversePos) -> {
|
||||
- BlockState blockState = this.getBlockState(traversePos);
|
||||
- FluidState fluidState = this.getFluidState(traversePos);
|
||||
+ // CraftBukkit start - moved block handling into separate method for use by Block#rayTrace
|
||||
+ default BlockHitResult clip(ClipContext raytrace1, BlockPos blockposition) {
|
||||
+ // Paper start - Add predicate for blocks when raytracing
|
||||
+ return clip(raytrace1, blockposition, null);
|
||||
+ }
|
||||
+
|
||||
+ default BlockHitResult clip(ClipContext traverseContext, BlockPos traversePos, java.util.function.Predicate<? super org.bukkit.block.Block> canCollide) {
|
||||
+ // Paper end - Add predicate for blocks when raytracing
|
||||
+ // Paper start - Prevent raytrace from loading chunks
|
||||
+ BlockState blockState = this.getBlockStateIfLoaded(traversePos);
|
||||
+ if (blockState == null) {
|
||||
+ // copied the last function parameter (listed below)
|
||||
+ Vec3 vec3d = traverseContext.getFrom().subtract(traverseContext.getTo());
|
||||
+
|
||||
+ return BlockHitResult.miss(traverseContext.getTo(), Direction.getApproximateNearest(vec3d.x, vec3d.y, vec3d.z), BlockPos.containing(raytrace1.getTo()));
|
||||
+ }
|
||||
+ // Paper end - Prevent raytrace from loading chunks
|
||||
+ if (blockState.isAir() || (canCollide != null && this instanceof LevelAccessor levelAccessor && !canCollide.test(org.bukkit.craftbukkit.block.CraftBlock.at(levelAccessor, blockposition)))) return null; // Paper - Perf: optimise air cases & check canCollide predicate
|
||||
+ FluidState fluidState = blockState.getFluidState(); // Paper - Perf: don't need to go to world state again
|
||||
Vec3 from = traverseContext.getFrom();
|
||||
Vec3 to = traverseContext.getTo();
|
||||
VoxelShape blockShape = traverseContext.getBlockShape(blockState, this, traversePos);
|
||||
@@ -79,6 +_,18 @@
|
||||
double d = blockHitResult == null ? Double.MAX_VALUE : traverseContext.getFrom().distanceToSqr(blockHitResult.getLocation());
|
||||
double d1 = blockHitResult1 == null ? Double.MAX_VALUE : traverseContext.getFrom().distanceToSqr(blockHitResult1.getLocation());
|
||||
return d <= d1 ? blockHitResult : blockHitResult1;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
+ default BlockHitResult clip(ClipContext context) {
|
||||
+ // Paper start - Add predicate for blocks when raytracing
|
||||
+ return clip(context, (java.util.function.Predicate<org.bukkit.block.Block>) null);
|
||||
+ }
|
||||
+
|
||||
+ default BlockHitResult clip(ClipContext context, java.util.function.Predicate<? super org.bukkit.block.Block> canCollide) {
|
||||
+ // Paper end - Add predicate for blocks when raytracing
|
||||
+ return (BlockHitResult) BlockGetter.traverseBlocks(context.getFrom(), context.getTo(), context, (raytrace1, blockposition) -> {
|
||||
+ return this.clip(raytrace1, blockposition, canCollide); // CraftBukkit - moved into separate method // Paper - Add predicate for blocks when raytracing
|
||||
}, failContext -> {
|
||||
Vec3 vec3 = failContext.getFrom().subtract(failContext.getTo());
|
||||
return BlockHitResult.miss(failContext.getTo(), Direction.getApproximateNearest(vec3.x, vec3.y, vec3.z), BlockPos.containing(failContext.getTo()));
|
@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/world/level/ChunkPos.java
|
||||
+++ b/net/minecraft/world/level/ChunkPos.java
|
||||
@@ -46,6 +46,7 @@
|
||||
@@ -46,6 +_,7 @@
|
||||
public static final int REGION_MAX_INDEX = 31;
|
||||
public final int x;
|
||||
public final int z;
|
||||
@ -8,10 +8,10 @@
|
||||
private static final int HASH_A = 1664525;
|
||||
private static final int HASH_C = 1013904223;
|
||||
private static final int HASH_Z_XOR = -559038737;
|
||||
@@ -53,16 +54,19 @@
|
||||
public ChunkPos(int x, int z) {
|
||||
@@ -53,16 +_,19 @@
|
||||
public ChunkPos(int x, int y) {
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
this.z = y;
|
||||
+ this.longKey = asLong(this.x, this.z); // Paper
|
||||
}
|
||||
|
||||
@ -21,19 +21,10 @@
|
||||
+ this.longKey = asLong(this.x, this.z); // Paper
|
||||
}
|
||||
|
||||
public ChunkPos(long pos) {
|
||||
this.x = (int)pos;
|
||||
this.z = (int)(pos >> 32);
|
||||
public ChunkPos(long packedPos) {
|
||||
this.x = (int)packedPos;
|
||||
this.z = (int)(packedPos >> 32);
|
||||
+ this.longKey = asLong(this.x, this.z); // Paper
|
||||
}
|
||||
|
||||
public static ChunkPos minFromRegion(int x, int z) {
|
||||
@@ -74,7 +78,7 @@
|
||||
}
|
||||
|
||||
public long toLong() {
|
||||
- return asLong(this.x, this.z);
|
||||
+ return longKey; // Paper
|
||||
}
|
||||
|
||||
public static long asLong(int chunkX, int chunkZ) {
|
||||
public static ChunkPos minFromRegion(int chunkX, int chunkZ) {
|
@ -0,0 +1,11 @@
|
||||
--- a/net/minecraft/world/level/ClipContext.java
|
||||
+++ b/net/minecraft/world/level/ClipContext.java
|
||||
@@ -21,7 +_,7 @@
|
||||
private final CollisionContext collisionContext;
|
||||
|
||||
public ClipContext(Vec3 from, Vec3 to, ClipContext.Block block, ClipContext.Fluid fluid, Entity entity) {
|
||||
- this(from, to, block, fluid, CollisionContext.of(entity));
|
||||
+ this(from, to, block, fluid, (entity == null) ? CollisionContext.empty() : CollisionContext.of(entity)); // CraftBukkit
|
||||
}
|
||||
|
||||
public ClipContext(Vec3 from, Vec3 to, ClipContext.Block block, ClipContext.Fluid fluid, CollisionContext collisionContext) {
|
@ -1,11 +1,11 @@
|
||||
--- a/net/minecraft/world/level/EmptyBlockGetter.java
|
||||
+++ b/net/minecraft/world/level/EmptyBlockGetter.java
|
||||
@@ -17,7 +17,19 @@
|
||||
@@ -17,6 +_,18 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
+ // Paper start - If loaded util
|
||||
@Override
|
||||
+ @Override
|
||||
+ public final FluidState getFluidIfLoaded(BlockPos blockposition) {
|
||||
+ return Fluids.EMPTY.defaultFluidState();
|
||||
+ }
|
||||
@ -16,7 +16,6 @@
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
+ @Override
|
||||
@Override
|
||||
public BlockState getBlockState(BlockPos pos) {
|
||||
return Blocks.AIR.defaultBlockState();
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/world/level/EntityGetter.java
|
||||
+++ b/net/minecraft/world/level/EntityGetter.java
|
||||
@@ -71,6 +71,11 @@
|
||||
@@ -71,6 +_,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,10 +9,11 @@
|
||||
+ return this.getNearestPlayer(entity.getX(), entity.getY(), entity.getZ(), maxDistance, predicate);
|
||||
+ }
|
||||
+ // Paper end - Affects Spawning API
|
||||
+
|
||||
@Nullable
|
||||
default Player getNearestPlayer(double x, double y, double z, double maxDistance, @Nullable Predicate<Entity> targetPredicate) {
|
||||
default Player getNearestPlayer(double x, double y, double z, double distance, @Nullable Predicate<Entity> predicate) {
|
||||
double d = -1.0;
|
||||
@@ -89,6 +94,28 @@
|
||||
@@ -89,6 +_,28 @@
|
||||
return player;
|
||||
}
|
||||
|
||||
@ -39,10 +40,10 @@
|
||||
+ // Paper end
|
||||
+
|
||||
@Nullable
|
||||
default Player getNearestPlayer(Entity entity, double maxDistance) {
|
||||
return this.getNearestPlayer(entity.getX(), entity.getY(), entity.getZ(), maxDistance, false);
|
||||
@@ -100,6 +127,20 @@
|
||||
return this.getNearestPlayer(x, y, z, maxDistance, predicate);
|
||||
default Player getNearestPlayer(Entity entity, double distance) {
|
||||
return this.getNearestPlayer(entity.getX(), entity.getY(), entity.getZ(), distance, false);
|
||||
@@ -100,6 +_,20 @@
|
||||
return this.getNearestPlayer(x, y, z, distance, predicate);
|
||||
}
|
||||
|
||||
+ // Paper start - Affects Spawning API
|
||||
@ -59,10 +60,10 @@
|
||||
+ }
|
||||
+ // Paper end - Affects Spawning API
|
||||
+
|
||||
default boolean hasNearbyAlivePlayer(double x, double y, double z, double range) {
|
||||
default boolean hasNearbyAlivePlayer(double x, double y, double z, double distance) {
|
||||
for (Player player : this.players()) {
|
||||
if (EntitySelector.NO_SPECTATORS.test(player) && EntitySelector.LIVING_ENTITY_STILL_ALIVE.test(player)) {
|
||||
@@ -124,4 +165,11 @@
|
||||
@@ -124,4 +_,11 @@
|
||||
|
||||
return null;
|
||||
}
|
@ -0,0 +1,298 @@
|
||||
--- a/net/minecraft/world/level/GameRules.java
|
||||
+++ b/net/minecraft/world/level/GameRules.java
|
||||
@@ -32,6 +_,14 @@
|
||||
import org.slf4j.Logger;
|
||||
|
||||
public class GameRules {
|
||||
+ // Paper start - allow disabling gamerule limits
|
||||
+ private static final boolean DISABLE_LIMITS = Boolean.getBoolean("paper.disableGameRuleLimits");
|
||||
+
|
||||
+ private static int limit(final int limit, final int unlimited) {
|
||||
+ return DISABLE_LIMITS ? unlimited : limit;
|
||||
+ }
|
||||
+ // Paper end - allow disabling gamerule limits
|
||||
+
|
||||
public static final int DEFAULT_RANDOM_TICK_SPEED = 3;
|
||||
static final Logger LOGGER = LogUtils.getLogger();
|
||||
private static final Map<GameRules.Key<?>, GameRules.Type<?>> GAME_RULE_TYPES = Maps.newTreeMap(Comparator.comparing(entry -> entry.id));
|
||||
@@ -81,10 +_,10 @@
|
||||
"sendCommandFeedback", GameRules.Category.CHAT, GameRules.BooleanValue.create(true)
|
||||
);
|
||||
public static final GameRules.Key<GameRules.BooleanValue> RULE_REDUCEDDEBUGINFO = register(
|
||||
- "reducedDebugInfo", GameRules.Category.MISC, GameRules.BooleanValue.create(false, (server, value) -> {
|
||||
+ "reducedDebugInfo", GameRules.Category.MISC, GameRules.BooleanValue.create(false, (level, value) -> { // Paper - rename param to match changes
|
||||
byte b = (byte)(value.get() ? 22 : 23);
|
||||
|
||||
- for (ServerPlayer serverPlayer : server.getPlayerList().getPlayers()) {
|
||||
+ for (ServerPlayer serverPlayer : level.players()) {
|
||||
serverPlayer.connection.send(new ClientboundEntityEventPacket(serverPlayer, b));
|
||||
}
|
||||
})
|
||||
@@ -108,8 +_,8 @@
|
||||
"doWeatherCycle", GameRules.Category.UPDATES, GameRules.BooleanValue.create(true)
|
||||
);
|
||||
public static final GameRules.Key<GameRules.BooleanValue> RULE_LIMITED_CRAFTING = register(
|
||||
- "doLimitedCrafting", GameRules.Category.PLAYER, GameRules.BooleanValue.create(false, (server, value) -> {
|
||||
- for (ServerPlayer serverPlayer : server.getPlayerList().getPlayers()) {
|
||||
+ "doLimitedCrafting", GameRules.Category.PLAYER, GameRules.BooleanValue.create(false, (level, value) -> { // Paper - rename param to match changes
|
||||
+ for (ServerPlayer serverPlayer : level.players()) {
|
||||
serverPlayer.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.LIMITED_CRAFTING, value.get() ? 1.0F : 0.0F));
|
||||
}
|
||||
})
|
||||
@@ -133,8 +_,8 @@
|
||||
"doInsomnia", GameRules.Category.SPAWNING, GameRules.BooleanValue.create(true)
|
||||
);
|
||||
public static final GameRules.Key<GameRules.BooleanValue> RULE_DO_IMMEDIATE_RESPAWN = register(
|
||||
- "doImmediateRespawn", GameRules.Category.PLAYER, GameRules.BooleanValue.create(false, (server, value) -> {
|
||||
- for (ServerPlayer serverPlayer : server.getPlayerList().getPlayers()) {
|
||||
+ "doImmediateRespawn", GameRules.Category.PLAYER, GameRules.BooleanValue.create(false, (level, value) -> { // Paper - rename param to match changes
|
||||
+ for (ServerPlayer serverPlayer : level.players()) {
|
||||
serverPlayer.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.IMMEDIATE_RESPAWN, value.get() ? 1.0F : 0.0F));
|
||||
}
|
||||
})
|
||||
@@ -205,16 +_,17 @@
|
||||
public static final GameRules.Key<GameRules.IntegerValue> RULE_MINECART_MAX_SPEED = register(
|
||||
"minecartMaxSpeed",
|
||||
GameRules.Category.MISC,
|
||||
- GameRules.IntegerValue.create(8, 1, 1000, FeatureFlagSet.of(FeatureFlags.MINECART_IMPROVEMENTS), (server, value) -> {})
|
||||
+ GameRules.IntegerValue.create(8, 1, limit(1000, Integer.MAX_VALUE), FeatureFlagSet.of(FeatureFlags.MINECART_IMPROVEMENTS), (server, value) -> {}) // Paper - allow disabling gamerule limits
|
||||
);
|
||||
public static final GameRules.Key<GameRules.IntegerValue> RULE_SPAWN_CHUNK_RADIUS = register(
|
||||
- "spawnChunkRadius", GameRules.Category.MISC, GameRules.IntegerValue.create(2, 0, 32, FeatureFlagSet.of(), (server, value) -> {
|
||||
- ServerLevel serverLevel = server.overworld();
|
||||
+ "spawnChunkRadius", GameRules.Category.MISC, GameRules.IntegerValue.create(2, 0, limit(32, Integer.MAX_VALUE), FeatureFlagSet.of(), (level, value) -> { // Paper - allow disabling gamerule limits - also, rename param
|
||||
+ ServerLevel serverLevel = level; // CraftBukkit - per-world
|
||||
serverLevel.setDefaultSpawnPos(serverLevel.getSharedSpawnPos(), serverLevel.getSharedSpawnAngle());
|
||||
})
|
||||
);
|
||||
private final Map<GameRules.Key<?>, GameRules.Value<?>> rules;
|
||||
private final FeatureFlagSet enabledFeatures;
|
||||
+ private final GameRules.Value<?>[] gameruleArray; // Paper - Perf: Use array for gamerule storage
|
||||
|
||||
private static <T extends GameRules.Value<T>> GameRules.Key<T> register(String name, GameRules.Category category, GameRules.Type<T> type) {
|
||||
GameRules.Key<T> key = new GameRules.Key<>(name, category);
|
||||
@@ -242,10 +_,21 @@
|
||||
private GameRules(Map<GameRules.Key<?>, GameRules.Value<?>> rules, FeatureFlagSet enabledFeatures) {
|
||||
this.rules = rules;
|
||||
this.enabledFeatures = enabledFeatures;
|
||||
+
|
||||
+ // Paper start - Perf: Use array for gamerule storage
|
||||
+ int arraySize = GameRules.Key.lastGameRuleIndex + 1;
|
||||
+ GameRules.Value<?>[] values = new GameRules.Value[arraySize];
|
||||
+
|
||||
+ for (Entry<GameRules.Key<?>, GameRules.Value<?>> entry : rules.entrySet()) {
|
||||
+ values[entry.getKey().gameRuleIndex] = entry.getValue();
|
||||
+ }
|
||||
+
|
||||
+ this.gameruleArray = values;
|
||||
+ // Paper end - Perf: Use array for gamerule storage
|
||||
}
|
||||
|
||||
public <T extends GameRules.Value<T>> T getRule(GameRules.Key<T> key) {
|
||||
- T value = (T)this.rules.get(key);
|
||||
+ T value = key == null ? null : (T) this.gameruleArray[key.gameRuleIndex]; // Paper - Perf: Use array for gamerule storage
|
||||
if (value == null) {
|
||||
throw new IllegalArgumentException("Tried to access invalid game rule");
|
||||
} else {
|
||||
@@ -286,13 +_,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
- public void assignFrom(GameRules rules, @Nullable MinecraftServer server) {
|
||||
- rules.rules.keySet().forEach(key -> this.assignCap((GameRules.Key<?>)key, rules, server));
|
||||
+ public void assignFrom(GameRules rules, @Nullable ServerLevel level) { // CraftBukkit - per-world
|
||||
+ rules.rules.keySet().forEach(key -> this.assignCap((GameRules.Key<?>)key, rules, level)); // CraftBukkit - per-world
|
||||
}
|
||||
|
||||
- private <T extends GameRules.Value<T>> void assignCap(GameRules.Key<T> key, GameRules rules, @Nullable MinecraftServer server) {
|
||||
+ private <T extends GameRules.Value<T>> void assignCap(GameRules.Key<T> key, GameRules rules, @Nullable ServerLevel level) { // CraftBukkit - per-world
|
||||
T rule = rules.getRule(key);
|
||||
- this.<T>getRule(key).setFrom(rule, server);
|
||||
+ this.<T>getRule(key).setFrom(rule, level); // CraftBukkit - per-world
|
||||
}
|
||||
|
||||
public boolean getBoolean(GameRules.Key<GameRules.BooleanValue> key) {
|
||||
@@ -306,7 +_,7 @@
|
||||
public static class BooleanValue extends GameRules.Value<GameRules.BooleanValue> {
|
||||
private boolean value;
|
||||
|
||||
- static GameRules.Type<GameRules.BooleanValue> create(boolean defaultValue, BiConsumer<MinecraftServer, GameRules.BooleanValue> changeListener) {
|
||||
+ static GameRules.Type<GameRules.BooleanValue> create(boolean defaultValue, BiConsumer<ServerLevel, GameRules.BooleanValue> changeListener) { // CraftBukkit - per-world
|
||||
return new GameRules.Type<>(
|
||||
BoolArgumentType::bool,
|
||||
type -> new GameRules.BooleanValue(type, defaultValue),
|
||||
@@ -326,17 +_,21 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
- protected void updateFromArgument(CommandContext<CommandSourceStack> context, String paramName) {
|
||||
- this.value = BoolArgumentType.getBool(context, paramName);
|
||||
+ // Paper start - Add WorldGameRuleChangeEvent
|
||||
+ protected void updateFromArgument(CommandContext<CommandSourceStack> context, String paramName, GameRules.Key<BooleanValue> gameRuleKey) {
|
||||
+ io.papermc.paper.event.world.WorldGameRuleChangeEvent event = new io.papermc.paper.event.world.WorldGameRuleChangeEvent(context.getSource().getBukkitWorld(), context.getSource().getBukkitSender(), (org.bukkit.GameRule<Boolean>) org.bukkit.GameRule.getByName(gameRuleKey.toString()), String.valueOf(BoolArgumentType.getBool(context, paramName)));
|
||||
+ if (!event.callEvent()) return;
|
||||
+ this.value = Boolean.parseBoolean(event.getValue());
|
||||
+ // Paper end - Add WorldGameRuleChangeEvent
|
||||
}
|
||||
|
||||
public boolean get() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
- public void set(boolean value, @Nullable MinecraftServer server) {
|
||||
+ public void set(boolean value, @Nullable ServerLevel level) { // CraftBukkit - per-world
|
||||
this.value = value;
|
||||
- this.onChanged(server);
|
||||
+ this.onChanged(level); // CraftBukkit - per-world
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -345,7 +_,7 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
- protected void deserialize(String value) {
|
||||
+ public void deserialize(String value) { // PAIL - protected->public
|
||||
this.value = Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
@@ -365,9 +_,9 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
- public void setFrom(GameRules.BooleanValue value, @Nullable MinecraftServer server) {
|
||||
+ public void setFrom(GameRules.BooleanValue value, @Nullable ServerLevel level) { // CraftBukkit - per-world
|
||||
this.value = value.value;
|
||||
- this.onChanged(server);
|
||||
+ this.onChanged(level); // CraftBukkit - per-world
|
||||
}
|
||||
}
|
||||
|
||||
@@ -405,7 +_,7 @@
|
||||
public static class IntegerValue extends GameRules.Value<GameRules.IntegerValue> {
|
||||
private int value;
|
||||
|
||||
- private static GameRules.Type<GameRules.IntegerValue> create(int defaultValue, BiConsumer<MinecraftServer, GameRules.IntegerValue> changeListener) {
|
||||
+ private static GameRules.Type<GameRules.IntegerValue> create(int defaultValue, BiConsumer<ServerLevel, GameRules.IntegerValue> changeListener) { // CraftBukkit - per-world
|
||||
return new GameRules.Type<>(
|
||||
IntegerArgumentType::integer,
|
||||
type -> new GameRules.IntegerValue(type, defaultValue),
|
||||
@@ -416,7 +_,7 @@
|
||||
}
|
||||
|
||||
static GameRules.Type<GameRules.IntegerValue> create(
|
||||
- int defaultValue, int min, int max, FeatureFlagSet requiredFeatures, BiConsumer<MinecraftServer, GameRules.IntegerValue> changeListener
|
||||
+ int defaultValue, int min, int max, FeatureFlagSet requiredFeatures, BiConsumer<ServerLevel, GameRules.IntegerValue> changeListener // CraftBukkit - per-world
|
||||
) {
|
||||
return new GameRules.Type<>(
|
||||
() -> IntegerArgumentType.integer(min, max),
|
||||
@@ -437,17 +_,21 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
- protected void updateFromArgument(CommandContext<CommandSourceStack> context, String paramName) {
|
||||
- this.value = IntegerArgumentType.getInteger(context, paramName);
|
||||
+ // Paper start - Add WorldGameRuleChangeEvent
|
||||
+ protected void updateFromArgument(CommandContext<CommandSourceStack> context, String paramName, GameRules.Key<IntegerValue> gameRuleKey) {
|
||||
+ io.papermc.paper.event.world.WorldGameRuleChangeEvent event = new io.papermc.paper.event.world.WorldGameRuleChangeEvent(context.getSource().getBukkitWorld(), context.getSource().getBukkitSender(), (org.bukkit.GameRule<Integer>) org.bukkit.GameRule.getByName(gameRuleKey.toString()), String.valueOf(IntegerArgumentType.getInteger(context, paramName)));
|
||||
+ if (!event.callEvent()) return;
|
||||
+ this.value = Integer.parseInt(event.getValue());
|
||||
+ // Paper end - Add WorldGameRuleChangeEvent
|
||||
}
|
||||
|
||||
public int get() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
- public void set(int value, @Nullable MinecraftServer server) {
|
||||
+ public void set(int value, @Nullable ServerLevel level) { // CraftBukkit - per-world
|
||||
this.value = value;
|
||||
- this.onChanged(server);
|
||||
+ this.onChanged(level) ;// CraftBukkit - per-world
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -456,7 +_,7 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
- protected void deserialize(String value) {
|
||||
+ public void deserialize(String value) { // PAIL - protected->public
|
||||
this.value = safeParse(value);
|
||||
}
|
||||
|
||||
@@ -498,13 +_,17 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
- public void setFrom(GameRules.IntegerValue value, @Nullable MinecraftServer server) {
|
||||
+ public void setFrom(GameRules.IntegerValue value, @Nullable ServerLevel level) { // CraftBukkit - per-world
|
||||
this.value = value.value;
|
||||
- this.onChanged(server);
|
||||
+ this.onChanged(level); // CraftBukkit - per-world
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Key<T extends GameRules.Value<T>> {
|
||||
+ // Paper start - Perf: Use array for gamerule storage
|
||||
+ public static int lastGameRuleIndex = 0;
|
||||
+ public final int gameRuleIndex = lastGameRuleIndex++;
|
||||
+ // Paper end - Perf: Use array for gamerule storage
|
||||
final String id;
|
||||
private final GameRules.Category category;
|
||||
|
||||
@@ -544,14 +_,14 @@
|
||||
public static class Type<T extends GameRules.Value<T>> {
|
||||
final Supplier<ArgumentType<?>> argument;
|
||||
private final Function<GameRules.Type<T>, T> constructor;
|
||||
- final BiConsumer<MinecraftServer, T> callback;
|
||||
+ final BiConsumer<ServerLevel, T> callback; // CraftBukkit - per-world
|
||||
private final GameRules.VisitorCaller<T> visitorCaller;
|
||||
final FeatureFlagSet requiredFeatures;
|
||||
|
||||
Type(
|
||||
Supplier<ArgumentType<?>> argument,
|
||||
Function<GameRules.Type<T>, T> constructor,
|
||||
- BiConsumer<MinecraftServer, T> callback,
|
||||
+ BiConsumer<ServerLevel, T> callback, // CraftBukkit - per-world
|
||||
GameRules.VisitorCaller<T> visitorCaller,
|
||||
FeatureFlagSet requiredFeature
|
||||
) {
|
||||
@@ -586,20 +_,20 @@
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
- protected abstract void updateFromArgument(CommandContext<CommandSourceStack> context, String paramName);
|
||||
+ protected abstract void updateFromArgument(CommandContext<CommandSourceStack> context, String paramName, GameRules.Key<T> gameRuleKey); // Paper - Add WorldGameRuleChangeEvent
|
||||
|
||||
- public void setFromArgument(CommandContext<CommandSourceStack> context, String paramName) {
|
||||
- this.updateFromArgument(context, paramName);
|
||||
- this.onChanged(context.getSource().getServer());
|
||||
+ public void setFromArgument(CommandContext<CommandSourceStack> context, String paramName, GameRules.Key<T> gameRuleKey) { // Paper - Add WorldGameRuleChangeEvent
|
||||
+ this.updateFromArgument(context, paramName, gameRuleKey); // Paper - Add WorldGameRuleChangeEvent
|
||||
+ this.onChanged(context.getSource().getLevel());
|
||||
}
|
||||
|
||||
- public void onChanged(@Nullable MinecraftServer server) {
|
||||
- if (server != null) {
|
||||
- this.type.callback.accept(server, this.getSelf());
|
||||
+ public void onChanged(@Nullable ServerLevel level) { // CraftBukkit - per-world
|
||||
+ if (level != null) { // CraftBukkit - per-world
|
||||
+ this.type.callback.accept(level, this.getSelf()); // CraftBukkit - per-world
|
||||
}
|
||||
}
|
||||
|
||||
- protected abstract void deserialize(String value);
|
||||
+ public abstract void deserialize(String value); // PAIL - private->public
|
||||
|
||||
public abstract String serialize();
|
||||
|
||||
@@ -614,7 +_,7 @@
|
||||
|
||||
protected abstract T copy();
|
||||
|
||||
- public abstract void setFrom(T value, @Nullable MinecraftServer server);
|
||||
+ public abstract void setFrom(T value, @Nullable ServerLevel level); // CraftBukkit - per-world
|
||||
}
|
||||
|
||||
interface VisitorCaller<T extends GameRules.Value<T>> {
|
@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
+++ b/net/minecraft/world/level/Level.java
|
||||
@@ -25,8 +25,10 @@
|
||||
@@ -24,8 +_,10 @@
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
@ -11,7 +11,7 @@
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
@@ -43,6 +45,7 @@
|
||||
@@ -42,6 +_,7 @@
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.boss.EnderDragonPart;
|
||||
import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
|
||||
@ -19,22 +19,7 @@
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.alchemy.PotionBrewing;
|
||||
@@ -57,12 +60,14 @@
|
||||
import net.minecraft.world.level.block.entity.FuelValues;
|
||||
import net.minecraft.world.level.block.entity.TickingBlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
+import net.minecraft.world.level.border.BorderChangeListener;
|
||||
import net.minecraft.world.level.border.WorldBorder;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ChunkSource;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
+import net.minecraft.world.level.dimension.LevelStem;
|
||||
import net.minecraft.world.level.entity.EntityTypeTest;
|
||||
import net.minecraft.world.level.entity.LevelEntityGetter;
|
||||
import net.minecraft.world.level.gameevent.GameEvent;
|
||||
@@ -81,6 +86,25 @@
|
||||
@@ -79,6 +_,27 @@
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.scores.Scoreboard;
|
||||
|
||||
@ -46,6 +31,8 @@
|
||||
+import net.minecraft.network.protocol.game.ClientboundSetBorderSizePacket;
|
||||
+import net.minecraft.network.protocol.game.ClientboundSetBorderWarningDelayPacket;
|
||||
+import net.minecraft.network.protocol.game.ClientboundSetBorderWarningDistancePacket;
|
||||
+import net.minecraft.world.level.border.BorderChangeListener;
|
||||
+import net.minecraft.world.level.dimension.LevelStem;
|
||||
+import org.bukkit.Bukkit;
|
||||
+import org.bukkit.craftbukkit.CraftServer;
|
||||
+import org.bukkit.craftbukkit.CraftWorld;
|
||||
@ -58,9 +45,9 @@
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
|
||||
public static final Codec<ResourceKey<Level>> RESOURCE_KEY_CODEC = ResourceKey.codec(Registries.DIMENSION);
|
||||
@@ -94,7 +118,7 @@
|
||||
public static final ResourceKey<Level> OVERWORLD = ResourceKey.create(Registries.DIMENSION, ResourceLocation.withDefaultNamespace("overworld"));
|
||||
@@ -91,7 +_,7 @@
|
||||
public static final int TICKS_PER_DAY = 24000;
|
||||
public static final int MAX_ENTITY_SPAWN_Y = 20000000;
|
||||
public static final int MIN_ENTITY_SPAWN_Y = -20000000;
|
||||
@ -69,21 +56,15 @@
|
||||
protected final NeighborUpdater neighborUpdater;
|
||||
private final List<TickingBlockEntity> pendingBlockEntityTickers = Lists.newArrayList();
|
||||
private boolean tickingBlockEntities;
|
||||
@@ -121,23 +145,91 @@
|
||||
@@ -117,6 +_,61 @@
|
||||
private final DamageSources damageSources;
|
||||
private long subTickCount;
|
||||
|
||||
- protected Level(WritableLevelData properties, ResourceKey<Level> registryRef, RegistryAccess registryManager, Holder<DimensionType> dimensionEntry, boolean isClient, boolean debugWorld, long seed, int maxChainedNeighborUpdates) {
|
||||
- this.levelData = properties;
|
||||
- this.dimensionTypeRegistration = dimensionEntry;
|
||||
- final DimensionType dimensionmanager = (DimensionType) dimensionEntry.value();
|
||||
+ // CraftBukkit start Added the following
|
||||
+ private final CraftWorld world;
|
||||
+ public boolean pvpMode;
|
||||
+ public org.bukkit.generator.ChunkGenerator generator;
|
||||
|
||||
- this.dimension = registryRef;
|
||||
- this.isClientSide = isClient;
|
||||
+
|
||||
+ public boolean preventPoiUpdated = false; // CraftBukkit - SPIGOT-5710
|
||||
+ public boolean captureBlockStates = false;
|
||||
+ public boolean captureTreeGeneration = false;
|
||||
@ -134,7 +115,21 @@
|
||||
+
|
||||
+ public abstract ResourceKey<LevelStem> getTypeKey();
|
||||
+
|
||||
+ protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, RegistryAccess iregistrycustom, Holder<DimensionType> holder, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function<org.spigotmc.SpigotWorldConfig, io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator) { // Paper - create paper world config
|
||||
protected Level(
|
||||
WritableLevelData levelData,
|
||||
ResourceKey<Level> dimension,
|
||||
@@ -125,8 +_,26 @@
|
||||
boolean isClientSide,
|
||||
boolean isDebug,
|
||||
long biomeZoomSeed,
|
||||
- int maxChainedNeighborUpdates
|
||||
+ int maxChainedNeighborUpdates,
|
||||
+ org.bukkit.generator.ChunkGenerator gen, // CraftBukkit
|
||||
+ org.bukkit.generator.BiomeProvider biomeProvider, // CraftBukkit
|
||||
+ org.bukkit.World.Environment env, // CraftBukkit
|
||||
+ java.util.function.Function<org.spigotmc.SpigotWorldConfig, // Spigot - create per world config
|
||||
+ io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator // Paper - create paper world config
|
||||
) {
|
||||
+ this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
|
||||
+ this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config
|
||||
+ this.generator = gen;
|
||||
@ -148,42 +143,30 @@
|
||||
+ }
|
||||
+
|
||||
+ // CraftBukkit end
|
||||
+ this.levelData = worlddatamutable;
|
||||
+ this.dimensionTypeRegistration = holder;
|
||||
+ final DimensionType dimensionmanager = (DimensionType) holder.value();
|
||||
+
|
||||
+ this.dimension = resourcekey;
|
||||
+ this.isClientSide = flag;
|
||||
if (dimensionmanager.coordinateScale() != 1.0D) {
|
||||
- this.worldBorder = new WorldBorder(this) {
|
||||
+ this.worldBorder = new WorldBorder() { // CraftBukkit - decompile error
|
||||
this.levelData = levelData;
|
||||
this.dimensionTypeRegistration = dimensionTypeRegistration;
|
||||
final DimensionType dimensionType = dimensionTypeRegistration.value();
|
||||
@@ -136,12 +_,12 @@
|
||||
this.worldBorder = new WorldBorder() {
|
||||
@Override
|
||||
public double getCenterX() {
|
||||
- return super.getCenterX() / dimensionmanager.coordinateScale();
|
||||
- return super.getCenterX() / dimensionType.coordinateScale();
|
||||
+ return super.getCenterX(); // CraftBukkit
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getCenterZ() {
|
||||
- return super.getCenterZ() / dimensionmanager.coordinateScale();
|
||||
- return super.getCenterZ() / dimensionType.coordinateScale();
|
||||
+ return super.getCenterZ(); // CraftBukkit
|
||||
}
|
||||
};
|
||||
} else {
|
||||
@@ -145,13 +237,90 @@
|
||||
}
|
||||
|
||||
this.thread = Thread.currentThread();
|
||||
- this.biomeManager = new BiomeManager(this, seed);
|
||||
- this.isDebug = debugWorld;
|
||||
- this.neighborUpdater = new CollectingNeighborUpdater(this, maxChainedNeighborUpdates);
|
||||
- this.registryAccess = registryManager;
|
||||
- this.damageSources = new DamageSources(registryManager);
|
||||
+ this.biomeManager = new BiomeManager(this, i);
|
||||
+ this.isDebug = flag1;
|
||||
+ this.neighborUpdater = new CollectingNeighborUpdater(this, j);
|
||||
+ this.registryAccess = iregistrycustom;
|
||||
+ this.damageSources = new DamageSources(iregistrycustom);
|
||||
@@ -154,7 +_,86 @@
|
||||
this.neighborUpdater = new CollectingNeighborUpdater(this, maxChainedNeighborUpdates);
|
||||
this.registryAccess = registryAccess;
|
||||
this.damageSources = new DamageSources(registryAccess);
|
||||
- }
|
||||
+
|
||||
+ // CraftBukkit start
|
||||
+ this.getWorldBorder().world = (ServerLevel) this;
|
||||
+ // From PlayerList.setPlayerFileData
|
||||
@ -222,8 +205,8 @@
|
||||
+ // CraftBukkit end
|
||||
+ this.entityLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.entityMaxTickTime);
|
||||
+ this.tileLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.tileMaxTickTime);
|
||||
}
|
||||
|
||||
+ }
|
||||
+
|
||||
+ // Paper start - Cancel hit for vanished players
|
||||
+ // ret true if no collision
|
||||
+ public final boolean checkEntityCollision(BlockState data, Entity source, net.minecraft.world.phys.shapes.CollisionContext voxelshapedcollision,
|
||||
@ -263,10 +246,10 @@
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Paper end - Cancel hit for vanished players
|
||||
|
||||
@Override
|
||||
public boolean isClientSide() {
|
||||
return this.isClientSide;
|
||||
@@ -163,6 +332,13 @@
|
||||
@@ -167,6 +_,13 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -278,9 +261,9 @@
|
||||
+ // Paper end
|
||||
+
|
||||
public boolean isInWorldBounds(BlockPos pos) {
|
||||
return !this.isOutsideBuildHeight(pos) && Level.isInWorldBoundsHorizontal(pos);
|
||||
return !this.isOutsideBuildHeight(pos) && isInWorldBoundsHorizontal(pos);
|
||||
}
|
||||
@@ -172,25 +348,87 @@
|
||||
@@ -176,25 +_,88 @@
|
||||
}
|
||||
|
||||
private static boolean isInWorldBoundsHorizontal(BlockPos pos) {
|
||||
@ -299,7 +282,7 @@
|
||||
|
||||
@Override
|
||||
- public LevelChunk getChunk(int chunkX, int chunkZ) {
|
||||
- return (LevelChunk) this.getChunk(chunkX, chunkZ, ChunkStatus.FULL);
|
||||
- return (LevelChunk)this.getChunk(chunkX, chunkZ, ChunkStatus.FULL);
|
||||
+ public final LevelChunk getChunk(int chunkX, int chunkZ) { // Paper - final to help inline
|
||||
+ // Paper start - Perf: make sure loaded chunks get the inlined variant of this function
|
||||
+ net.minecraft.server.level.ServerChunkCache cps = ((ServerLevel)this).getChunkSource();
|
||||
@ -309,11 +292,11 @@
|
||||
+ }
|
||||
+ return (LevelChunk) cps.getChunk(chunkX, chunkZ, ChunkStatus.FULL, true); // Paper - avoid a method jump
|
||||
+ // Paper end - Perf: make sure loaded chunks get the inlined variant of this function
|
||||
}
|
||||
|
||||
+ }
|
||||
+
|
||||
+ // Paper start - if loaded
|
||||
@Nullable
|
||||
@Override
|
||||
+ @Nullable
|
||||
+ @Override
|
||||
+ public final ChunkAccess getChunkIfLoadedImmediately(int x, int z) {
|
||||
+ return ((ServerLevel)this).chunkSource.getChunkAtIfLoadedImmediately(x, z);
|
||||
+ }
|
||||
@ -364,18 +347,19 @@
|
||||
+ // reduces need to do isLoaded before getType
|
||||
+ public final @Nullable BlockState getBlockStateIfLoadedAndInBounds(BlockPos blockposition) {
|
||||
+ return getWorldBorder().isWithinBounds(blockposition) ? getBlockStateIfLoaded(blockposition) : null;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
public ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) {
|
||||
+ // Paper end
|
||||
ChunkAccess ichunkaccess = this.getChunkSource().getChunk(chunkX, chunkZ, leastStatus, create);
|
||||
}
|
||||
|
||||
if (ichunkaccess == null && create) {
|
||||
@@ -207,6 +445,22 @@
|
||||
@Nullable
|
||||
@Override
|
||||
public ChunkAccess getChunk(int x, int z, ChunkStatus chunkStatus, boolean requireChunk) {
|
||||
+ // Paper end
|
||||
ChunkAccess chunk = this.getChunkSource().getChunk(x, z, chunkStatus, requireChunk);
|
||||
if (chunk == null && requireChunk) {
|
||||
throw new IllegalStateException("Should always be able to create a chunk!");
|
||||
@@ -210,6 +_,22 @@
|
||||
|
||||
@Override
|
||||
public boolean setBlock(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) {
|
||||
public boolean setBlock(BlockPos pos, BlockState state, int flags, int recursionLeft) {
|
||||
+ // CraftBukkit start - tree generation
|
||||
+ if (this.captureTreeGeneration) {
|
||||
+ // Paper start - Protect Bedrock and End Portal/Frames from being destroyed
|
||||
@ -395,12 +379,11 @@
|
||||
if (this.isOutsideBuildHeight(pos)) {
|
||||
return false;
|
||||
} else if (!this.isClientSide && this.isDebug()) {
|
||||
@@ -214,44 +468,125 @@
|
||||
@@ -217,11 +_,28 @@
|
||||
} else {
|
||||
LevelChunk chunk = this.getChunkAt(pos);
|
||||
LevelChunk chunkAt = this.getChunkAt(pos);
|
||||
Block block = state.getBlock();
|
||||
- BlockState iblockdata1 = chunk.setBlockState(pos, state, (flags & 64) != 0);
|
||||
|
||||
- BlockState blockState = chunkAt.setBlockState(pos, state, (flags & 64) != 0);
|
||||
+ // CraftBukkit start - capture blockstates
|
||||
+ boolean captured = false;
|
||||
+ if (this.captureBlockStates && !this.capturedBlockStates.containsKey(pos)) {
|
||||
@ -411,9 +394,9 @@
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
+ BlockState iblockdata1 = chunk.setBlockState(pos, state, (flags & 64) != 0, (flags & 1024) == 0); // CraftBukkit custom NO_PLACE flag
|
||||
+ BlockState blockState = chunkAt.setBlockState(pos, state, (flags & 64) != 0, (flags & 1024) == 0); // CraftBukkit custom NO_PLACE flag
|
||||
+
|
||||
if (iblockdata1 == null) {
|
||||
if (blockState == null) {
|
||||
+ // CraftBukkit start - remove blockstate if failed (or the same)
|
||||
+ if (this.captureBlockStates && captured) {
|
||||
+ this.capturedBlockStates.remove(pos);
|
||||
@ -421,69 +404,35 @@
|
||||
+ // CraftBukkit end
|
||||
return false;
|
||||
} else {
|
||||
BlockState iblockdata2 = this.getBlockState(pos);
|
||||
|
||||
- if (iblockdata2 == state) {
|
||||
BlockState blockState1 = this.getBlockState(pos);
|
||||
+ /*
|
||||
+ if (iblockdata2 == iblockdata) {
|
||||
if (iblockdata1 != iblockdata2) {
|
||||
- this.setBlocksDirty(pos, iblockdata1, iblockdata2);
|
||||
+ this.setBlocksDirty(blockposition, iblockdata1, iblockdata2);
|
||||
}
|
||||
if (blockState1 == state) {
|
||||
if (blockState != blockState1) {
|
||||
this.setBlocksDirty(pos, blockState, blockState1);
|
||||
@@ -249,12 +_,76 @@
|
||||
|
||||
- if ((flags & 2) != 0 && (!this.isClientSide || (flags & 4) == 0) && (this.isClientSide || chunk.getFullStatus() != null && chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING))) {
|
||||
- this.sendBlockUpdated(pos, iblockdata1, state, flags);
|
||||
+ if ((i & 2) != 0 && (!this.isClientSide || (i & 4) == 0) && (this.isClientSide || chunk.getFullStatus() != null && chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING))) {
|
||||
+ this.sendBlockUpdated(blockposition, iblockdata1, iblockdata, i);
|
||||
}
|
||||
|
||||
- if ((flags & 1) != 0) {
|
||||
- this.blockUpdated(pos, iblockdata1.getBlock());
|
||||
- if (!this.isClientSide && state.hasAnalogOutputSignal()) {
|
||||
- this.updateNeighbourForOutputSignal(pos, block);
|
||||
+ if ((i & 1) != 0) {
|
||||
+ this.blockUpdated(blockposition, iblockdata1.getBlock());
|
||||
+ if (!this.isClientSide && iblockdata.hasAnalogOutputSignal()) {
|
||||
+ this.updateNeighbourForOutputSignal(blockposition, block);
|
||||
}
|
||||
}
|
||||
|
||||
- if ((flags & 16) == 0 && maxUpdateDepth > 0) {
|
||||
- int k = flags & -34;
|
||||
+ if ((i & 16) == 0 && j > 0) {
|
||||
+ int k = i & -34;
|
||||
|
||||
- iblockdata1.updateIndirectNeighbourShapes(this, pos, k, maxUpdateDepth - 1);
|
||||
- state.updateNeighbourShapes(this, pos, k, maxUpdateDepth - 1);
|
||||
- state.updateIndirectNeighbourShapes(this, pos, k, maxUpdateDepth - 1);
|
||||
+ iblockdata1.updateIndirectNeighbourShapes(this, blockposition, k, j - 1);
|
||||
+ iblockdata.updateNeighbourShapes(this, blockposition, k, j - 1);
|
||||
+ iblockdata.updateIndirectNeighbourShapes(this, blockposition, k, j - 1);
|
||||
}
|
||||
|
||||
- this.onBlockStateChange(pos, iblockdata1, iblockdata2);
|
||||
+ this.onBlockStateChange(blockposition, iblockdata1, iblockdata2);
|
||||
this.onBlockStateChange(pos, blockState, blockState1);
|
||||
}
|
||||
+ */
|
||||
|
||||
+
|
||||
+ // CraftBukkit start
|
||||
+ if (!this.captureBlockStates) { // Don't notify clients or update physics while capturing blockstates
|
||||
+ // Modularize client and physic updates
|
||||
+ // Spigot start
|
||||
+ try {
|
||||
+ this.notifyAndUpdatePhysics(pos, chunk, iblockdata1, state, iblockdata2, flags, maxUpdateDepth);
|
||||
+ this.notifyAndUpdatePhysics(pos, chunkAt, blockState, state, blockState1, flags, recursionLeft);
|
||||
+ } catch (StackOverflowError ex) {
|
||||
+ Level.lastPhysicsProblem = new BlockPos(pos);
|
||||
+ }
|
||||
+ // Spigot end
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
|
||||
return true;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ // CraftBukkit start - Split off from above in order to directly send client and physic updates
|
||||
+ public void notifyAndUpdatePhysics(BlockPos blockposition, LevelChunk chunk, BlockState oldBlock, BlockState newBlock, BlockState actualBlock, int i, int j) {
|
||||
+ BlockState iblockdata = newBlock;
|
||||
@ -520,60 +469,59 @@
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+ if (!cancelledUpdates) { // Paper - Fix block place logic
|
||||
+ iblockdata.updateNeighbourShapes(this, blockposition, k, j - 1);
|
||||
+ iblockdata.updateIndirectNeighbourShapes(this, blockposition, k, j - 1);
|
||||
+ iblockdata.updateNeighbourShapes(this, blockposition, k, j - 1);
|
||||
+ iblockdata.updateIndirectNeighbourShapes(this, blockposition, k, j - 1);
|
||||
+ } // Paper - Fix block place logic
|
||||
}
|
||||
+ }
|
||||
+
|
||||
+ // CraftBukkit start - SPIGOT-5710
|
||||
+ if (!this.preventPoiUpdated) {
|
||||
+ this.onBlockStateChange(blockposition, iblockdata1, iblockdata2);
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
}
|
||||
+ }
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
public void onBlockStateChange(BlockPos pos, BlockState blockState, BlockState newState) {
|
||||
}
|
||||
|
||||
public void onBlockStateChange(BlockPos pos, BlockState oldBlock, BlockState newBlock) {}
|
||||
|
||||
@@ -270,15 +605,33 @@
|
||||
@@ -271,13 +_,31 @@
|
||||
return false;
|
||||
} else {
|
||||
FluidState fluid = this.getFluidState(pos);
|
||||
FluidState fluidState = this.getFluidState(pos);
|
||||
- if (!(blockState.getBlock() instanceof BaseFireBlock)) {
|
||||
- this.levelEvent(2001, pos, Block.getId(blockState));
|
||||
+ // Paper start - BlockDestroyEvent; while the above setAir method is named same and looks very similar
|
||||
+ // they are NOT used with same intent and the above should not fire this event. The above method is more of a BlockSetToAirEvent,
|
||||
+ // it doesn't imply destruction of a block that plays a sound effect / drops an item.
|
||||
+ boolean playEffect = true;
|
||||
+ BlockState effectType = iblockdata;
|
||||
+ int xp = iblockdata.getBlock().getExpDrop(iblockdata, (ServerLevel) this, pos, ItemStack.EMPTY, true);
|
||||
+ BlockState effectType = blockState;
|
||||
+ int xp = blockState.getBlock().getExpDrop(blockState, (ServerLevel) this, pos, ItemStack.EMPTY, true);
|
||||
+ if (com.destroystokyo.paper.event.block.BlockDestroyEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
||||
+ com.destroystokyo.paper.event.block.BlockDestroyEvent event = new com.destroystokyo.paper.event.block.BlockDestroyEvent(org.bukkit.craftbukkit.block.CraftBlock.at(this, pos), fluid.createLegacyBlock().createCraftBlockData(), effectType.createCraftBlockData(), xp, drop);
|
||||
+ com.destroystokyo.paper.event.block.BlockDestroyEvent event = new com.destroystokyo.paper.event.block.BlockDestroyEvent(org.bukkit.craftbukkit.block.CraftBlock.at(this, pos), fluidState.createLegacyBlock().createCraftBlockData(), effectType.createCraftBlockData(), xp, dropBlock);
|
||||
+ if (!event.callEvent()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ effectType = ((CraftBlockData) event.getEffectBlock()).getState();
|
||||
+ playEffect = event.playEffect();
|
||||
+ drop = event.willDrop();
|
||||
+ dropBlock = event.willDrop();
|
||||
+ xp = event.getExpToDrop();
|
||||
+ }
|
||||
+ // Paper end - BlockDestroyEvent
|
||||
|
||||
- if (!(iblockdata.getBlock() instanceof BaseFireBlock)) {
|
||||
- this.levelEvent(2001, pos, Block.getId(iblockdata));
|
||||
+ if (playEffect && !(effectType.getBlock() instanceof BaseFireBlock)) { // Paper - BlockDestroyEvent
|
||||
+ if (playEffect && !(blockState.getBlock() instanceof BaseFireBlock)) { // Paper - BlockDestroyEvent
|
||||
+ this.levelEvent(2001, pos, Block.getId(effectType)); // Paper - BlockDestroyEvent
|
||||
}
|
||||
|
||||
if (drop) {
|
||||
BlockEntity tileentity = iblockdata.hasBlockEntity() ? this.getBlockEntity(pos) : null;
|
||||
|
||||
- Block.dropResources(iblockdata, this, pos, tileentity, breakingEntity, ItemStack.EMPTY);
|
||||
+ Block.dropResources(iblockdata, this, pos, tileentity, breakingEntity, ItemStack.EMPTY, false); // Paper - Properly handle xp dropping
|
||||
+ iblockdata.getBlock().popExperience((ServerLevel) this, pos, xp, breakingEntity); // Paper - Properly handle xp dropping; custom amount
|
||||
if (dropBlock) {
|
||||
BlockEntity blockEntity = blockState.hasBlockEntity() ? this.getBlockEntity(pos) : null;
|
||||
- Block.dropResources(blockState, this, pos, blockEntity, entity, ItemStack.EMPTY);
|
||||
+ Block.dropResources(blockState, this, pos, blockEntity, entity, ItemStack.EMPTY, false); // Paper - Properly handle xp dropping
|
||||
+ blockState.getBlock().popExperience((ServerLevel) this, pos, xp, entity); // Paper - Properly handle xp dropping; custom amount
|
||||
}
|
||||
|
||||
boolean flag1 = this.setBlock(pos, fluid.createLegacyBlock(), 3, maxUpdateDepth);
|
||||
@@ -340,10 +693,18 @@
|
||||
boolean flag = this.setBlock(pos, fluidState.createLegacyBlock(), 3, recursionLeft);
|
||||
@@ -344,10 +_,18 @@
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(BlockPos pos) {
|
||||
@ -590,121 +538,112 @@
|
||||
} else {
|
||||
- LevelChunk chunk = this.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ()));
|
||||
+ ChunkAccess chunk = this.getChunk(pos.getX() >> 4, pos.getZ() >> 4, ChunkStatus.FULL, true); // Paper - manually inline to reduce hops and avoid unnecessary null check to reduce total byte code size, this should never return null and if it does we will see it the next line but the real stack trace will matter in the chunk engine
|
||||
|
||||
return chunk.getBlockState(pos);
|
||||
}
|
||||
@@ -446,34 +807,53 @@
|
||||
}
|
||||
@@ -454,32 +_,54 @@
|
||||
this.pendingBlockEntityTickers.clear();
|
||||
}
|
||||
|
||||
- Iterator<TickingBlockEntity> iterator = this.blockEntityTickers.iterator();
|
||||
+ // Spigot start
|
||||
+ // Iterator<TickingBlockEntity> iterator = this.blockEntityTickers.iterator();
|
||||
boolean flag = this.tickRateManager().runsNormally();
|
||||
boolean runsNormally = this.tickRateManager().runsNormally();
|
||||
|
||||
- while (iterator.hasNext()) {
|
||||
- TickingBlockEntity tickingblockentity = (TickingBlockEntity) iterator.next();
|
||||
- TickingBlockEntity tickingBlockEntity = iterator.next();
|
||||
+ int tilesThisCycle = 0;
|
||||
+ var toRemove = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<TickingBlockEntity>(); // Paper - Fix MC-117075; use removeAll
|
||||
+ toRemove.add(null); // Paper - Fix MC-117075
|
||||
+ for (tileTickPosition = 0; tileTickPosition < this.blockEntityTickers.size(); tileTickPosition++) { // Paper - Disable tick limiters
|
||||
+ this.tileTickPosition = (this.tileTickPosition < this.blockEntityTickers.size()) ? this.tileTickPosition : 0;
|
||||
+ TickingBlockEntity tickingblockentity = (TickingBlockEntity) this.blockEntityTickers.get(this.tileTickPosition);
|
||||
+ TickingBlockEntity tickingBlockEntity = (TickingBlockEntity) this.blockEntityTickers.get(this.tileTickPosition);
|
||||
+ // Spigot end
|
||||
|
||||
if (tickingblockentity.isRemoved()) {
|
||||
if (tickingBlockEntity.isRemoved()) {
|
||||
- iterator.remove();
|
||||
+ // Spigot start
|
||||
+ tilesThisCycle--;
|
||||
+ toRemove.add(tickingblockentity); // Paper - Fix MC-117075; use removeAll
|
||||
+ tilesThisCycle--;
|
||||
+ toRemove.add(tickingBlockEntity); // Paper - Fix MC-117075; use removeAll
|
||||
+ // Spigot end
|
||||
} else if (flag && this.shouldTickBlocksAt(tickingblockentity.getPos())) {
|
||||
tickingblockentity.tick();
|
||||
} else if (runsNormally && this.shouldTickBlocksAt(tickingBlockEntity.getPos())) {
|
||||
tickingBlockEntity.tick();
|
||||
}
|
||||
}
|
||||
+ this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075
|
||||
|
||||
this.tickingBlockEntities = false;
|
||||
gameprofilerfiller.pop();
|
||||
profilerFiller.pop();
|
||||
+ this.spigotConfig.currentPrimedTnt = 0; // Spigot
|
||||
}
|
||||
|
||||
public <T extends Entity> void guardEntityTick(Consumer<T> tickConsumer, T entity) {
|
||||
public <T extends Entity> void guardEntityTick(Consumer<T> consumerEntity, T entity) {
|
||||
try {
|
||||
tickConsumer.accept(entity);
|
||||
} catch (Throwable throwable) {
|
||||
- CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking entity");
|
||||
- CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being ticked");
|
||||
-
|
||||
- entity.fillCrashReportCategory(crashreportsystemdetails);
|
||||
- throw new ReportedException(crashreport);
|
||||
consumerEntity.accept(entity);
|
||||
} catch (Throwable var6) {
|
||||
- CrashReport crashReport = CrashReport.forThrowable(var6, "Ticking entity");
|
||||
- CrashReportCategory crashReportCategory = crashReport.addCategory("Entity being ticked");
|
||||
- entity.fillCrashReportCategory(crashReportCategory);
|
||||
- throw new ReportedException(crashReport);
|
||||
+ // Paper start - Prevent block entity and entity crashes
|
||||
+ final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level().getWorld().getName(), entity.getX(), entity.getY(), entity.getZ());
|
||||
+ MinecraftServer.LOGGER.error(msg, throwable);
|
||||
+ MinecraftServer.LOGGER.error(msg, var6);
|
||||
+ getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, throwable))); // Paper - ServerExceptionEvent
|
||||
+ entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD);
|
||||
+ // Paper end - Prevent block entity and entity crashes
|
||||
}
|
||||
+ }
|
||||
}
|
||||
+
|
||||
+ // Paper start - Option to prevent armor stands from doing entity lookups
|
||||
+ @Override
|
||||
+ public boolean noCollision(@Nullable Entity entity, AABB box) {
|
||||
+ if (entity instanceof net.minecraft.world.entity.decoration.ArmorStand && !entity.level().paperConfig().entities.armorStands.doCollisionEntityLookups) return false;
|
||||
+ if (entity instanceof net.minecraft.world.entity.decoration.ArmorStand && !entity.level().paperConfig().entities.armorStands.doCollisionEntityLookups)
|
||||
+ return false;
|
||||
+ return LevelAccessor.super.noCollision(entity, box);
|
||||
}
|
||||
+ }
|
||||
+ // Paper end - Option to prevent armor stands from doing entity lookups
|
||||
|
||||
public boolean shouldTickDeath(Entity entity) {
|
||||
return true;
|
||||
@@ -510,13 +890,32 @@
|
||||
@@ -599,6 +_,19 @@
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockEntity getBlockEntity(BlockPos pos) {
|
||||
- return this.isOutsideBuildHeight(pos) ? null : (!this.isClientSide && Thread.currentThread() != this.thread ? null : this.getChunkAt(pos).getBlockEntity(pos, LevelChunk.EntityCreationType.IMMEDIATE));
|
||||
+ // CraftBukkit start
|
||||
+ return this.getBlockEntity(pos, true);
|
||||
}
|
||||
|
||||
+ }
|
||||
+
|
||||
+ @Nullable
|
||||
+ public BlockEntity getBlockEntity(BlockPos blockposition, boolean validate) {
|
||||
+ public BlockEntity getBlockEntity(BlockPos pos, boolean validate) {
|
||||
+ // Paper start - Perf: Optimize capturedTileEntities lookup
|
||||
+ net.minecraft.world.level.block.entity.BlockEntity blockEntity;
|
||||
+ if (!this.capturedTileEntities.isEmpty() && (blockEntity = this.capturedTileEntities.get(blockposition)) != null) {
|
||||
+ if (!this.capturedTileEntities.isEmpty() && (blockEntity = this.capturedTileEntities.get(pos)) != null) {
|
||||
+ return blockEntity;
|
||||
+ }
|
||||
+ // Paper end - Perf: Optimize capturedTileEntities lookup
|
||||
+ // CraftBukkit end
|
||||
+ return this.isOutsideBuildHeight(blockposition) ? null : (!this.isClientSide && Thread.currentThread() != this.thread ? null : this.getChunkAt(blockposition).getBlockEntity(blockposition, LevelChunk.EntityCreationType.IMMEDIATE));
|
||||
+ }
|
||||
+
|
||||
if (this.isOutsideBuildHeight(pos)) {
|
||||
return null;
|
||||
} else {
|
||||
@@ -611,6 +_,12 @@
|
||||
public void setBlockEntity(BlockEntity blockEntity) {
|
||||
BlockPos blockposition = blockEntity.getBlockPos();
|
||||
|
||||
if (!this.isOutsideBuildHeight(blockposition)) {
|
||||
BlockPos blockPos = blockEntity.getBlockPos();
|
||||
if (!this.isOutsideBuildHeight(blockPos)) {
|
||||
+ // CraftBukkit start
|
||||
+ if (this.captureBlockStates) {
|
||||
+ this.capturedTileEntities.put(blockposition.immutable(), blockEntity);
|
||||
+ this.capturedTileEntities.put(blockPos.immutable(), blockEntity);
|
||||
+ return;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
this.getChunkAt(blockposition).addAndRegisterBlockEntity(blockEntity);
|
||||
this.getChunkAt(blockPos).addAndRegisterBlockEntity(blockEntity);
|
||||
}
|
||||
}
|
||||
@@ -643,7 +1042,7 @@
|
||||
|
||||
for (int k = 0; k < j; ++k) {
|
||||
EnderDragonPart entitycomplexpart = aentitycomplexpart[k];
|
||||
- T t0 = (Entity) filter.tryCast(entitycomplexpart);
|
||||
+ T t0 = filter.tryCast(entitycomplexpart); // CraftBukkit - decompile error
|
||||
|
||||
if (t0 != null && predicate.test(t0)) {
|
||||
result.add(t0);
|
||||
@@ -912,7 +1311,7 @@
|
||||
|
||||
public static enum ExplosionInteraction implements StringRepresentable {
|
||||
|
||||
- NONE("none"), BLOCK("block"), MOB("mob"), TNT("tnt"), TRIGGER("trigger");
|
||||
+ NONE("none"), BLOCK("block"), MOB("mob"), TNT("tnt"), TRIGGER("trigger"), STANDARD("standard"); // CraftBukkit - Add STANDARD which will always use Explosion.Effect.DESTROY
|
||||
@@ -987,7 +_,8 @@
|
||||
BLOCK("block"),
|
||||
MOB("mob"),
|
||||
TNT("tnt"),
|
||||
- TRIGGER("trigger");
|
||||
+ TRIGGER("trigger"),
|
||||
+ STANDARD("standard"); // CraftBukkit - Add STANDARD which will always use Explosion.Effect.DESTROY
|
||||
|
||||
public static final Codec<Level.ExplosionInteraction> CODEC = StringRepresentable.fromEnum(Level.ExplosionInteraction::values);
|
||||
private final String id;
|
@ -0,0 +1,9 @@
|
||||
--- a/net/minecraft/world/level/LevelAccessor.java
|
||||
+++ b/net/minecraft/world/level/LevelAccessor.java
|
||||
@@ -101,4 +_,6 @@
|
||||
default void gameEvent(ResourceKey<GameEvent> gameEvent, BlockPos pos, GameEvent.Context context) {
|
||||
this.gameEvent(this.registryAccess().lookupOrThrow(Registries.GAME_EVENT).getOrThrow(gameEvent), pos, context);
|
||||
}
|
||||
+
|
||||
+ net.minecraft.server.level.ServerLevel getMinecraftWorld(); // CraftBukkit
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
--- a/net/minecraft/world/level/LevelReader.java
|
||||
+++ b/net/minecraft/world/level/LevelReader.java
|
||||
@@ -26,6 +26,9 @@
|
||||
@@ -26,6 +_,9 @@
|
||||
@Nullable
|
||||
ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create);
|
||||
ChunkAccess getChunk(int x, int z, ChunkStatus chunkStatus, boolean requireChunk);
|
||||
|
||||
+ @Nullable ChunkAccess getChunkIfLoadedImmediately(int x, int z); // Paper - ifLoaded api (we need this since current impl blocks if the chunk is loading)
|
||||
+ @Nullable default ChunkAccess getChunkIfLoadedImmediately(BlockPos pos) { return this.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4);}
|
@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/world/level/LevelWriter.java
|
||||
+++ b/net/minecraft/world/level/LevelWriter.java
|
||||
@@ -28,4 +28,10 @@
|
||||
@@ -27,4 +_,10 @@
|
||||
default boolean addFreshEntity(Entity entity) {
|
||||
return false;
|
||||
}
|
@ -0,0 +1,234 @@
|
||||
--- a/net/minecraft/world/level/NaturalSpawner.java
|
||||
+++ b/net/minecraft/world/level/NaturalSpawner.java
|
||||
@@ -49,6 +_,13 @@
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import net.minecraft.world.level.storage.LevelData;
|
||||
+import org.bukkit.craftbukkit.util.CraftSpawnCategory;
|
||||
+import org.bukkit.entity.SpawnCategory;
|
||||
+import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
|
||||
+// CraftBukkit end
|
||||
+
|
||||
public final class NaturalSpawner {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private static final int MIN_SPAWN_DISTANCE = 24;
|
||||
@@ -72,6 +_,13 @@
|
||||
if (!(entity instanceof Mob mob && (mob.isPersistenceRequired() || mob.requiresCustomPersistence()))) {
|
||||
MobCategory category = entity.getType().getCategory();
|
||||
if (category != MobCategory.MISC) {
|
||||
+ // Paper start - Only count natural spawns
|
||||
+ if (!entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
|
||||
+ !(entity.spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL ||
|
||||
+ entity.spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ // Paper end - Only count natural spawns
|
||||
BlockPos blockPos = entity.blockPosition();
|
||||
chunkGetter.query(ChunkPos.asLong(blockPos), chunk -> {
|
||||
MobSpawnSettings.MobSpawnCost mobSpawnCost = getRoughBiome(blockPos, chunk).getMobSettings().getMobSpawnCost(entity.getType());
|
||||
@@ -96,17 +_,36 @@
|
||||
return chunk.getNoiseBiome(QuartPos.fromBlock(pos.getX()), QuartPos.fromBlock(pos.getY()), QuartPos.fromBlock(pos.getZ())).value();
|
||||
}
|
||||
|
||||
+ // CraftBukkit start - add server
|
||||
public static List<MobCategory> getFilteredSpawningCategories(
|
||||
- NaturalSpawner.SpawnState spawnState, boolean spawnFriendlies, boolean spawnEnemies, boolean spawnPassives
|
||||
+ NaturalSpawner.SpawnState spawnState, boolean spawnFriendlies, boolean spawnEnemies, boolean spawnPassives, ServerLevel worldserver
|
||||
) {
|
||||
+ LevelData worlddata = worldserver.getLevelData(); // CraftBukkit - Other mob type spawn tick rate
|
||||
+ // CraftBukkit end
|
||||
List<MobCategory> list = new ArrayList<>(SPAWNING_CATEGORIES.length);
|
||||
-
|
||||
- for (MobCategory mobCategory : SPAWNING_CATEGORIES) {
|
||||
- if ((spawnFriendlies || !mobCategory.isFriendly())
|
||||
- && (spawnEnemies || mobCategory.isFriendly())
|
||||
- && (spawnPassives || !mobCategory.isPersistent())
|
||||
- && spawnState.canSpawnForCategoryGlobal(mobCategory)) {
|
||||
- list.add(mobCategory);
|
||||
+ MobCategory[] aenumcreaturetype = NaturalSpawner.SPAWNING_CATEGORIES;
|
||||
+ int i = aenumcreaturetype.length;
|
||||
+
|
||||
+ for (int j = 0; j < i; ++j) {
|
||||
+ MobCategory enumcreaturetype = SPAWNING_CATEGORIES[j];
|
||||
+ // CraftBukkit start - Use per-world spawn limits
|
||||
+ boolean spawnThisTick = true;
|
||||
+ int limit = enumcreaturetype.getMaxInstancesPerChunk();
|
||||
+ SpawnCategory spawnCategory = CraftSpawnCategory.toBukkit(enumcreaturetype);
|
||||
+ if (CraftSpawnCategory.isValidForLimits(spawnCategory)) {
|
||||
+ spawnThisTick = worldserver.ticksPerSpawnCategory.getLong(spawnCategory) != 0 && worlddata.getGameTime() % worldserver.ticksPerSpawnCategory.getLong(spawnCategory) == 0;
|
||||
+ limit = worldserver.getWorld().getSpawnLimit(spawnCategory);
|
||||
+ }
|
||||
+
|
||||
+ if (!spawnThisTick || limit == 0) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if ((spawnFriendlies || !enumcreaturetype.isFriendly())
|
||||
+ && (spawnEnemies || enumcreaturetype.isFriendly())
|
||||
+ && (spawnPassives || !enumcreaturetype.isPersistent())
|
||||
+ && spawnState.canSpawnForCategoryGlobal(enumcreaturetype)) {
|
||||
+ list.add(enumcreaturetype);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +_,16 @@
|
||||
profilerFiller.pop();
|
||||
}
|
||||
|
||||
+ // Paper start - Add mobcaps commands
|
||||
+ public static int globalLimitForCategory(final ServerLevel level, final MobCategory category, final int spawnableChunkCount) {
|
||||
+ final int categoryLimit = level.getWorld().getSpawnLimitUnsafe(CraftSpawnCategory.toBukkit(category));
|
||||
+ if (categoryLimit < 1) {
|
||||
+ return categoryLimit;
|
||||
+ }
|
||||
+ return categoryLimit * spawnableChunkCount / NaturalSpawner.MAGIC_NUMBER;
|
||||
+ }
|
||||
+ // Paper end - Add mobcaps commands
|
||||
+
|
||||
public static void spawnCategoryForChunk(
|
||||
MobCategory category, ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback
|
||||
) {
|
||||
@@ -151,8 +_,8 @@
|
||||
StructureManager structureManager = level.structureManager();
|
||||
ChunkGenerator generator = level.getChunkSource().getGenerator();
|
||||
int y = pos.getY();
|
||||
- BlockState blockState = chunk.getBlockState(pos);
|
||||
- if (!blockState.isRedstoneConductor(chunk, pos)) {
|
||||
+ BlockState blockState = chunk.getBlockStateIfLoadedAndInBounds(pos); // Paper - don't load chunks for mob spawn
|
||||
+ if (blockState != null && !blockState.isRedstoneConductor(chunk, pos)) { // Paper - don't load chunks for mob spawn
|
||||
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
||||
int i = 0;
|
||||
|
||||
@@ -174,7 +_,7 @@
|
||||
Player nearestPlayer = level.getNearestPlayer(d, y, d1, -1.0, false);
|
||||
if (nearestPlayer != null) {
|
||||
double d2 = nearestPlayer.distanceToSqr(d, y, d1);
|
||||
- if (isRightDistanceToPlayerAndSpawnPoint(level, chunk, mutableBlockPos, d2)) {
|
||||
+ if (level.isLoadedAndInBounds(mutableBlockPos) && isRightDistanceToPlayerAndSpawnPoint(level, chunk, mutableBlockPos, d2)) { // Paper - don't load chunks for mob spawn
|
||||
if (spawnerData == null) {
|
||||
Optional<MobSpawnSettings.SpawnerData> randomSpawnMobAt = getRandomSpawnMobAt(
|
||||
level, structureManager, generator, category, level.random, mutableBlockPos
|
||||
@@ -187,8 +_,13 @@
|
||||
ceil = spawnerData.minCount + level.random.nextInt(1 + spawnerData.maxCount - spawnerData.minCount);
|
||||
}
|
||||
|
||||
- if (isValidSpawnPostitionForType(level, category, structureManager, generator, spawnerData, mutableBlockPos, d2)
|
||||
- && filter.test(spawnerData.type, mutableBlockPos, chunk)) {
|
||||
+ // Paper start - PreCreatureSpawnEvent
|
||||
+ PreSpawnStatus doSpawning = isValidSpawnPostitionForType(level, category, structureManager, generator, spawnerData, mutableBlockPos, d2);
|
||||
+ if (doSpawning == PreSpawnStatus.ABORT) {
|
||||
+ return;
|
||||
+ }
|
||||
+ if (doSpawning == PreSpawnStatus.SUCCESS && filter.test(spawnerData.type, mutableBlockPos, chunk)) {
|
||||
+ // Paper end - PreCreatureSpawnEvent
|
||||
Mob mobForSpawn = getMobForSpawn(level, spawnerData.type);
|
||||
if (mobForSpawn == null) {
|
||||
return;
|
||||
@@ -199,10 +_,15 @@
|
||||
spawnGroupData = mobForSpawn.finalizeSpawn(
|
||||
level, level.getCurrentDifficultyAt(mobForSpawn.blockPosition()), EntitySpawnReason.NATURAL, spawnGroupData
|
||||
);
|
||||
- i++;
|
||||
- i3++;
|
||||
- level.addFreshEntityWithPassengers(mobForSpawn);
|
||||
- callback.run(mobForSpawn, chunk);
|
||||
+ // CraftBukkit start
|
||||
+ // SPIGOT-7045: Give ocelot babies back their special spawn reason. Note: This is the only modification required as ocelots count as monsters which means they only spawn during normal chunk ticking and do not spawn during chunk generation as starter mobs.
|
||||
+ level.addFreshEntityWithPassengers(mobForSpawn, (mobForSpawn instanceof net.minecraft.world.entity.animal.Ocelot && !((org.bukkit.entity.Ageable) mobForSpawn.getBukkitEntity()).isAdult()) ? SpawnReason.OCELOT_BABY : SpawnReason.NATURAL);
|
||||
+ if (!mobForSpawn.isRemoved()) {
|
||||
+ ++i;
|
||||
+ ++i3;
|
||||
+ callback.run(mobForSpawn, chunk);
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
if (i >= mobForSpawn.getMaxSpawnClusterSize()) {
|
||||
return;
|
||||
}
|
||||
@@ -225,7 +_,15 @@
|
||||
&& (Objects.equals(new ChunkPos(pos), chunk.getPos()) || level.isNaturalSpawningAllowed(pos));
|
||||
}
|
||||
|
||||
- private static boolean isValidSpawnPostitionForType(
|
||||
+ // Paper start - PreCreatureSpawnEvent
|
||||
+ private enum PreSpawnStatus {
|
||||
+ FAIL,
|
||||
+ SUCCESS,
|
||||
+ CANCELLED,
|
||||
+ ABORT
|
||||
+ }
|
||||
+ private static PreSpawnStatus isValidSpawnPostitionForType(
|
||||
+ // Paper end - PreCreatureSpawnEvent
|
||||
ServerLevel level,
|
||||
MobCategory category,
|
||||
StructureManager structureManager,
|
||||
@@ -235,16 +_,20 @@
|
||||
double distance
|
||||
) {
|
||||
EntityType<?> entityType = data.type;
|
||||
- return entityType.getCategory() != MobCategory.MISC
|
||||
- && (
|
||||
- entityType.canSpawnFarFromPlayer()
|
||||
- || !(distance > entityType.getCategory().getDespawnDistance() * entityType.getCategory().getDespawnDistance())
|
||||
- )
|
||||
- && entityType.canSummon()
|
||||
- && canSpawnMobAt(level, structureManager, generator, category, data, pos)
|
||||
- && SpawnPlacements.isSpawnPositionOk(entityType, level, pos)
|
||||
- && SpawnPlacements.checkSpawnRules(entityType, level, EntitySpawnReason.NATURAL, pos, level.random)
|
||||
- && level.noCollision(entityType.getSpawnAABB(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5));
|
||||
+
|
||||
+ // Paper start - PreCreatureSpawnEvent
|
||||
+ com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
|
||||
+ io.papermc.paper.util.MCUtil.toLocation(level, pos),
|
||||
+ org.bukkit.craftbukkit.entity.CraftEntityType.minecraftToBukkit(entityType), SpawnReason.NATURAL
|
||||
+ );
|
||||
+ if (!event.callEvent()) {
|
||||
+ if (event.shouldAbortSpawn()) {
|
||||
+ return PreSpawnStatus.ABORT;
|
||||
+ }
|
||||
+ return PreSpawnStatus.CANCELLED;
|
||||
+ }
|
||||
+ // Paper end - PreCreatureSpawnEvent
|
||||
+ return entityType.getCategory() == MobCategory.MISC ? PreSpawnStatus.FAIL : (!entityType.canSpawnFarFromPlayer() && distance > (double) (entityType.getCategory().getDespawnDistance() * entityType.getCategory().getDespawnDistance()) ? PreSpawnStatus.FAIL : (entityType.canSummon() && NaturalSpawner.canSpawnMobAt(level, structureManager, generator, category, data, pos) ? (!SpawnPlacements.isSpawnPositionOk(entityType, level, pos) ? PreSpawnStatus.FAIL : (!SpawnPlacements.checkSpawnRules(entityType, level, EntitySpawnReason.NATURAL, pos, level.random) ? PreSpawnStatus.FAIL : level.noCollision(entityType.getSpawnAABB((double) pos.getX() + 0.5D, (double) pos.getY(), (double) pos.getZ() + 0.5D)) ? PreSpawnStatus.SUCCESS : PreSpawnStatus.FAIL)) : PreSpawnStatus.FAIL)); // Paper - PreCreatureSpawnEvent
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -258,6 +_,7 @@
|
||||
LOGGER.warn("Can't spawn entity of type: {}", BuiltInRegistries.ENTITY_TYPE.getKey(entityType));
|
||||
} catch (Exception var4) {
|
||||
LOGGER.warn("Failed to create mob", (Throwable)var4);
|
||||
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(var4); // Paper - ServerExceptionEvent
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -364,6 +_,7 @@
|
||||
entity = spawnerData.type.create(levelAccessor.getLevel(), EntitySpawnReason.NATURAL);
|
||||
} catch (Exception var27) {
|
||||
LOGGER.warn("Failed to create mob", (Throwable)var27);
|
||||
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(var27); // Paper - ServerExceptionEvent
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -381,7 +_,7 @@
|
||||
EntitySpawnReason.CHUNK_GENERATION,
|
||||
spawnGroupData
|
||||
);
|
||||
- levelAccessor.addFreshEntityWithPassengers(mob);
|
||||
+ levelAccessor.addFreshEntityWithPassengers(mob, SpawnReason.CHUNK_GEN); // CraftBukkit
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
@@ -501,8 +_,10 @@
|
||||
return this.unmodifiableMobCategoryCounts;
|
||||
}
|
||||
|
||||
- boolean canSpawnForCategoryGlobal(MobCategory category) {
|
||||
- int i = category.getMaxInstancesPerChunk() * this.spawnableChunkCount / NaturalSpawner.MAGIC_NUMBER;
|
||||
+ // CraftBukkit start
|
||||
+ boolean canSpawnForCategoryGlobal(MobCategory category, int limit) {
|
||||
+ int i = limit * this.spawnableChunkCount / NaturalSpawner.MAGIC_NUMBER;
|
||||
+ // CraftBukkit end
|
||||
return this.mobCategoryCounts.getInt(category) < i;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/world/level/PathNavigationRegion.java
|
||||
+++ b/net/minecraft/world/level/PathNavigationRegion.java
|
||||
@@ -8,6 +8,7 @@
|
||||
@@ -8,6 +_,7 @@
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
@ -8,19 +8,19 @@
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.biome.Biomes;
|
||||
@@ -66,7 +67,7 @@
|
||||
private ChunkAccess getChunk(int chunkX, int chunkZ) {
|
||||
int i = chunkX - this.centerX;
|
||||
int j = chunkZ - this.centerZ;
|
||||
- if (i >= 0 && i < this.chunks.length && j >= 0 && j < this.chunks[i].length) {
|
||||
+ if (i >= 0 && i < this.chunks.length && j >= 0 && j < this.chunks[i].length) { // Paper - if this changes, update getChunkIfLoaded below
|
||||
ChunkAccess chunkAccess = this.chunks[i][j];
|
||||
return (ChunkAccess)(chunkAccess != null ? chunkAccess : new EmptyLevelChunk(this.level, new ChunkPos(chunkX, chunkZ), this.plains.get()));
|
||||
@@ -66,13 +_,37 @@
|
||||
private ChunkAccess getChunk(int x, int z) {
|
||||
int i = x - this.centerX;
|
||||
int i1 = z - this.centerZ;
|
||||
- if (i >= 0 && i < this.chunks.length && i1 >= 0 && i1 < this.chunks[i].length) {
|
||||
+ if (i >= 0 && i < this.chunks.length && i1 >= 0 && i1 < this.chunks[i].length) { // Paper - if this changes, update getChunkIfLoaded below
|
||||
ChunkAccess chunkAccess = this.chunks[i][i1];
|
||||
return (ChunkAccess)(chunkAccess != null ? chunkAccess : new EmptyLevelChunk(this.level, new ChunkPos(x, z), this.plains.get()));
|
||||
} else {
|
||||
@@ -74,7 +75,31 @@
|
||||
return new EmptyLevelChunk(this.level, new ChunkPos(x, z), this.plains.get());
|
||||
}
|
||||
}
|
||||
|
||||
+
|
||||
+ // Paper start - if loaded util
|
||||
+ private @Nullable ChunkAccess getChunkIfLoaded(int x, int z) {
|
||||
+ // Based on getChunk(int, int)
|
||||
@ -32,7 +32,7 @@
|
||||
+ }
|
||||
+ return null;
|
||||
+ }
|
||||
@Override
|
||||
+ @Override
|
||||
+ public final FluidState getFluidIfLoaded(BlockPos blockposition) {
|
||||
+ ChunkAccess chunk = getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4);
|
||||
+ return chunk == null ? null : chunk.getFluidState(blockposition);
|
||||
@ -44,8 +44,6 @@
|
||||
+ return chunk == null ? null : chunk.getBlockState(blockposition);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
+ @Override
|
||||
|
||||
@Override
|
||||
public WorldBorder getWorldBorder() {
|
||||
return this.level.getWorldBorder();
|
||||
}
|
@ -1,23 +1,12 @@
|
||||
--- a/net/minecraft/world/level/ServerExplosion.java
|
||||
+++ b/net/minecraft/world/level/ServerExplosion.java
|
||||
@@ -22,18 +22,27 @@
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||
+import net.minecraft.world.entity.boss.EnderDragonPart;
|
||||
+import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.item.PrimedTnt;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.BaseFireBlock;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
-import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.gameevent.GameEvent;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
@@ -33,6 +_,18 @@
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
+// CraftBukkit start
|
||||
+import net.minecraft.world.entity.boss.EnderDragonPart;
|
||||
+import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
|
||||
+import net.minecraft.world.level.block.Blocks;
|
||||
+import net.minecraft.world.level.block.state.BlockState;
|
||||
+import org.bukkit.craftbukkit.event.CraftEventFactory;
|
||||
@ -26,77 +15,82 @@
|
||||
+import org.bukkit.Location;
|
||||
+import org.bukkit.event.block.BlockExplodeEvent;
|
||||
+// CraftBukkit end
|
||||
|
||||
+
|
||||
public class ServerExplosion implements Explosion {
|
||||
|
||||
@@ -50,16 +59,22 @@
|
||||
private static final ExplosionDamageCalculator EXPLOSION_DAMAGE_CALCULATOR = new ExplosionDamageCalculator();
|
||||
private static final int MAX_DROPS_PER_COMBINED_STACK = 16;
|
||||
@@ -47,6 +_,11 @@
|
||||
private final DamageSource damageSource;
|
||||
private final ExplosionDamageCalculator damageCalculator;
|
||||
private final Map<Player, Vec3> hitPlayers = new HashMap();
|
||||
private final Map<Player, Vec3> hitPlayers = new HashMap<>();
|
||||
+ // CraftBukkit - add field
|
||||
+ public boolean wasCanceled = false;
|
||||
+ public float yield;
|
||||
+ // CraftBukkit end
|
||||
+ public boolean excludeSourceFromDamage = true; // Paper - Allow explosions to damage source
|
||||
|
||||
public ServerExplosion(ServerLevel world, @Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, Vec3 pos, float power, boolean createFire, Explosion.BlockInteraction destructionType) {
|
||||
this.level = world;
|
||||
this.source = entity;
|
||||
- this.radius = power;
|
||||
+ this.radius = (float) Math.max(power, 0.0); // CraftBukkit - clamp bad values
|
||||
this.center = pos;
|
||||
this.fire = createFire;
|
||||
this.blockInteraction = destructionType;
|
||||
this.damageSource = damageSource == null ? world.damageSources().explosion(this) : damageSource;
|
||||
this.damageCalculator = behavior == null ? this.makeDamageCalculator(entity) : behavior;
|
||||
public ServerExplosion(
|
||||
ServerLevel level,
|
||||
@@ -60,12 +_,13 @@
|
||||
) {
|
||||
this.level = level;
|
||||
this.source = source;
|
||||
- this.radius = radius;
|
||||
+ this.radius = (float) Math.max(radius, 0.0); // CraftBukkit - clamp bad values
|
||||
this.center = center;
|
||||
this.fire = fire;
|
||||
this.blockInteraction = blockInteraction;
|
||||
this.damageSource = damageSource == null ? level.damageSources().explosion(this) : damageSource;
|
||||
this.damageCalculator = damageCalculator == null ? this.makeDamageCalculator(source) : damageCalculator;
|
||||
+ this.yield = this.blockInteraction == Explosion.BlockInteraction.DESTROY_WITH_DECAY ? 1.0F / this.radius : 1.0F; // CraftBukkit
|
||||
}
|
||||
|
||||
private ExplosionDamageCalculator makeDamageCalculator(@Nullable Entity entity) {
|
||||
@@ -135,7 +150,8 @@
|
||||
@@ -139,7 +_,8 @@
|
||||
for (float f1 = 0.3F; f > 0.0F; f -= 0.22500001F) {
|
||||
BlockPos blockposition = BlockPos.containing(d4, d5, d6);
|
||||
BlockState iblockdata = this.level.getBlockState(blockposition);
|
||||
- FluidState fluid = this.level.getFluidState(blockposition);
|
||||
+ if (!iblockdata.isDestroyable()) continue; // Paper - Protect Bedrock and End Portal/Frames from being destroyed
|
||||
+ FluidState fluid = iblockdata.getFluidState(); // Paper - Perf: Optimize call to getFluid for explosions
|
||||
|
||||
if (!this.level.isInWorldBounds(blockposition)) {
|
||||
BlockPos blockPos = BlockPos.containing(d3, d4, d5);
|
||||
BlockState blockState = this.level.getBlockState(blockPos);
|
||||
- FluidState fluidState = this.level.getFluidState(blockPos);
|
||||
+ if (!blockState.isDestroyable()) continue; // Paper - Protect Bedrock and End Portal/Frames from being destroyed
|
||||
+ FluidState fluidState = blockState.getFluidState(); // Paper - Perf: Optimize call to getFluid for explosions
|
||||
if (!this.level.isInWorldBounds(blockPos)) {
|
||||
break;
|
||||
@@ -149,6 +165,15 @@
|
||||
}
|
||||
@@ -152,6 +_,15 @@
|
||||
|
||||
if (f > 0.0F && this.damageCalculator.shouldBlockExplode(this, this.level, blockposition, iblockdata, f)) {
|
||||
set.add(blockposition);
|
||||
if (f > 0.0F && this.damageCalculator.shouldBlockExplode(this, this.level, blockPos, blockState, f)) {
|
||||
set.add(blockPos);
|
||||
+ // Paper start - prevent headless pistons from forming
|
||||
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowHeadlessPistons && iblockdata.getBlock() == Blocks.MOVING_PISTON) {
|
||||
+ net.minecraft.world.level.block.entity.BlockEntity extension = this.level.getBlockEntity(blockposition);
|
||||
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowHeadlessPistons && blockState.getBlock() == Blocks.MOVING_PISTON) {
|
||||
+ net.minecraft.world.level.block.entity.BlockEntity extension = this.level.getBlockEntity(blockPos);
|
||||
+ if (extension instanceof net.minecraft.world.level.block.piston.PistonMovingBlockEntity blockEntity && blockEntity.isSourcePiston()) {
|
||||
+ net.minecraft.core.Direction direction = iblockdata.getValue(net.minecraft.world.level.block.piston.PistonHeadBlock.FACING);
|
||||
+ set.add(blockposition.relative(direction.getOpposite()));
|
||||
+ net.minecraft.core.Direction direction = blockState.getValue(net.minecraft.world.level.block.piston.PistonHeadBlock.FACING);
|
||||
+ set.add(blockPos.relative(direction.getOpposite()));
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - prevent headless pistons from forming
|
||||
}
|
||||
|
||||
d4 += d0 * 0.30000001192092896D;
|
||||
@@ -171,7 +196,7 @@
|
||||
int l = Mth.floor(this.center.y + (double) f + 1.0D);
|
||||
int i1 = Mth.floor(this.center.z - (double) f - 1.0D);
|
||||
int j1 = Mth.floor(this.center.z + (double) f + 1.0D);
|
||||
- List<Entity> list = this.level.getEntities(this.source, new AABB((double) i, (double) k, (double) i1, (double) j, (double) l, (double) j1));
|
||||
+ List<Entity> list = this.level.getEntities(excludeSourceFromDamage ? this.source : null, new AABB((double) i, (double) k, (double) i1, (double) j, (double) l, (double) j1), (com.google.common.base.Predicate<Entity>) entity -> entity.isAlive() && !entity.isSpectator()); // Paper - Fix lag from explosions processing dead entities, Allow explosions to damage source
|
||||
Iterator iterator = list.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
@@ -192,10 +217,38 @@
|
||||
d3 /= d4;
|
||||
boolean flag = this.damageCalculator.shouldDamageEntity(this, entity);
|
||||
float f1 = this.damageCalculator.getKnockbackMultiplier(entity);
|
||||
- float f2 = !flag && f1 == 0.0F ? 0.0F : ServerExplosion.getSeenPercent(this.center, entity);
|
||||
+ float f2 = !flag && f1 == 0.0F ? 0.0F : this.getBlockDensity(this.center, entity); // Paper - Optimize explosions
|
||||
|
||||
if (flag) {
|
||||
- entity.hurtServer(this.level, this.damageSource, this.damageCalculator.getEntityDamageAmount(this, entity, f2));
|
||||
d3 += d * 0.3F;
|
||||
@@ -174,8 +_,8 @@
|
||||
int floor3 = Mth.floor(this.center.y + f + 1.0);
|
||||
int floor4 = Mth.floor(this.center.z - f - 1.0);
|
||||
int floor5 = Mth.floor(this.center.z + f + 1.0);
|
||||
-
|
||||
- for (Entity entity : this.level.getEntities(this.source, new AABB(floor, floor2, floor4, floor1, floor3, floor5))) {
|
||||
+ List <Entity> list = this.level.getEntities(excludeSourceFromDamage ? this.source : null, new AABB(floor, floor2, floor4, floor1, floor3, floor5), (com.google.common.base.Predicate<Entity>) entity -> entity.isAlive() && !entity.isSpectator()); // Paper - Fix lag from explosions processing dead entities, Allow explosions to damage source
|
||||
+ for (Entity entity : list) { // Paper - used in loop
|
||||
if (!entity.ignoreExplosion(this)) {
|
||||
double d = Math.sqrt(entity.distanceToSqr(this.center)) / f;
|
||||
if (d <= 1.0) {
|
||||
@@ -189,15 +_,43 @@
|
||||
d3 /= squareRoot;
|
||||
boolean shouldDamageEntity = this.damageCalculator.shouldDamageEntity(this, entity);
|
||||
float knockbackMultiplier = this.damageCalculator.getKnockbackMultiplier(entity);
|
||||
- float f1 = !shouldDamageEntity && knockbackMultiplier == 0.0F ? 0.0F : getSeenPercent(this.center, entity);
|
||||
+ float f1 = !shouldDamageEntity && knockbackMultiplier == 0.0F ? 0.0F : this.getBlockDensity(this.center, entity); // Paper - Optimize explosions
|
||||
if (shouldDamageEntity) {
|
||||
- entity.hurtServer(this.level, this.damageSource, this.damageCalculator.getEntityDamageAmount(this, entity, f1));
|
||||
+ // CraftBukkit start
|
||||
+
|
||||
+ // Special case ender dragon only give knockback if no damage is cancelled
|
||||
@ -115,11 +109,11 @@
|
||||
+ for (EnderDragonPart entityComplexPart : ((EnderDragon) entity).subEntities) {
|
||||
+ // Calculate damage separately for each EntityComplexPart
|
||||
+ if (list.contains(entityComplexPart)) {
|
||||
+ entityComplexPart.hurtServer(this.level, this.damageSource, this.damageCalculator.getEntityDamageAmount(this, entity, f2));
|
||||
+ entityComplexPart.hurtServer(this.level, this.damageSource, this.damageCalculator.getEntityDamageAmount(this, entity, f1));
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ entity.hurtServer(this.level, this.damageSource, this.damageCalculator.getEntityDamageAmount(this, entity, f2));
|
||||
+ entity.hurtServer(this.level, this.damageSource, this.damageCalculator.getEntityDamageAmount(this, entity, f1));
|
||||
+ }
|
||||
+
|
||||
+ if (entity.lastDamageCancelled) { // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Skip entity if damage event was cancelled
|
||||
@ -128,48 +122,45 @@
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
|
||||
double d5 = (1.0D - d0) * (double) f2 * (double) f1;
|
||||
@@ -204,7 +257,7 @@
|
||||
if (entity instanceof LivingEntity) {
|
||||
LivingEntity entityliving = (LivingEntity) entity;
|
||||
|
||||
- d6 = d5 * (1.0D - entityliving.getAttributeValue(Attributes.EXPLOSION_KNOCKBACK_RESISTANCE));
|
||||
+ d6 = entity instanceof Player && this.level.paperConfig().environment.disableExplosionKnockback ? 0 : d5 * (1.0D - entityliving.getAttributeValue(Attributes.EXPLOSION_KNOCKBACK_RESISTANCE)); // Paper
|
||||
double d4 = (1.0 - d) * f1 * knockbackMultiplier;
|
||||
double d5;
|
||||
if (entity instanceof LivingEntity livingEntity) {
|
||||
- d5 = d4 * (1.0 - livingEntity.getAttributeValue(Attributes.EXPLOSION_KNOCKBACK_RESISTANCE));
|
||||
+ d5 = entity instanceof Player && this.level.paperConfig().environment.disableExplosionKnockback ? 0 : d4 * (1.0 - livingEntity.getAttributeValue(Attributes.EXPLOSION_KNOCKBACK_RESISTANCE)); // Paper
|
||||
} else {
|
||||
d6 = d5;
|
||||
d5 = d4;
|
||||
}
|
||||
@@ -214,11 +267,19 @@
|
||||
d3 *= d6;
|
||||
Vec3 vec3d = new Vec3(d1, d2, d3);
|
||||
|
||||
@@ -206,10 +_,18 @@
|
||||
d2 *= d5;
|
||||
d3 *= d5;
|
||||
Vec3 vec3 = new Vec3(d1, d2, d3);
|
||||
+ // CraftBukkit start - Call EntityKnockbackEvent
|
||||
+ if (entity instanceof LivingEntity) {
|
||||
+ // Paper start - knockback events
|
||||
+ io.papermc.paper.event.entity.EntityKnockbackEvent event = CraftEventFactory.callEntityKnockbackEvent((org.bukkit.craftbukkit.entity.CraftLivingEntity) entity.getBukkitEntity(), this.source, this.damageSource.getEntity() != null ? this.damageSource.getEntity() : this.source, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.EXPLOSION, d6, vec3d);
|
||||
+ vec3d = event.isCancelled() ? Vec3.ZERO : org.bukkit.craftbukkit.util.CraftVector.toNMS(event.getKnockback());
|
||||
+ // Paper end - knockback events
|
||||
+ // Paper start - knockback events
|
||||
+ io.papermc.paper.event.entity.EntityKnockbackEvent event = CraftEventFactory.callEntityKnockbackEvent((org.bukkit.craftbukkit.entity.CraftLivingEntity) entity.getBukkitEntity(), this.source, this.damageSource.getEntity() != null ? this.damageSource.getEntity() : this.source, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.EXPLOSION, d5, vec3);
|
||||
+ vec3 = event.isCancelled() ? Vec3.ZERO : org.bukkit.craftbukkit.util.CraftVector.toNMS(event.getKnockback());
|
||||
+ // Paper end - knockback events
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
entity.push(vec3d);
|
||||
entity.push(vec3);
|
||||
if (entity instanceof Player) {
|
||||
Player entityhuman = (Player) entity;
|
||||
|
||||
- if (!entityhuman.isSpectator() && (!entityhuman.isCreative() || !entityhuman.getAbilities().flying)) {
|
||||
+ if (!entityhuman.isSpectator() && (!entityhuman.isCreative() || !entityhuman.getAbilities().flying) && !level.paperConfig().environment.disableExplosionKnockback) { // Paper - Option to disable explosion knockback
|
||||
this.hitPlayers.put(entityhuman, vec3d);
|
||||
Player player = (Player)entity;
|
||||
- if (!player.isSpectator() && (!player.isCreative() || !player.getAbilities().flying)) {
|
||||
+ if (!player.isSpectator() && (!player.isCreative() || !player.getAbilities().flying) && !level.paperConfig().environment.disableExplosionKnockback) { // Paper - Option to disable explosion knockback
|
||||
this.hitPlayers.put(player, vec3);
|
||||
}
|
||||
}
|
||||
@@ -235,10 +296,62 @@
|
||||
List<ServerExplosion.StackCollector> list1 = new ArrayList();
|
||||
@@ -225,7 +_,61 @@
|
||||
List<ServerExplosion.StackCollector> list = new ArrayList<>();
|
||||
Util.shuffle(blocks, this.level.random);
|
||||
|
||||
Util.shuffle(positions, this.level.random);
|
||||
+ // CraftBukkit start
|
||||
+ org.bukkit.World bworld = this.level.getWorld();
|
||||
+ Location location = CraftLocation.toBukkit(this.center, bworld);
|
||||
+
|
||||
+ List<org.bukkit.block.Block> blockList = new ObjectArrayList<>();
|
||||
+ for (int i1 = positions.size() - 1; i1 >= 0; i1--) {
|
||||
+ BlockPos cpos = positions.get(i1);
|
||||
+ for (int i1 = blocks.size() - 1; i1 >= 0; i1--) {
|
||||
+ BlockPos cpos = blocks.get(i1);
|
||||
+ org.bukkit.block.Block bblock = bworld.getBlockAt(cpos.getX(), cpos.getY(), cpos.getZ());
|
||||
+ if (!bblock.getType().isAir()) {
|
||||
+ blockList.add(bblock);
|
||||
@ -192,49 +183,47 @@
|
||||
+ this.yield = event.getYield();
|
||||
+ }
|
||||
+
|
||||
+ positions.clear();
|
||||
+ blocks.clear();
|
||||
+
|
||||
+ for (org.bukkit.block.Block bblock : bukkitBlocks) {
|
||||
+ BlockPos coords = new BlockPos(bblock.getX(), bblock.getY(), bblock.getZ());
|
||||
+ positions.add(coords);
|
||||
+ blocks.add(coords);
|
||||
+ }
|
||||
+
|
||||
+ if (this.wasCanceled) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
Iterator iterator = positions.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
BlockPos blockposition = (BlockPos) iterator.next();
|
||||
+
|
||||
for (BlockPos blockPos : blocks) {
|
||||
+ // CraftBukkit start - TNTPrimeEvent
|
||||
+ BlockState iblockdata = this.level.getBlockState(blockposition);
|
||||
+ BlockState iblockdata = this.level.getBlockState(blockPos);
|
||||
+ Block block = iblockdata.getBlock();
|
||||
+ if (block instanceof net.minecraft.world.level.block.TntBlock) {
|
||||
+ Entity sourceEntity = this.source == null ? null : this.source;
|
||||
+ BlockPos sourceBlock = sourceEntity == null ? BlockPos.containing(this.center) : null;
|
||||
+ if (!CraftEventFactory.callTNTPrimeEvent(this.level, blockposition, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.EXPLOSION, sourceEntity, sourceBlock)) {
|
||||
+ this.level.sendBlockUpdated(blockposition, Blocks.AIR.defaultBlockState(), iblockdata, 3); // Update the block on the client
|
||||
+ if (!CraftEventFactory.callTNTPrimeEvent(this.level, blockPos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.EXPLOSION, sourceEntity, sourceBlock)) {
|
||||
+ this.level.sendBlockUpdated(blockPos, Blocks.AIR.defaultBlockState(), iblockdata, 3); // Update the block on the client
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
|
||||
this.level.getBlockState(blockposition).onExplosionHit(this.level, blockposition, this, (itemstack, blockposition1) -> {
|
||||
ServerExplosion.addOrAppendStack(list1, itemstack, blockposition1);
|
||||
@@ -262,13 +375,22 @@
|
||||
BlockPos blockposition = (BlockPos) iterator.next();
|
||||
|
||||
if (this.level.random.nextInt(3) == 0 && this.level.getBlockState(blockposition).isAir() && this.level.getBlockState(blockposition.below()).isSolidRender()) {
|
||||
- this.level.setBlockAndUpdate(blockposition, BaseFireBlock.getState(this.level, blockposition));
|
||||
+
|
||||
this.level
|
||||
.getBlockState(blockPos)
|
||||
.onExplosionHit(this.level, blockPos, this, (itemStack, blockPos1) -> addOrAppendStack(list, itemStack, blockPos1));
|
||||
@@ -239,12 +_,21 @@
|
||||
private void createFire(List<BlockPos> blocks) {
|
||||
for (BlockPos blockPos : blocks) {
|
||||
if (this.level.random.nextInt(3) == 0 && this.level.getBlockState(blockPos).isAir() && this.level.getBlockState(blockPos.below()).isSolidRender()) {
|
||||
- this.level.setBlockAndUpdate(blockPos, BaseFireBlock.getState(this.level, blockPos));
|
||||
+ // CraftBukkit start - Ignition by explosion
|
||||
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.level, blockposition, this).isCancelled()) {
|
||||
+ this.level.setBlockAndUpdate(blockposition, BaseFireBlock.getState(this.level, blockposition));
|
||||
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.level, blockPos, this).isCancelled()) {
|
||||
+ this.level.setBlockAndUpdate(blockPos, BaseFireBlock.getState(this.level, blockPos));
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void explode() {
|
||||
@ -243,22 +232,23 @@
|
||||
+ return;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
this.level.gameEvent(this.source, (Holder) GameEvent.EXPLODE, this.center);
|
||||
this.level.gameEvent(this.source, GameEvent.EXPLODE, this.center);
|
||||
List<BlockPos> list = this.calculateExplodedPositions();
|
||||
|
||||
@@ -288,6 +410,7 @@
|
||||
this.hurtEntities();
|
||||
@@ -261,6 +_,7 @@
|
||||
}
|
||||
|
||||
private static void addOrAppendStack(List<ServerExplosion.StackCollector> droppedItemsOut, ItemStack item, BlockPos pos) {
|
||||
+ if (item.isEmpty()) return; // CraftBukkit - SPIGOT-5425
|
||||
Iterator iterator = droppedItemsOut.iterator();
|
||||
|
||||
do {
|
||||
@@ -372,4 +495,85 @@
|
||||
|
||||
private static void addOrAppendStack(List<ServerExplosion.StackCollector> stackCollectors, ItemStack stack, BlockPos pos) {
|
||||
+ if (stack.isEmpty()) return; // CraftBukkit - SPIGOT-5425
|
||||
for (ServerExplosion.StackCollector stackCollector : stackCollectors) {
|
||||
stackCollector.tryMerge(stack);
|
||||
if (stack.isEmpty()) {
|
||||
@@ -342,4 +_,86 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
+
|
||||
+
|
||||
+ // Paper start - Optimize explosions
|
||||
+ private float getBlockDensity(Vec3 vec3d, Entity entity) {
|
||||
+ if (!this.level.paperConfig().environment.optimizeExplosions) {
|
@ -1,13 +1,14 @@
|
||||
--- a/net/minecraft/world/level/ServerLevelAccessor.java
|
||||
+++ b/net/minecraft/world/level/ServerLevelAccessor.java
|
||||
@@ -8,6 +8,17 @@
|
||||
@@ -7,6 +_,17 @@
|
||||
ServerLevel getLevel();
|
||||
|
||||
default void addFreshEntityWithPassengers(Entity entity) {
|
||||
- entity.getSelfAndPassengers().forEach(this::addFreshEntity);
|
||||
- }
|
||||
+ // CraftBukkit start
|
||||
+ this.addFreshEntityWithPassengers(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT);
|
||||
}
|
||||
+ }
|
||||
+
|
||||
+ default void addFreshEntityWithPassengers(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) {
|
||||
+ entity.getSelfAndPassengers().forEach((e) -> this.addFreshEntity(e, reason));
|
@ -1,20 +1,21 @@
|
||||
--- a/net/minecraft/world/level/StructureManager.java
|
||||
+++ b/net/minecraft/world/level/StructureManager.java
|
||||
@@ -48,7 +48,12 @@
|
||||
@@ -48,7 +_,13 @@
|
||||
}
|
||||
|
||||
public List<StructureStart> startsForStructure(ChunkPos pos, Predicate<Structure> predicate) {
|
||||
- Map<Structure, LongSet> map = this.level.getChunk(pos.x, pos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences();
|
||||
public List<StructureStart> startsForStructure(ChunkPos chunkPos, Predicate<Structure> structurePredicate) {
|
||||
- Map<Structure, LongSet> allReferences = this.level.getChunk(chunkPos.x, chunkPos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences();
|
||||
+ // Paper start - Fix swamp hut cat generation deadlock
|
||||
+ return this.startsForStructure(pos, predicate, null);
|
||||
+ return this.startsForStructure(chunkPos, structurePredicate, null);
|
||||
+ }
|
||||
+ public List<StructureStart> startsForStructure(ChunkPos pos, Predicate<Structure> predicate, @Nullable ServerLevelAccessor levelAccessor) {
|
||||
+ Map<Structure, LongSet> map = (levelAccessor == null ? this.level : levelAccessor).getChunk(pos.x, pos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences();
|
||||
+
|
||||
+ public List<StructureStart> startsForStructure(ChunkPos chunkPos, Predicate<Structure> structurePredicate, @Nullable ServerLevelAccessor levelAccessor) {
|
||||
+ Map<Structure, LongSet> allReferences = (levelAccessor == null ? this.level : levelAccessor).getChunk(chunkPos.x, chunkPos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences();
|
||||
+ // Paper end - Fix swamp hut cat generation deadlock
|
||||
Builder<StructureStart> builder = ImmutableList.builder();
|
||||
|
||||
for (Entry<Structure, LongSet> entry : map.entrySet()) {
|
||||
@@ -116,10 +121,20 @@
|
||||
for (Entry<Structure, LongSet> entry : allReferences.entrySet()) {
|
||||
@@ -118,10 +_,20 @@
|
||||
}
|
||||
|
||||
public StructureStart getStructureWithPieceAt(BlockPos pos, Predicate<Holder<Structure>> predicate) {
|
@ -1,167 +0,0 @@
|
||||
--- a/net/minecraft/world/level/BaseSpawner.java
|
||||
+++ b/net/minecraft/world/level/BaseSpawner.java
|
||||
@@ -49,15 +49,17 @@
|
||||
public int maxNearbyEntities = 6;
|
||||
public int requiredPlayerRange = 16;
|
||||
public int spawnRange = 4;
|
||||
+ private int tickDelay = 0; // Paper - Configurable mob spawner tick rate
|
||||
|
||||
public BaseSpawner() {}
|
||||
|
||||
public void setEntityId(EntityType<?> type, @Nullable Level world, RandomSource random, BlockPos pos) {
|
||||
this.getOrCreateNextSpawnData(world, random, pos).getEntityToSpawn().putString("id", BuiltInRegistries.ENTITY_TYPE.getKey(type).toString());
|
||||
+ this.spawnPotentials = SimpleWeightedRandomList.empty(); // CraftBukkit - SPIGOT-3496, MC-92282
|
||||
}
|
||||
|
||||
public boolean isNearPlayer(Level world, BlockPos pos) {
|
||||
- return world.hasNearbyAlivePlayer((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, (double) this.requiredPlayerRange);
|
||||
+ return world.hasNearbyAlivePlayerThatAffectsSpawning((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, (double) this.requiredPlayerRange); // Paper - Affects Spawning API
|
||||
}
|
||||
|
||||
public void clientTick(Level world, BlockPos pos) {
|
||||
@@ -82,13 +84,19 @@
|
||||
}
|
||||
|
||||
public void serverTick(ServerLevel world, BlockPos pos) {
|
||||
+ if (spawnCount <= 0 || maxNearbyEntities <= 0) return; // Paper - Ignore impossible spawn tick
|
||||
+ // Paper start - Configurable mob spawner tick rate
|
||||
+ if (spawnDelay > 0 && --tickDelay > 0) return;
|
||||
+ tickDelay = world.paperConfig().tickRates.mobSpawner;
|
||||
+ if (tickDelay == -1) { return; } // If disabled
|
||||
+ // Paper end - Configurable mob spawner tick rate
|
||||
if (this.isNearPlayer(world, pos)) {
|
||||
- if (this.spawnDelay == -1) {
|
||||
+ if (this.spawnDelay < -tickDelay) { // Paper - Configurable mob spawner tick rate
|
||||
this.delay(world, pos);
|
||||
}
|
||||
|
||||
if (this.spawnDelay > 0) {
|
||||
- --this.spawnDelay;
|
||||
+ this.spawnDelay -= tickDelay; // Paper - Configurable mob spawner tick rate
|
||||
} else {
|
||||
boolean flag = false;
|
||||
RandomSource randomsource = world.getRandom();
|
||||
@@ -125,6 +133,20 @@
|
||||
} else if (!SpawnPlacements.checkSpawnRules((EntityType) optional.get(), world, EntitySpawnReason.SPAWNER, blockposition1, world.getRandom())) {
|
||||
continue;
|
||||
}
|
||||
+ // Paper start - PreCreatureSpawnEvent
|
||||
+ com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent event = new com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent(
|
||||
+ io.papermc.paper.util.MCUtil.toLocation(world, d0, d1, d2),
|
||||
+ org.bukkit.craftbukkit.entity.CraftEntityType.minecraftToBukkit(optional.get()),
|
||||
+ io.papermc.paper.util.MCUtil.toLocation(world, pos)
|
||||
+ );
|
||||
+ if (!event.callEvent()) {
|
||||
+ flag = true;
|
||||
+ if (event.shouldAbortSpawn()) {
|
||||
+ break;
|
||||
+ }
|
||||
+ continue;
|
||||
+ }
|
||||
+ // Paper end - PreCreatureSpawnEvent
|
||||
|
||||
Entity entity = EntityType.loadEntityRecursive(nbttagcompound, world, EntitySpawnReason.SPAWNER, (entity1) -> {
|
||||
entity1.moveTo(d0, d1, d2, entity1.getYRot(), entity1.getXRot());
|
||||
@@ -143,6 +165,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
+ entity.preserveMotion = true; // Paper - Fix Entity Teleportation and cancel velocity if teleported; preserve entity motion from tag
|
||||
entity.moveTo(entity.getX(), entity.getY(), entity.getZ(), randomsource.nextFloat() * 360.0F, 0.0F);
|
||||
if (entity instanceof Mob) {
|
||||
Mob entityinsentient = (Mob) entity;
|
||||
@@ -157,13 +180,27 @@
|
||||
((Mob) entity).finalizeSpawn(world, world.getCurrentDifficultyAt(entity.blockPosition()), EntitySpawnReason.SPAWNER, (SpawnGroupData) null);
|
||||
}
|
||||
|
||||
- Optional optional1 = mobspawnerdata.getEquipment();
|
||||
+ Optional<net.minecraft.world.entity.EquipmentTable> optional1 = mobspawnerdata.getEquipment(); // CraftBukkit - decompile error
|
||||
|
||||
Objects.requireNonNull(entityinsentient);
|
||||
optional1.ifPresent(entityinsentient::equip);
|
||||
+ // Spigot Start
|
||||
+ if ( entityinsentient.level().spigotConfig.nerfSpawnerMobs )
|
||||
+ {
|
||||
+ entityinsentient.aware = false;
|
||||
+ }
|
||||
+ // Spigot End
|
||||
}
|
||||
|
||||
- if (!world.tryAddFreshEntityWithPassengers(entity)) {
|
||||
+ entity.spawnedViaMobSpawner = true; // Paper
|
||||
+ entity.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER; // Paper - Entity#getEntitySpawnReason
|
||||
+ flag = true; // Paper
|
||||
+ // CraftBukkit start
|
||||
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callSpawnerSpawnEvent(entity, pos).isCancelled()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (!world.tryAddFreshEntityWithPassengers(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER)) {
|
||||
+ // CraftBukkit end
|
||||
this.delay(world, pos);
|
||||
return;
|
||||
}
|
||||
@@ -174,7 +211,7 @@
|
||||
((Mob) entity).spawnAnim();
|
||||
}
|
||||
|
||||
- flag = true;
|
||||
+ //flag = true; // Paper - moved up above cancellable event
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +239,13 @@
|
||||
}
|
||||
|
||||
public void load(@Nullable Level world, BlockPos pos, CompoundTag nbt) {
|
||||
+ // Paper start - use larger int if set
|
||||
+ if (nbt.contains("Paper.Delay")) {
|
||||
+ this.spawnDelay = nbt.getInt("Paper.Delay");
|
||||
+ } else {
|
||||
this.spawnDelay = nbt.getShort("Delay");
|
||||
+ }
|
||||
+ // Paper end
|
||||
boolean flag = nbt.contains("SpawnData", 10);
|
||||
|
||||
if (flag) {
|
||||
@@ -225,9 +268,15 @@
|
||||
this.spawnPotentials = SimpleWeightedRandomList.single(this.nextSpawnData != null ? this.nextSpawnData : new SpawnData());
|
||||
}
|
||||
|
||||
+ // Paper start - use ints if set
|
||||
+ if (nbt.contains("Paper.MinSpawnDelay", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) {
|
||||
+ this.minSpawnDelay = nbt.getInt("Paper.MinSpawnDelay");
|
||||
+ this.maxSpawnDelay = nbt.getInt("Paper.MaxSpawnDelay");
|
||||
+ this.spawnCount = nbt.getShort("SpawnCount");
|
||||
+ } else // Paper end
|
||||
if (nbt.contains("MinSpawnDelay", 99)) {
|
||||
- this.minSpawnDelay = nbt.getShort("MinSpawnDelay");
|
||||
- this.maxSpawnDelay = nbt.getShort("MaxSpawnDelay");
|
||||
+ this.minSpawnDelay = nbt.getInt("MinSpawnDelay"); // Paper - short -> int
|
||||
+ this.maxSpawnDelay = nbt.getInt("MaxSpawnDelay"); // Paper - short -> int
|
||||
this.spawnCount = nbt.getShort("SpawnCount");
|
||||
}
|
||||
|
||||
@@ -244,9 +293,20 @@
|
||||
}
|
||||
|
||||
public CompoundTag save(CompoundTag nbt) {
|
||||
- nbt.putShort("Delay", (short) this.spawnDelay);
|
||||
- nbt.putShort("MinSpawnDelay", (short) this.minSpawnDelay);
|
||||
- nbt.putShort("MaxSpawnDelay", (short) this.maxSpawnDelay);
|
||||
+ // Paper start
|
||||
+ if (spawnDelay > Short.MAX_VALUE) {
|
||||
+ nbt.putInt("Paper.Delay", this.spawnDelay);
|
||||
+ }
|
||||
+ nbt.putShort("Delay", (short) Math.min(Short.MAX_VALUE, this.spawnDelay));
|
||||
+
|
||||
+ if (minSpawnDelay > Short.MAX_VALUE || maxSpawnDelay > Short.MAX_VALUE) {
|
||||
+ nbt.putInt("Paper.MinSpawnDelay", this.minSpawnDelay);
|
||||
+ nbt.putInt("Paper.MaxSpawnDelay", this.maxSpawnDelay);
|
||||
+ }
|
||||
+
|
||||
+ nbt.putShort("MinSpawnDelay", (short) Math.min(Short.MAX_VALUE, this.minSpawnDelay));
|
||||
+ nbt.putShort("MaxSpawnDelay", (short) Math.min(Short.MAX_VALUE, this.maxSpawnDelay));
|
||||
+ // Paper end
|
||||
nbt.putShort("SpawnCount", (short) this.spawnCount);
|
||||
nbt.putShort("MaxNearbyEntities", (short) this.maxNearbyEntities);
|
||||
nbt.putShort("RequiredPlayerRange", (short) this.requiredPlayerRange);
|
@ -1,90 +0,0 @@
|
||||
--- a/net/minecraft/world/level/BlockGetter.java
|
||||
+++ b/net/minecraft/world/level/BlockGetter.java
|
||||
@@ -12,6 +12,7 @@
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.util.Mth;
|
||||
+import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
@@ -31,11 +32,20 @@
|
||||
default <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos pos, BlockEntityType<T> type) {
|
||||
BlockEntity tileentity = this.getBlockEntity(pos);
|
||||
|
||||
- return tileentity != null && tileentity.getType() == type ? Optional.of(tileentity) : Optional.empty();
|
||||
+ return tileentity != null && tileentity.getType() == type ? (Optional<T>) Optional.of(tileentity) : Optional.empty(); // CraftBukkit - decompile error
|
||||
}
|
||||
|
||||
BlockState getBlockState(BlockPos pos);
|
||||
+ // Paper start - if loaded util
|
||||
+ @Nullable BlockState getBlockStateIfLoaded(BlockPos blockposition);
|
||||
|
||||
+ default @Nullable Block getBlockIfLoaded(BlockPos blockposition) {
|
||||
+ BlockState type = this.getBlockStateIfLoaded(blockposition);
|
||||
+ return type == null ? null : type.getBlock();
|
||||
+ }
|
||||
+ @Nullable FluidState getFluidIfLoaded(BlockPos blockposition);
|
||||
+ // Paper end
|
||||
+
|
||||
FluidState getFluidState(BlockPos pos);
|
||||
|
||||
default int getLightEmission(BlockPos pos) {
|
||||
@@ -59,10 +69,25 @@
|
||||
});
|
||||
}
|
||||
|
||||
- default BlockHitResult clip(ClipContext context) {
|
||||
- return (BlockHitResult) BlockGetter.traverseBlocks(context.getFrom(), context.getTo(), context, (raytrace1, blockposition) -> {
|
||||
- BlockState iblockdata = this.getBlockState(blockposition);
|
||||
- FluidState fluid = this.getFluidState(blockposition);
|
||||
+ // CraftBukkit start - moved block handling into separate method for use by Block#rayTrace
|
||||
+ default BlockHitResult clip(ClipContext raytrace1, BlockPos blockposition) {
|
||||
+ // Paper start - Add predicate for blocks when raytracing
|
||||
+ return clip(raytrace1, blockposition, null);
|
||||
+ }
|
||||
+
|
||||
+ default BlockHitResult clip(ClipContext raytrace1, BlockPos blockposition, java.util.function.Predicate<? super org.bukkit.block.Block> canCollide) {
|
||||
+ // Paper end - Add predicate for blocks when raytracing
|
||||
+ // Paper start - Prevent raytrace from loading chunks
|
||||
+ BlockState iblockdata = this.getBlockStateIfLoaded(blockposition);
|
||||
+ if (iblockdata == null) {
|
||||
+ // copied the last function parameter (listed below)
|
||||
+ Vec3 vec3d = raytrace1.getFrom().subtract(raytrace1.getTo());
|
||||
+
|
||||
+ return BlockHitResult.miss(raytrace1.getTo(), Direction.getApproximateNearest(vec3d.x, vec3d.y, vec3d.z), BlockPos.containing(raytrace1.getTo()));
|
||||
+ }
|
||||
+ // Paper end - Prevent raytrace from loading chunks
|
||||
+ if (iblockdata.isAir() || (canCollide != null && this instanceof LevelAccessor levelAccessor && !canCollide.test(org.bukkit.craftbukkit.block.CraftBlock.at(levelAccessor, blockposition)))) return null; // Paper - Perf: optimise air cases & check canCollide predicate
|
||||
+ FluidState fluid = iblockdata.getFluidState(); // Paper - Perf: don't need to go to world state again
|
||||
Vec3 vec3d = raytrace1.getFrom();
|
||||
Vec3 vec3d1 = raytrace1.getTo();
|
||||
VoxelShape voxelshape = raytrace1.getBlockShape(iblockdata, this, blockposition);
|
||||
@@ -73,6 +98,18 @@
|
||||
double d1 = movingobjectpositionblock1 == null ? Double.MAX_VALUE : raytrace1.getFrom().distanceToSqr(movingobjectpositionblock1.getLocation());
|
||||
|
||||
return d0 <= d1 ? movingobjectpositionblock : movingobjectpositionblock1;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
+ default BlockHitResult clip(ClipContext context) {
|
||||
+ // Paper start - Add predicate for blocks when raytracing
|
||||
+ return clip(context, (java.util.function.Predicate<org.bukkit.block.Block>) null);
|
||||
+ }
|
||||
+
|
||||
+ default BlockHitResult clip(ClipContext context, java.util.function.Predicate<? super org.bukkit.block.Block> canCollide) {
|
||||
+ // Paper end - Add predicate for blocks when raytracing
|
||||
+ return (BlockHitResult) BlockGetter.traverseBlocks(context.getFrom(), context.getTo(), context, (raytrace1, blockposition) -> {
|
||||
+ return this.clip(raytrace1, blockposition, canCollide); // CraftBukkit - moved into separate method // Paper - Add predicate for blocks when raytracing
|
||||
}, (raytrace1) -> {
|
||||
Vec3 vec3d = raytrace1.getFrom().subtract(raytrace1.getTo());
|
||||
|
||||
@@ -145,7 +182,7 @@
|
||||
double d13 = d10 * (i1 > 0 ? 1.0D - Mth.frac(d4) : Mth.frac(d4));
|
||||
double d14 = d11 * (j1 > 0 ? 1.0D - Mth.frac(d5) : Mth.frac(d5));
|
||||
|
||||
- Object object;
|
||||
+ T object; // CraftBukkit - decompile error
|
||||
|
||||
do {
|
||||
if (d12 > 1.0D && d13 > 1.0D && d14 > 1.0D) {
|
@ -1,20 +0,0 @@
|
||||
--- a/net/minecraft/world/level/ClipContext.java
|
||||
+++ b/net/minecraft/world/level/ClipContext.java
|
||||
@@ -22,7 +22,7 @@
|
||||
private final CollisionContext collisionContext;
|
||||
|
||||
public ClipContext(Vec3 start, Vec3 end, ClipContext.Block shapeType, ClipContext.Fluid fluidHandling, Entity entity) {
|
||||
- this(start, end, shapeType, fluidHandling, CollisionContext.of(entity));
|
||||
+ this(start, end, shapeType, fluidHandling, (entity == null) ? CollisionContext.empty() : CollisionContext.of(entity)); // CraftBukkit
|
||||
}
|
||||
|
||||
public ClipContext(Vec3 start, Vec3 end, ClipContext.Block shapeType, ClipContext.Fluid fluidHandling, CollisionContext shapeContext) {
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
private final Predicate<FluidState> canPick;
|
||||
|
||||
- private Fluid(final Predicate predicate) {
|
||||
+ private Fluid(final Predicate<FluidState> predicate) { // CraftBukkit - decompile error
|
||||
this.canPick = predicate;
|
||||
}
|
||||
|
@ -1,321 +0,0 @@
|
||||
--- a/net/minecraft/world/level/GameRules.java
|
||||
+++ b/net/minecraft/world/level/GameRules.java
|
||||
@@ -36,6 +36,14 @@
|
||||
|
||||
public class GameRules {
|
||||
|
||||
+ // Paper start - allow disabling gamerule limits
|
||||
+ private static final boolean DISABLE_LIMITS = Boolean.getBoolean("paper.disableGameRuleLimits");
|
||||
+
|
||||
+ private static int limit(final int limit, final int unlimited) {
|
||||
+ return DISABLE_LIMITS ? unlimited : limit;
|
||||
+ }
|
||||
+ // Paper end - allow disabling gamerule limits
|
||||
+
|
||||
public static final int DEFAULT_RANDOM_TICK_SPEED = 3;
|
||||
static final Logger LOGGER = LogUtils.getLogger();
|
||||
private static final Map<GameRules.Key<?>, GameRules.Type<?>> GAME_RULE_TYPES = Maps.newTreeMap(Comparator.comparing((gamerules_gamerulekey) -> {
|
||||
@@ -58,7 +66,7 @@
|
||||
public static final GameRules.Key<GameRules.BooleanValue> RULE_SENDCOMMANDFEEDBACK = GameRules.register("sendCommandFeedback", GameRules.Category.CHAT, GameRules.BooleanValue.create(true));
|
||||
public static final GameRules.Key<GameRules.BooleanValue> RULE_REDUCEDDEBUGINFO = GameRules.register("reducedDebugInfo", GameRules.Category.MISC, GameRules.BooleanValue.create(false, (minecraftserver, gamerules_gameruleboolean) -> {
|
||||
int i = gamerules_gameruleboolean.get() ? 22 : 23;
|
||||
- Iterator iterator = minecraftserver.getPlayerList().getPlayers().iterator();
|
||||
+ Iterator iterator = minecraftserver.players().iterator(); // CraftBukkit - per-world
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
ServerPlayer entityplayer = (ServerPlayer) iterator.next();
|
||||
@@ -74,7 +82,7 @@
|
||||
public static final GameRules.Key<GameRules.IntegerValue> RULE_MAX_ENTITY_CRAMMING = GameRules.register("maxEntityCramming", GameRules.Category.MOBS, GameRules.IntegerValue.create(24));
|
||||
public static final GameRules.Key<GameRules.BooleanValue> RULE_WEATHER_CYCLE = GameRules.register("doWeatherCycle", GameRules.Category.UPDATES, GameRules.BooleanValue.create(true));
|
||||
public static final GameRules.Key<GameRules.BooleanValue> RULE_LIMITED_CRAFTING = GameRules.register("doLimitedCrafting", GameRules.Category.PLAYER, GameRules.BooleanValue.create(false, (minecraftserver, gamerules_gameruleboolean) -> {
|
||||
- Iterator iterator = minecraftserver.getPlayerList().getPlayers().iterator();
|
||||
+ Iterator iterator = minecraftserver.players().iterator(); // CraftBukkit - per-world
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
ServerPlayer entityplayer = (ServerPlayer) iterator.next();
|
||||
@@ -90,7 +98,7 @@
|
||||
public static final GameRules.Key<GameRules.BooleanValue> RULE_DISABLE_RAIDS = GameRules.register("disableRaids", GameRules.Category.MOBS, GameRules.BooleanValue.create(false));
|
||||
public static final GameRules.Key<GameRules.BooleanValue> RULE_DOINSOMNIA = GameRules.register("doInsomnia", GameRules.Category.SPAWNING, GameRules.BooleanValue.create(true));
|
||||
public static final GameRules.Key<GameRules.BooleanValue> RULE_DO_IMMEDIATE_RESPAWN = GameRules.register("doImmediateRespawn", GameRules.Category.PLAYER, GameRules.BooleanValue.create(false, (minecraftserver, gamerules_gameruleboolean) -> {
|
||||
- Iterator iterator = minecraftserver.getPlayerList().getPlayers().iterator();
|
||||
+ Iterator iterator = minecraftserver.players().iterator(); // CraftBukkit - per-world
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
ServerPlayer entityplayer = (ServerPlayer) iterator.next();
|
||||
@@ -120,15 +128,16 @@
|
||||
public static final GameRules.Key<GameRules.BooleanValue> RULE_GLOBAL_SOUND_EVENTS = GameRules.register("globalSoundEvents", GameRules.Category.MISC, GameRules.BooleanValue.create(true));
|
||||
public static final GameRules.Key<GameRules.BooleanValue> RULE_DO_VINES_SPREAD = GameRules.register("doVinesSpread", GameRules.Category.UPDATES, GameRules.BooleanValue.create(true));
|
||||
public static final GameRules.Key<GameRules.BooleanValue> RULE_ENDER_PEARLS_VANISH_ON_DEATH = GameRules.register("enderPearlsVanishOnDeath", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true));
|
||||
- public static final GameRules.Key<GameRules.IntegerValue> RULE_MINECART_MAX_SPEED = GameRules.register("minecartMaxSpeed", GameRules.Category.MISC, GameRules.IntegerValue.create(8, 1, 1000, FeatureFlagSet.of(FeatureFlags.MINECART_IMPROVEMENTS), (minecraftserver, gamerules_gameruleint) -> {
|
||||
+ public static final GameRules.Key<GameRules.IntegerValue> RULE_MINECART_MAX_SPEED = GameRules.register("minecartMaxSpeed", GameRules.Category.MISC, GameRules.IntegerValue.create(8, 1, limit(1000, Integer.MAX_VALUE), FeatureFlagSet.of(FeatureFlags.MINECART_IMPROVEMENTS), (minecraftserver, gamerules_gameruleint) -> { // Paper - allow disabling gamerule limits
|
||||
}));
|
||||
- public static final GameRules.Key<GameRules.IntegerValue> RULE_SPAWN_CHUNK_RADIUS = GameRules.register("spawnChunkRadius", GameRules.Category.MISC, GameRules.IntegerValue.create(2, 0, 32, FeatureFlagSet.of(), (minecraftserver, gamerules_gameruleint) -> {
|
||||
- ServerLevel worldserver = minecraftserver.overworld();
|
||||
+ public static final GameRules.Key<GameRules.IntegerValue> RULE_SPAWN_CHUNK_RADIUS = GameRules.register("spawnChunkRadius", GameRules.Category.MISC, GameRules.IntegerValue.create(2, 0, limit(32, Integer.MAX_VALUE), FeatureFlagSet.of(), (minecraftserver, gamerules_gameruleint) -> { // Paper - allow disabling gamerule limits
|
||||
+ ServerLevel worldserver = minecraftserver; // CraftBukkit - per-world
|
||||
|
||||
worldserver.setDefaultSpawnPos(worldserver.getSharedSpawnPos(), worldserver.getSharedSpawnAngle());
|
||||
}));
|
||||
private final Map<GameRules.Key<?>, GameRules.Value<?>> rules;
|
||||
private final FeatureFlagSet enabledFeatures;
|
||||
+ private final GameRules.Value<?>[] gameruleArray; // Paper - Perf: Use array for gamerule storage
|
||||
|
||||
private static <T extends GameRules.Value<T>> GameRules.Key<T> register(String name, GameRules.Category category, GameRules.Type<T> type) {
|
||||
GameRules.Key<T> gamerules_gamerulekey = new GameRules.Key<>(name, category);
|
||||
@@ -161,10 +170,21 @@
|
||||
private GameRules(Map<GameRules.Key<?>, GameRules.Value<?>> rules, FeatureFlagSet enabledFeatures) {
|
||||
this.rules = rules;
|
||||
this.enabledFeatures = enabledFeatures;
|
||||
+
|
||||
+ // Paper start - Perf: Use array for gamerule storage
|
||||
+ int arraySize = GameRules.Key.lastGameRuleIndex + 1;
|
||||
+ GameRules.Value<?>[] values = new GameRules.Value[arraySize];
|
||||
+
|
||||
+ for (Entry<GameRules.Key<?>, GameRules.Value<?>> entry : rules.entrySet()) {
|
||||
+ values[entry.getKey().gameRuleIndex] = entry.getValue();
|
||||
+ }
|
||||
+
|
||||
+ this.gameruleArray = values;
|
||||
+ // Paper end - Perf: Use array for gamerule storage
|
||||
}
|
||||
|
||||
public <T extends GameRules.Value<T>> T getRule(GameRules.Key<T> key) {
|
||||
- T t0 = (GameRules.Value) this.rules.get(key);
|
||||
+ T t0 = key == null ? null : (T) this.gameruleArray[key.gameRuleIndex]; // Paper - Perf: Use array for gamerule storage
|
||||
|
||||
if (t0 == null) {
|
||||
throw new IllegalArgumentException("Tried to access invalid game rule");
|
||||
@@ -184,7 +204,7 @@
|
||||
|
||||
private void loadFromTag(DynamicLike<?> values) {
|
||||
this.rules.forEach((gamerules_gamerulekey, gamerules_gamerulevalue) -> {
|
||||
- DataResult dataresult = values.get(gamerules_gamerulekey.id).asString();
|
||||
+ DataResult<String> dataresult = values.get(gamerules_gamerulekey.id).asString(); // CraftBukkit - decompile error
|
||||
|
||||
Objects.requireNonNull(gamerules_gamerulevalue);
|
||||
dataresult.ifSuccess(gamerules_gamerulevalue::deserialize);
|
||||
@@ -205,22 +225,22 @@
|
||||
|
||||
private <T extends GameRules.Value<T>> void callVisitorCap(GameRules.GameRuleTypeVisitor visitor, GameRules.Key<?> key, GameRules.Type<?> type) {
|
||||
if (type.requiredFeatures.isSubsetOf(this.enabledFeatures)) {
|
||||
- visitor.visit(key, type);
|
||||
- type.callVisitor(visitor, key);
|
||||
+ visitor.visit((GameRules.Key<T>) key, (GameRules.Type<T>) type); // CraftBukkit - decompile error
|
||||
+ ((GameRules.Type<T>) type).callVisitor(visitor, (GameRules.Key<T>) key); // CraftBukkit - decompile error
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- public void assignFrom(GameRules rules, @Nullable MinecraftServer server) {
|
||||
- rules.rules.keySet().forEach((gamerules_gamerulekey) -> {
|
||||
- this.assignCap(gamerules_gamerulekey, rules, server);
|
||||
+ public void assignFrom(GameRules gamerules, @Nullable ServerLevel minecraftserver) { // CraftBukkit - per-world
|
||||
+ gamerules.rules.keySet().forEach((gamerules_gamerulekey) -> {
|
||||
+ this.assignCap(gamerules_gamerulekey, gamerules, minecraftserver);
|
||||
});
|
||||
}
|
||||
|
||||
- private <T extends GameRules.Value<T>> void assignCap(GameRules.Key<T> key, GameRules rules, @Nullable MinecraftServer server) {
|
||||
- T t0 = rules.getRule(key);
|
||||
+ private <T extends GameRules.Value<T>> void assignCap(GameRules.Key<T> gamerules_gamerulekey, GameRules gamerules, @Nullable ServerLevel minecraftserver) { // CraftBukkit - per-world
|
||||
+ T t0 = gamerules.getRule(gamerules_gamerulekey);
|
||||
|
||||
- this.getRule(key).setFrom(t0, server);
|
||||
+ this.getRule(gamerules_gamerulekey).setFrom(t0, minecraftserver);
|
||||
}
|
||||
|
||||
public boolean getBoolean(GameRules.Key<GameRules.BooleanValue> rule) {
|
||||
@@ -232,6 +252,10 @@
|
||||
}
|
||||
|
||||
public static final class Key<T extends GameRules.Value<T>> {
|
||||
+ // Paper start - Perf: Use array for gamerule storage
|
||||
+ public static int lastGameRuleIndex = 0;
|
||||
+ public final int gameRuleIndex = lastGameRuleIndex++;
|
||||
+ // Paper end - Perf: Use array for gamerule storage
|
||||
|
||||
final String id;
|
||||
private final GameRules.Category category;
|
||||
@@ -285,11 +309,11 @@
|
||||
|
||||
final Supplier<ArgumentType<?>> argument;
|
||||
private final Function<GameRules.Type<T>, T> constructor;
|
||||
- final BiConsumer<MinecraftServer, T> callback;
|
||||
+ final BiConsumer<ServerLevel, T> callback; // CraftBukkit - per-world
|
||||
private final GameRules.VisitorCaller<T> visitorCaller;
|
||||
final FeatureFlagSet requiredFeatures;
|
||||
|
||||
- Type(Supplier<ArgumentType<?>> argumentType, Function<GameRules.Type<T>, T> ruleFactory, BiConsumer<MinecraftServer, T> changeCallback, GameRules.VisitorCaller<T> ruleAcceptor, FeatureFlagSet requiredFeatures) {
|
||||
+ Type(Supplier<ArgumentType<?>> argumentType, Function<GameRules.Type<T>, T> ruleFactory, BiConsumer<ServerLevel, T> changeCallback, GameRules.VisitorCaller<T> ruleAcceptor, FeatureFlagSet requiredFeatures) { // CraftBukkit - per-world
|
||||
this.argument = argumentType;
|
||||
this.constructor = ruleFactory;
|
||||
this.callback = changeCallback;
|
||||
@@ -302,7 +326,7 @@
|
||||
}
|
||||
|
||||
public T createRule() {
|
||||
- return (GameRules.Value) this.constructor.apply(this);
|
||||
+ return this.constructor.apply(this); // CraftBukkit - decompile error
|
||||
}
|
||||
|
||||
public void callVisitor(GameRules.GameRuleTypeVisitor consumer, GameRules.Key<T> key) {
|
||||
@@ -322,21 +346,21 @@
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
- protected abstract void updateFromArgument(CommandContext<CommandSourceStack> context, String name);
|
||||
+ protected abstract void updateFromArgument(CommandContext<CommandSourceStack> context, String name, GameRules.Key<T> gameRuleKey); // Paper - Add WorldGameRuleChangeEvent
|
||||
|
||||
- public void setFromArgument(CommandContext<CommandSourceStack> context, String name) {
|
||||
- this.updateFromArgument(context, name);
|
||||
- this.onChanged(((CommandSourceStack) context.getSource()).getServer());
|
||||
+ public void setFromArgument(CommandContext<CommandSourceStack> context, String name, GameRules.Key<T> gameRuleKey) { // Paper - Add WorldGameRuleChangeEvent
|
||||
+ this.updateFromArgument(context, name, gameRuleKey); // Paper - Add WorldGameRuleChangeEvent
|
||||
+ this.onChanged(((CommandSourceStack) context.getSource()).getLevel()); // CraftBukkit - per-world
|
||||
}
|
||||
|
||||
- public void onChanged(@Nullable MinecraftServer server) {
|
||||
- if (server != null) {
|
||||
- this.type.callback.accept(server, this.getSelf());
|
||||
+ public void onChanged(@Nullable ServerLevel minecraftserver) { // CraftBukkit - per-world
|
||||
+ if (minecraftserver != null) {
|
||||
+ this.type.callback.accept(minecraftserver, this.getSelf());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- protected abstract void deserialize(String value);
|
||||
+ public abstract void deserialize(String value); // PAIL - private->public
|
||||
|
||||
public abstract String serialize();
|
||||
|
||||
@@ -350,7 +374,7 @@
|
||||
|
||||
protected abstract T copy();
|
||||
|
||||
- public abstract void setFrom(T rule, @Nullable MinecraftServer server);
|
||||
+ public abstract void setFrom(T t0, @Nullable ServerLevel minecraftserver); // CraftBukkit - per-world
|
||||
}
|
||||
|
||||
public interface GameRuleTypeVisitor {
|
||||
@@ -366,7 +390,7 @@
|
||||
|
||||
private boolean value;
|
||||
|
||||
- static GameRules.Type<GameRules.BooleanValue> create(boolean initialValue, BiConsumer<MinecraftServer, GameRules.BooleanValue> changeCallback) {
|
||||
+ static GameRules.Type<GameRules.BooleanValue> create(boolean initialValue, BiConsumer<ServerLevel, GameRules.BooleanValue> changeCallback) { // CraftBukkit - per-world
|
||||
return new GameRules.Type<>(BoolArgumentType::bool, (gamerules_gameruledefinition) -> {
|
||||
return new GameRules.BooleanValue(gamerules_gameruledefinition, initialValue);
|
||||
}, changeCallback, GameRules.GameRuleTypeVisitor::visitBoolean, FeatureFlagSet.of());
|
||||
@@ -383,17 +407,20 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
- protected void updateFromArgument(CommandContext<CommandSourceStack> context, String name) {
|
||||
- this.value = BoolArgumentType.getBool(context, name);
|
||||
+ protected void updateFromArgument(CommandContext<CommandSourceStack> context, String name, GameRules.Key<BooleanValue> gameRuleKey) { // Paper start - Add WorldGameRuleChangeEvent
|
||||
+ io.papermc.paper.event.world.WorldGameRuleChangeEvent event = new io.papermc.paper.event.world.WorldGameRuleChangeEvent(context.getSource().getBukkitWorld(), context.getSource().getBukkitSender(), (org.bukkit.GameRule<Boolean>) org.bukkit.GameRule.getByName(gameRuleKey.toString()), String.valueOf(BoolArgumentType.getBool(context, name)));
|
||||
+ if (!event.callEvent()) return;
|
||||
+ this.value = Boolean.parseBoolean(event.getValue());
|
||||
+ // Paper end - Add WorldGameRuleChangeEvent
|
||||
}
|
||||
|
||||
public boolean get() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
- public void set(boolean value, @Nullable MinecraftServer server) {
|
||||
- this.value = value;
|
||||
- this.onChanged(server);
|
||||
+ public void set(boolean flag, @Nullable ServerLevel minecraftserver) { // CraftBukkit - per-world
|
||||
+ this.value = flag;
|
||||
+ this.onChanged(minecraftserver);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -402,7 +429,7 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
- protected void deserialize(String value) {
|
||||
+ public void deserialize(String value) { // PAIL - protected->public
|
||||
this.value = Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
@@ -421,9 +448,9 @@
|
||||
return new GameRules.BooleanValue(this.type, this.value);
|
||||
}
|
||||
|
||||
- public void setFrom(GameRules.BooleanValue rule, @Nullable MinecraftServer server) {
|
||||
- this.value = rule.value;
|
||||
- this.onChanged(server);
|
||||
+ public void setFrom(GameRules.BooleanValue gamerules_gameruleboolean, @Nullable ServerLevel minecraftserver) { // CraftBukkit - per-world
|
||||
+ this.value = gamerules_gameruleboolean.value;
|
||||
+ this.onChanged(minecraftserver);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,13 +458,13 @@
|
||||
|
||||
private int value;
|
||||
|
||||
- private static GameRules.Type<GameRules.IntegerValue> create(int initialValue, BiConsumer<MinecraftServer, GameRules.IntegerValue> changeCallback) {
|
||||
+ private static GameRules.Type<GameRules.IntegerValue> create(int initialValue, BiConsumer<ServerLevel, GameRules.IntegerValue> changeCallback) { // CraftBukkit - per-world
|
||||
return new GameRules.Type<>(IntegerArgumentType::integer, (gamerules_gameruledefinition) -> {
|
||||
return new GameRules.IntegerValue(gamerules_gameruledefinition, initialValue);
|
||||
}, changeCallback, GameRules.GameRuleTypeVisitor::visitInteger, FeatureFlagSet.of());
|
||||
}
|
||||
|
||||
- static GameRules.Type<GameRules.IntegerValue> create(int initialValue, int min, int max, FeatureFlagSet requiredFeatures, BiConsumer<MinecraftServer, GameRules.IntegerValue> changeCallback) {
|
||||
+ static GameRules.Type<GameRules.IntegerValue> create(int initialValue, int min, int max, FeatureFlagSet requiredFeatures, BiConsumer<ServerLevel, GameRules.IntegerValue> changeCallback) { // CraftBukkit - per-world
|
||||
return new GameRules.Type<>(() -> {
|
||||
return IntegerArgumentType.integer(min, max);
|
||||
}, (gamerules_gameruledefinition) -> {
|
||||
@@ -456,17 +483,20 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
- protected void updateFromArgument(CommandContext<CommandSourceStack> context, String name) {
|
||||
- this.value = IntegerArgumentType.getInteger(context, name);
|
||||
+ protected void updateFromArgument(CommandContext<CommandSourceStack> context, String name, GameRules.Key<IntegerValue> gameRuleKey) { // Paper start - Add WorldGameRuleChangeEvent
|
||||
+ io.papermc.paper.event.world.WorldGameRuleChangeEvent event = new io.papermc.paper.event.world.WorldGameRuleChangeEvent(context.getSource().getBukkitWorld(), context.getSource().getBukkitSender(), (org.bukkit.GameRule<Integer>) org.bukkit.GameRule.getByName(gameRuleKey.toString()), String.valueOf(IntegerArgumentType.getInteger(context, name)));
|
||||
+ if (!event.callEvent()) return;
|
||||
+ this.value = Integer.parseInt(event.getValue());
|
||||
+ // Paper end - Add WorldGameRuleChangeEvent
|
||||
}
|
||||
|
||||
public int get() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
- public void set(int value, @Nullable MinecraftServer server) {
|
||||
- this.value = value;
|
||||
- this.onChanged(server);
|
||||
+ public void set(int i, @Nullable ServerLevel minecraftserver) { // CraftBukkit - per-world
|
||||
+ this.value = i;
|
||||
+ this.onChanged(minecraftserver);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -475,7 +505,7 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
- protected void deserialize(String value) {
|
||||
+ public void deserialize(String value) { // PAIL - protected->public
|
||||
this.value = IntegerValue.safeParse(value);
|
||||
}
|
||||
|
||||
@@ -517,9 +547,9 @@
|
||||
return new GameRules.IntegerValue(this.type, this.value);
|
||||
}
|
||||
|
||||
- public void setFrom(GameRules.IntegerValue rule, @Nullable MinecraftServer server) {
|
||||
- this.value = rule.value;
|
||||
- this.onChanged(server);
|
||||
+ public void setFrom(GameRules.IntegerValue gamerules_gameruleint, @Nullable ServerLevel minecraftserver) { // CraftBukkit - per-world
|
||||
+ this.value = gamerules_gameruleint.value;
|
||||
+ this.onChanged(minecraftserver);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +0,0 @@
|
||||
--- a/net/minecraft/world/level/LevelAccessor.java
|
||||
+++ b/net/minecraft/world/level/LevelAccessor.java
|
||||
@@ -101,4 +101,6 @@
|
||||
default void gameEvent(ResourceKey<GameEvent> event, BlockPos pos, GameEvent.Context emitter) {
|
||||
this.gameEvent((Holder) this.registryAccess().lookupOrThrow(Registries.GAME_EVENT).getOrThrow(event), pos, emitter);
|
||||
}
|
||||
+
|
||||
+ net.minecraft.server.level.ServerLevel getMinecraftWorld(); // CraftBukkit
|
||||
}
|
@ -1,212 +0,0 @@
|
||||
--- a/net/minecraft/world/level/NaturalSpawner.java
|
||||
+++ b/net/minecraft/world/level/NaturalSpawner.java
|
||||
@@ -47,8 +47,13 @@
|
||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||
import net.minecraft.world.level.levelgen.structure.structures.NetherFortressStructure;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
+import net.minecraft.world.level.storage.LevelData;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.slf4j.Logger;
|
||||
+import org.bukkit.craftbukkit.util.CraftSpawnCategory;
|
||||
+import org.bukkit.entity.SpawnCategory;
|
||||
+import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
|
||||
+// CraftBukkit end
|
||||
|
||||
public final class NaturalSpawner {
|
||||
|
||||
@@ -82,6 +87,13 @@
|
||||
MobCategory enumcreaturetype = entity.getType().getCategory();
|
||||
|
||||
if (enumcreaturetype != MobCategory.MISC) {
|
||||
+ // Paper start - Only count natural spawns
|
||||
+ if (!entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
|
||||
+ !(entity.spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL ||
|
||||
+ entity.spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ // Paper end - Only count natural spawns
|
||||
BlockPos blockposition = entity.blockPosition();
|
||||
|
||||
chunkSource.query(ChunkPos.asLong(blockposition), (chunk) -> {
|
||||
@@ -107,15 +119,31 @@
|
||||
return (Biome) chunk.getNoiseBiome(QuartPos.fromBlock(pos.getX()), QuartPos.fromBlock(pos.getY()), QuartPos.fromBlock(pos.getZ())).value();
|
||||
}
|
||||
|
||||
- public static List<MobCategory> getFilteredSpawningCategories(NaturalSpawner.SpawnState info, boolean spawnAnimals, boolean spawnMonsters, boolean rare) {
|
||||
+ // CraftBukkit start - add server
|
||||
+ public static List<MobCategory> getFilteredSpawningCategories(NaturalSpawner.SpawnState spawnercreature_d, boolean flag, boolean flag1, boolean flag2, ServerLevel worldserver) {
|
||||
+ LevelData worlddata = worldserver.getLevelData(); // CraftBukkit - Other mob type spawn tick rate
|
||||
+ // CraftBukkit end
|
||||
List<MobCategory> list = new ArrayList(NaturalSpawner.SPAWNING_CATEGORIES.length);
|
||||
MobCategory[] aenumcreaturetype = NaturalSpawner.SPAWNING_CATEGORIES;
|
||||
int i = aenumcreaturetype.length;
|
||||
|
||||
for (int j = 0; j < i; ++j) {
|
||||
MobCategory enumcreaturetype = aenumcreaturetype[j];
|
||||
+ // CraftBukkit start - Use per-world spawn limits
|
||||
+ boolean spawnThisTick = true;
|
||||
+ int limit = enumcreaturetype.getMaxInstancesPerChunk();
|
||||
+ SpawnCategory spawnCategory = CraftSpawnCategory.toBukkit(enumcreaturetype);
|
||||
+ if (CraftSpawnCategory.isValidForLimits(spawnCategory)) {
|
||||
+ spawnThisTick = worldserver.ticksPerSpawnCategory.getLong(spawnCategory) != 0 && worlddata.getGameTime() % worldserver.ticksPerSpawnCategory.getLong(spawnCategory) == 0;
|
||||
+ limit = worldserver.getWorld().getSpawnLimit(spawnCategory);
|
||||
+ }
|
||||
|
||||
- if ((spawnAnimals || !enumcreaturetype.isFriendly()) && (spawnMonsters || enumcreaturetype.isFriendly()) && (rare || !enumcreaturetype.isPersistent()) && info.canSpawnForCategoryGlobal(enumcreaturetype)) {
|
||||
+ if (!spawnThisTick || limit == 0) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if ((flag || !enumcreaturetype.isFriendly()) && (flag1 || enumcreaturetype.isFriendly()) && (flag2 || !enumcreaturetype.isPersistent()) && spawnercreature_d.canSpawnForCategoryGlobal(enumcreaturetype, limit)) {
|
||||
+ // CraftBukkit end
|
||||
list.add(enumcreaturetype);
|
||||
}
|
||||
}
|
||||
@@ -144,6 +172,16 @@
|
||||
gameprofilerfiller.pop();
|
||||
}
|
||||
|
||||
+ // Paper start - Add mobcaps commands
|
||||
+ public static int globalLimitForCategory(final ServerLevel level, final MobCategory category, final int spawnableChunkCount) {
|
||||
+ final int categoryLimit = level.getWorld().getSpawnLimitUnsafe(CraftSpawnCategory.toBukkit(category));
|
||||
+ if (categoryLimit < 1) {
|
||||
+ return categoryLimit;
|
||||
+ }
|
||||
+ return categoryLimit * spawnableChunkCount / NaturalSpawner.MAGIC_NUMBER;
|
||||
+ }
|
||||
+ // Paper end - Add mobcaps commands
|
||||
+
|
||||
public static void spawnCategoryForChunk(MobCategory group, ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner) {
|
||||
BlockPos blockposition = NaturalSpawner.getRandomPosWithin(world, chunk);
|
||||
|
||||
@@ -164,9 +202,9 @@
|
||||
StructureManager structuremanager = world.structureManager();
|
||||
ChunkGenerator chunkgenerator = world.getChunkSource().getGenerator();
|
||||
int i = pos.getY();
|
||||
- BlockState iblockdata = chunk.getBlockState(pos);
|
||||
+ BlockState iblockdata = world.getBlockStateIfLoadedAndInBounds(pos); // Paper - don't load chunks for mob spawn
|
||||
|
||||
- if (!iblockdata.isRedstoneConductor(chunk, pos)) {
|
||||
+ if (iblockdata != null && !iblockdata.isRedstoneConductor(chunk, pos)) { // Paper - don't load chunks for mob spawn
|
||||
BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
|
||||
int j = 0;
|
||||
int k = 0;
|
||||
@@ -195,7 +233,7 @@
|
||||
if (entityhuman != null) {
|
||||
double d2 = entityhuman.distanceToSqr(d0, (double) i, d1);
|
||||
|
||||
- if (NaturalSpawner.isRightDistanceToPlayerAndSpawnPoint(world, chunk, blockposition_mutableblockposition, d2)) {
|
||||
+ if (world.isLoadedAndInBounds(blockposition_mutableblockposition) && NaturalSpawner.isRightDistanceToPlayerAndSpawnPoint(world, chunk, blockposition_mutableblockposition, d2)) { // Paper - don't load chunks for mob spawn
|
||||
if (biomesettingsmobs_c == null) {
|
||||
Optional<MobSpawnSettings.SpawnerData> optional = NaturalSpawner.getRandomSpawnMobAt(world, structuremanager, chunkgenerator, group, world.random, blockposition_mutableblockposition);
|
||||
|
||||
@@ -207,7 +245,13 @@
|
||||
j1 = biomesettingsmobs_c.minCount + world.random.nextInt(1 + biomesettingsmobs_c.maxCount - biomesettingsmobs_c.minCount);
|
||||
}
|
||||
|
||||
- if (NaturalSpawner.isValidSpawnPostitionForType(world, group, structuremanager, chunkgenerator, biomesettingsmobs_c, blockposition_mutableblockposition, d2) && checker.test(biomesettingsmobs_c.type, blockposition_mutableblockposition, chunk)) {
|
||||
+ // Paper start - PreCreatureSpawnEvent
|
||||
+ PreSpawnStatus doSpawning = isValidSpawnPostitionForType(world, group, structuremanager, chunkgenerator, biomesettingsmobs_c, blockposition_mutableblockposition, d2);
|
||||
+ if (doSpawning == PreSpawnStatus.ABORT) {
|
||||
+ return;
|
||||
+ }
|
||||
+ if (doSpawning == PreSpawnStatus.SUCCESS && checker.test(biomesettingsmobs_c.type, blockposition_mutableblockposition, chunk)) {
|
||||
+ // Paper end - PreCreatureSpawnEvent
|
||||
Mob entityinsentient = NaturalSpawner.getMobForSpawn(world, biomesettingsmobs_c.type);
|
||||
|
||||
if (entityinsentient == null) {
|
||||
@@ -217,10 +261,15 @@
|
||||
entityinsentient.moveTo(d0, (double) i, d1, world.random.nextFloat() * 360.0F, 0.0F);
|
||||
if (NaturalSpawner.isValidPositionForMob(world, entityinsentient, d2)) {
|
||||
groupdataentity = entityinsentient.finalizeSpawn(world, world.getCurrentDifficultyAt(entityinsentient.blockPosition()), EntitySpawnReason.NATURAL, groupdataentity);
|
||||
- ++j;
|
||||
- ++k1;
|
||||
- world.addFreshEntityWithPassengers(entityinsentient);
|
||||
- runner.run(entityinsentient, chunk);
|
||||
+ // CraftBukkit start
|
||||
+ // SPIGOT-7045: Give ocelot babies back their special spawn reason. Note: This is the only modification required as ocelots count as monsters which means they only spawn during normal chunk ticking and do not spawn during chunk generation as starter mobs.
|
||||
+ world.addFreshEntityWithPassengers(entityinsentient, (entityinsentient instanceof net.minecraft.world.entity.animal.Ocelot && !((org.bukkit.entity.Ageable) entityinsentient.getBukkitEntity()).isAdult()) ? SpawnReason.OCELOT_BABY : SpawnReason.NATURAL);
|
||||
+ if (!entityinsentient.isRemoved()) {
|
||||
+ ++j;
|
||||
+ ++k1;
|
||||
+ runner.run(entityinsentient, chunk);
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
if (j >= entityinsentient.getMaxSpawnClusterSize()) {
|
||||
return;
|
||||
}
|
||||
@@ -250,10 +299,31 @@
|
||||
return squaredDistance <= 576.0D ? false : (world.getSharedSpawnPos().closerToCenterThan(new Vec3((double) pos.getX() + 0.5D, (double) pos.getY(), (double) pos.getZ() + 0.5D), 24.0D) ? false : Objects.equals(new ChunkPos(pos), chunk.getPos()) || world.isNaturalSpawningAllowed((BlockPos) pos));
|
||||
}
|
||||
|
||||
- private static boolean isValidSpawnPostitionForType(ServerLevel world, MobCategory group, StructureManager structureAccessor, ChunkGenerator chunkGenerator, MobSpawnSettings.SpawnerData spawnEntry, BlockPos.MutableBlockPos pos, double squaredDistance) {
|
||||
+ // Paper start - PreCreatureSpawnEvent
|
||||
+ private enum PreSpawnStatus {
|
||||
+ FAIL,
|
||||
+ SUCCESS,
|
||||
+ CANCELLED,
|
||||
+ ABORT
|
||||
+ }
|
||||
+ private static PreSpawnStatus isValidSpawnPostitionForType(ServerLevel world, MobCategory group, StructureManager structureAccessor, ChunkGenerator chunkGenerator, MobSpawnSettings.SpawnerData spawnEntry, BlockPos.MutableBlockPos pos, double squaredDistance) {
|
||||
+ // Paper end - PreCreatureSpawnEvent
|
||||
EntityType<?> entitytypes = spawnEntry.type;
|
||||
|
||||
- return entitytypes.getCategory() == MobCategory.MISC ? false : (!entitytypes.canSpawnFarFromPlayer() && squaredDistance > (double) (entitytypes.getCategory().getDespawnDistance() * entitytypes.getCategory().getDespawnDistance()) ? false : (entitytypes.canSummon() && NaturalSpawner.canSpawnMobAt(world, structureAccessor, chunkGenerator, group, spawnEntry, pos) ? (!SpawnPlacements.isSpawnPositionOk(entitytypes, world, pos) ? false : (!SpawnPlacements.checkSpawnRules(entitytypes, world, EntitySpawnReason.NATURAL, pos, world.random) ? false : world.noCollision(entitytypes.getSpawnAABB((double) pos.getX() + 0.5D, (double) pos.getY(), (double) pos.getZ() + 0.5D)))) : false));
|
||||
+ // Paper start - PreCreatureSpawnEvent
|
||||
+ com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
|
||||
+ io.papermc.paper.util.MCUtil.toLocation(world, pos),
|
||||
+ org.bukkit.craftbukkit.entity.CraftEntityType.minecraftToBukkit(entitytypes), SpawnReason.NATURAL
|
||||
+ );
|
||||
+ if (!event.callEvent()) {
|
||||
+ if (event.shouldAbortSpawn()) {
|
||||
+ return PreSpawnStatus.ABORT;
|
||||
+ }
|
||||
+ return PreSpawnStatus.CANCELLED;
|
||||
+ }
|
||||
+ // Paper end - PreCreatureSpawnEvent
|
||||
+
|
||||
+ return entitytypes.getCategory() == MobCategory.MISC ? PreSpawnStatus.FAIL : (!entitytypes.canSpawnFarFromPlayer() && squaredDistance > (double) (entitytypes.getCategory().getDespawnDistance() * entitytypes.getCategory().getDespawnDistance()) ? PreSpawnStatus.FAIL : (entitytypes.canSummon() && NaturalSpawner.canSpawnMobAt(world, structureAccessor, chunkGenerator, group, spawnEntry, pos) ? (!SpawnPlacements.isSpawnPositionOk(entitytypes, world, pos) ? PreSpawnStatus.FAIL : (!SpawnPlacements.checkSpawnRules(entitytypes, world, EntitySpawnReason.NATURAL, pos, world.random) ? PreSpawnStatus.FAIL : world.noCollision(entitytypes.getSpawnAABB((double) pos.getX() + 0.5D, (double) pos.getY(), (double) pos.getZ() + 0.5D)) ? PreSpawnStatus.SUCCESS : PreSpawnStatus.FAIL)) : PreSpawnStatus.FAIL)); // Paper - PreCreatureSpawnEvent
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -268,6 +338,7 @@
|
||||
NaturalSpawner.LOGGER.warn("Can't spawn entity of type: {}", BuiltInRegistries.ENTITY_TYPE.getKey(type));
|
||||
} catch (Exception exception) {
|
||||
NaturalSpawner.LOGGER.warn("Failed to create mob", exception);
|
||||
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper - ServerExceptionEvent
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -356,6 +427,7 @@
|
||||
entity = biomesettingsmobs_c.type.create(world.getLevel(), EntitySpawnReason.NATURAL);
|
||||
} catch (Exception exception) {
|
||||
NaturalSpawner.LOGGER.warn("Failed to create mob", exception);
|
||||
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper - ServerExceptionEvent
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -369,7 +441,7 @@
|
||||
|
||||
if (entityinsentient.checkSpawnRules(world, EntitySpawnReason.CHUNK_GENERATION) && entityinsentient.checkSpawnObstruction(world)) {
|
||||
groupdataentity = entityinsentient.finalizeSpawn(world, world.getCurrentDifficultyAt(entityinsentient.blockPosition()), EntitySpawnReason.CHUNK_GENERATION, groupdataentity);
|
||||
- world.addFreshEntityWithPassengers(entityinsentient);
|
||||
+ world.addFreshEntityWithPassengers(entityinsentient, SpawnReason.CHUNK_GEN); // CraftBukkit
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
@@ -482,10 +554,12 @@
|
||||
return this.unmodifiableMobCategoryCounts;
|
||||
}
|
||||
|
||||
- boolean canSpawnForCategoryGlobal(MobCategory group) {
|
||||
- int i = group.getMaxInstancesPerChunk() * this.spawnableChunkCount / NaturalSpawner.MAGIC_NUMBER;
|
||||
+ // CraftBukkit start
|
||||
+ boolean canSpawnForCategoryGlobal(MobCategory enumcreaturetype, int limit) {
|
||||
+ int i = limit * this.spawnableChunkCount / NaturalSpawner.MAGIC_NUMBER;
|
||||
+ // CraftBukkit end
|
||||
|
||||
- return this.mobCategoryCounts.getInt(group) < i;
|
||||
+ return this.mobCategoryCounts.getInt(enumcreaturetype) < i;
|
||||
}
|
||||
|
||||
boolean canSpawnForCategoryLocal(MobCategory group, ChunkPos chunkPos) {
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren