diff --git a/paper-server/patches/sources/net/minecraft/server/level/ChunkMap.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ChunkMap.java.patch index f402fda9f2..79e4932dd1 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ChunkMap.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ChunkMap.java.patch @@ -100,7 +100,23 @@ } void forEachSpawnCandidateChunk(Consumer callback) { -@@ -1424,7 +1458,7 @@ +@@ -1215,6 +1249,7 @@ + } + + public void addEntity(Entity entity) { ++ org.spigotmc.AsyncCatcher.catchOp("entity track"); // Spigot + if (!(entity instanceof EnderDragonPart)) { + EntityType entitytypes = entity.getType(); + int i = entitytypes.clientTrackingRange() * 16; +@@ -1250,6 +1285,7 @@ + } + + protected void removeEntity(Entity entity) { ++ org.spigotmc.AsyncCatcher.catchOp("entity untrack"); // Spigot + if (entity instanceof ServerPlayer entityplayer) { + this.updatePlayerStatus(entityplayer, false); + ObjectIterator objectiterator = this.entityMap.values().iterator(); +@@ -1424,7 +1460,7 @@ public final Set seenBy = Sets.newIdentityHashSet(); public TrackedEntity(final Entity entity, final int i, final int j, final boolean flag) { @@ -109,7 +125,23 @@ this.entity = entity; this.range = i; this.lastSectionPos = SectionPos.of((EntityAccess) entity); -@@ -1484,6 +1518,11 @@ +@@ -1469,6 +1505,7 @@ + } + + public void removePlayer(ServerPlayer player) { ++ org.spigotmc.AsyncCatcher.catchOp("player tracker clear"); // Spigot + if (this.seenBy.remove(player.connection)) { + this.serverEntity.removePairing(player); + } +@@ -1476,6 +1513,7 @@ + } + + public void updatePlayer(ServerPlayer player) { ++ org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot + if (player != this.entity) { + Vec3 vec3d = player.position().subtract(this.entity.position()); + int i = ChunkMap.this.getPlayerViewDistance(player); +@@ -1484,6 +1522,11 @@ double d2 = d0 * d0; boolean flag = d1 <= d2 && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z); diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch index 88d306b6fb..aa947ffaa4 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch @@ -78,7 +78,7 @@ + // CraftBukkit start + public final LevelStorageSource.LevelStorageAccess convertable; + public final UUID uuid; -+ + + public LevelChunk getChunkIfLoaded(int x, int z) { + return this.chunkSource.getChunk(x, z, false); + } @@ -102,7 +102,7 @@ + ChunkGenerator chunkgenerator = worlddimension.generator(); + // CraftBukkit start + this.serverLevelData.setWorld(this); - ++ + if (biomeProvider != null) { + BiomeSource worldChunkManager = new CustomWorldChunkManager(this.getWorld(), biomeProvider, this.server.registryAccess().lookupOrThrow(Registries.BIOME)); + if (chunkgenerator instanceof NoiseBasedChunkGenerator cga) { @@ -284,14 +284,14 @@ - this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.THUNDER_LEVEL_CHANGE, this.thunderLevel)); + this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.RAIN_LEVEL_CHANGE, this.rainLevel)); + this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.THUNDER_LEVEL_CHANGE, this.thunderLevel)); - } ++ } + // */ + for (int idx = 0; idx < this.players.size(); ++idx) { + if (((ServerPlayer) this.players.get(idx)).level() == this) { + ((ServerPlayer) this.players.get(idx)).tickWeather(); + } + } - ++ + if (flag != this.isRaining()) { + // Only send weather packets to those affected + for (int idx = 0; idx < this.players.size(); ++idx) { @@ -299,14 +299,14 @@ + ((ServerPlayer) this.players.get(idx)).setPlayerWeather((!flag ? WeatherType.DOWNFALL : WeatherType.CLEAR), false); + } + } -+ } + } + for (int idx = 0; idx < this.players.size(); ++idx) { + if (((ServerPlayer) this.players.get(idx)).level() == this) { + ((ServerPlayer) this.players.get(idx)).updateWeather(this.oRainLevel, this.rainLevel, this.oThunderLevel, this.thunderLevel); + } + } + // CraftBukkit end -+ + } @VisibleForTesting @@ -421,13 +421,14 @@ } } -@@ -939,24 +1061,37 @@ +@@ -939,24 +1061,38 @@ this.entityManager.addNewEntity(player); } - private boolean addEntity(Entity entity) { + // CraftBukkit start + private boolean addEntity(Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { ++ org.spigotmc.AsyncCatcher.catchOp("entity add"); // Spigot if (entity.isRemoved()) { - ServerLevel.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityType.getKey(entity.getType())); + // WorldServer.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityTypes.getKey(entity.getType())); // CraftBukkit @@ -463,7 +464,7 @@ return true; } } -@@ -967,13 +1102,35 @@ +@@ -967,13 +1103,35 @@ } public void removePlayerImmediately(ServerPlayer player, Entity.RemovalReason reason) { @@ -500,7 +501,7 @@ while (iterator.hasNext()) { ServerPlayer entityplayer = (ServerPlayer) iterator.next(); -@@ -982,6 +1139,12 @@ +@@ -982,6 +1140,12 @@ double d1 = (double) pos.getY() - entityplayer.getY(); double d2 = (double) pos.getZ() - entityplayer.getZ(); @@ -513,7 +514,7 @@ if (d0 * d0 + d1 * d1 + d2 * d2 < 1024.0D) { entityplayer.connection.send(new ClientboundBlockDestructionPacket(entityId, pos, progress)); } -@@ -1060,7 +1223,18 @@ +@@ -1060,7 +1224,18 @@ Iterator iterator = this.navigatingMobs.iterator(); while (iterator.hasNext()) { @@ -533,7 +534,7 @@ PathNavigation navigationabstract = entityinsentient.getNavigation(); if (navigationabstract.shouldRecomputePath(pos)) { -@@ -1126,9 +1300,15 @@ +@@ -1126,9 +1301,15 @@ @Override public void explode(@Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, double x, double y, double z, float power, boolean createFire, Level.ExplosionInteraction explosionSourceType, ParticleOptions smallParticle, ParticleOptions largeParticle, Holder soundEvent) { @@ -550,7 +551,7 @@ case NONE: explosion_effect = Explosion.BlockInteraction.KEEP; break; -@@ -1144,16 +1324,26 @@ +@@ -1144,16 +1325,26 @@ case TRIGGER: explosion_effect = Explosion.BlockInteraction.TRIGGER_BLOCK; break; @@ -580,7 +581,7 @@ Iterator iterator = this.players.iterator(); while (iterator.hasNext()) { -@@ -1162,10 +1352,11 @@ +@@ -1162,10 +1353,11 @@ if (entityplayer.distanceToSqr(vec3d) < 4096.0D) { Optional optional = Optional.ofNullable((Vec3) serverexplosion.getHitPlayers().get(entityplayer)); @@ -593,7 +594,7 @@ } private Explosion.BlockInteraction getDestroyType(GameRules.Key decayRule) { -@@ -1226,17 +1417,24 @@ +@@ -1226,17 +1418,24 @@ } public int sendParticles(T parameters, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double speed) { @@ -621,7 +622,7 @@ ++j; } } -@@ -1292,7 +1490,7 @@ +@@ -1292,7 +1491,7 @@ @Nullable public BlockPos findNearestMapStructure(TagKey structureTag, BlockPos pos, int radius, boolean skipReferencedStructures) { @@ -630,7 +631,7 @@ return null; } else { Optional> optional = this.registryAccess().lookupOrThrow(Registries.STRUCTURE).get(structureTag); -@@ -1334,11 +1532,22 @@ +@@ -1334,11 +1533,22 @@ @Nullable @Override public MapItemSavedData getMapData(MapId id) { @@ -654,7 +655,7 @@ this.getServer().overworld().getDataStorage().set(id.key(), state); } -@@ -1649,6 +1858,11 @@ +@@ -1649,6 +1859,11 @@ @Override public void blockUpdated(BlockPos pos, Block block) { if (!this.isDebug()) { @@ -666,7 +667,7 @@ this.updateNeighborsAt(pos, block); } -@@ -1668,12 +1882,12 @@ +@@ -1668,12 +1883,12 @@ } public boolean isFlat() { @@ -681,7 +682,7 @@ } @Nullable -@@ -1696,7 +1910,7 @@ +@@ -1696,7 +1911,7 @@ private static String getTypeCount(Iterable items, Function classifier) { try { Object2IntOpenHashMap object2intopenhashmap = new Object2IntOpenHashMap(); @@ -690,7 +691,7 @@ while (iterator.hasNext()) { T t0 = iterator.next(); -@@ -1705,7 +1919,7 @@ +@@ -1705,7 +1920,7 @@ object2intopenhashmap.addTo(s, 1); } @@ -699,7 +700,23 @@ String s1 = (String) entry.getKey(); return s1 + ":" + entry.getIntValue(); -@@ -1864,6 +2078,8 @@ +@@ -1717,6 +1932,7 @@ + + @Override + public LevelEntityGetter getEntities() { ++ org.spigotmc.AsyncCatcher.catchOp("Chunk getEntities call"); // Spigot + return this.entityManager.getEntityGetter(); + } + +@@ -1836,6 +2052,7 @@ + } + + public void onTrackingStart(Entity entity) { ++ org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot + ServerLevel.this.getChunkSource().addEntity(entity); + if (entity instanceof ServerPlayer entityplayer) { + ServerLevel.this.players.add(entityplayer); +@@ -1864,9 +2081,12 @@ } entity.updateDynamicGameEventListener(DynamicGameEventListener::add); @@ -708,7 +725,11 @@ } public void onTrackingEnd(Entity entity) { -@@ -1895,6 +2111,14 @@ ++ org.spigotmc.AsyncCatcher.catchOp("entity unregister"); // Spigot + ServerLevel.this.getChunkSource().removeEntity(entity); + if (entity instanceof ServerPlayer entityplayer) { + ServerLevel.this.players.remove(entityplayer); +@@ -1895,6 +2115,14 @@ } entity.updateDynamicGameEventListener(DynamicGameEventListener::remove); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch index fdda023f17..2312b7078b 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch @@ -216,10 +216,13 @@ this.activeEffects.clear(); } -@@ -781,6 +841,17 @@ - } - } - +@@ -778,8 +838,19 @@ + if (mobeffect != null) { + this.activeEffects.put(mobeffect.getEffect(), mobeffect); + } ++ } ++ } ++ + // CraftBukkit start + if (nbt.contains("Bukkit.MaxHealth")) { + Tag nbtbase = nbt.get("Bukkit.MaxHealth"); @@ -227,13 +230,12 @@ + this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(((FloatTag) nbtbase).getAsDouble()); + } else if (nbtbase.getId() == 3) { + this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(((IntTag) nbtbase).getAsDouble()); -+ } -+ } + } + } + // CraftBukkit end -+ + if (nbt.contains("Health", 99)) { this.setHealth(nbt.getFloat("Health")); - } @@ -819,9 +890,32 @@ } @@ -348,7 +350,7 @@ } } -@@ -987,24 +1117,54 @@ +@@ -987,24 +1117,55 @@ return this.addEffect(effect, (Entity) null); } @@ -363,6 +365,7 @@ + } + + public boolean addEffect(MobEffectInstance mobeffect, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause) { ++ org.spigotmc.AsyncCatcher.catchOp("effect add"); // Spigot + if (this.isTickingEffects) { + this.effectsToProcess.add(new ProcessableEffect(mobeffect, cause)); + return true; @@ -412,7 +415,7 @@ return flag; } } -@@ -1031,14 +1191,40 @@ +@@ -1031,14 +1192,40 @@ return this.getType().is(EntityTypeTags.INVERTED_HEALING_AND_HARM); } @@ -455,7 +458,7 @@ if (mobeffect != null) { this.onEffectsRemoved(List.of(mobeffect)); return true; -@@ -1142,20 +1328,55 @@ +@@ -1142,20 +1329,55 @@ } @@ -512,7 +515,7 @@ this.entityData.set(LivingEntity.DATA_HEALTH_ID, Mth.clamp(health, 0.0F, this.getMaxHealth())); } -@@ -1167,7 +1388,7 @@ +@@ -1167,7 +1389,7 @@ public boolean hurtServer(ServerLevel world, DamageSource source, float amount) { if (this.isInvulnerableTo(world, source)) { return false; @@ -521,7 +524,7 @@ return false; } else if (source.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) { return false; -@@ -1182,10 +1403,11 @@ +@@ -1182,10 +1404,11 @@ } float f1 = amount; @@ -535,7 +538,7 @@ this.hurtCurrentlyUsedShield(amount); f2 = amount; amount = 0.0F; -@@ -1202,15 +1424,26 @@ +@@ -1202,15 +1425,26 @@ flag = true; } @@ -564,7 +567,7 @@ this.walkAnimation.setSpeed(1.5F); if (Float.isNaN(amount) || Float.isInfinite(amount)) { amount = Float.MAX_VALUE; -@@ -1218,18 +1451,27 @@ +@@ -1218,18 +1452,27 @@ boolean flag1 = true; @@ -596,7 +599,7 @@ this.hurtDuration = 10; this.hurtTime = this.hurtDuration; } -@@ -1243,7 +1485,7 @@ +@@ -1243,7 +1486,7 @@ world.broadcastDamageEvent(this, source); } @@ -605,7 +608,7 @@ this.markHurt(); } -@@ -1263,7 +1505,7 @@ +@@ -1263,7 +1506,7 @@ d1 = source.getSourcePosition().z() - this.getZ(); } @@ -614,7 +617,7 @@ if (!flag) { this.indicateDamage(d0, d1); } -@@ -1282,7 +1524,7 @@ +@@ -1282,7 +1525,7 @@ this.playHurtSound(source); } @@ -623,7 +626,7 @@ if (flag2) { this.lastDamageSource = source; -@@ -1329,10 +1571,10 @@ +@@ -1329,10 +1572,10 @@ } @Nullable @@ -636,7 +639,7 @@ this.lastHurtByPlayerTime = 100; this.lastHurtByPlayer = entityhuman; return entityhuman; -@@ -1342,8 +1584,8 @@ +@@ -1342,8 +1585,8 @@ this.lastHurtByPlayerTime = 100; LivingEntity entityliving = entitywolf.getOwner(); @@ -647,7 +650,7 @@ this.lastHurtByPlayer = entityhuman1; } else { -@@ -1363,7 +1605,7 @@ +@@ -1363,7 +1606,7 @@ } protected void blockedByShield(LivingEntity target) { @@ -656,7 +659,7 @@ } private boolean checkTotemDeathProtection(DamageSource source) { -@@ -1375,20 +1617,33 @@ +@@ -1375,20 +1618,33 @@ InteractionHand[] aenumhand = InteractionHand.values(); int i = aenumhand.length; @@ -694,7 +697,7 @@ ServerPlayer entityplayer = (ServerPlayer) this; entityplayer.awardStat(Stats.ITEM_USED.get(itemstack.getItem())); -@@ -1512,14 +1767,22 @@ +@@ -1512,14 +1768,22 @@ BlockState iblockdata = Blocks.WITHER_ROSE.defaultBlockState(); if (this.level().getBlockState(blockposition).isAir() && iblockdata.canSurvive(this.level(), blockposition)) { @@ -719,7 +722,7 @@ this.level().addFreshEntity(entityitem); } } -@@ -1530,24 +1793,39 @@ +@@ -1530,22 +1794,37 @@ protected void dropAllDeathLoot(ServerLevel world, DamageSource damageSource) { boolean flag = this.lastHurtByPlayerTime > 0; @@ -749,8 +752,8 @@ } + return 0; // CraftBukkit - } - ++ } ++ + protected void dropExperience(ServerLevel world, @Nullable Entity attacker) { + // CraftBukkit start - Update getExpReward() above if the removed if() changes! + if (!(this instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon)) { // CraftBukkit - SPIGOT-2420: Special case ender dragon will drop the xp over time @@ -758,12 +761,10 @@ + this.expToDrop = 0; + } + // CraftBukkit end -+ } -+ - protected void dropCustomDeathLoot(ServerLevel world, DamageSource source, boolean causedByPlayer) {} + } - public long getLootTableSeed() { -@@ -1612,19 +1890,31 @@ + protected void dropCustomDeathLoot(ServerLevel world, DamageSource source, boolean causedByPlayer) {} +@@ -1612,19 +1891,31 @@ } public void knockback(double strength, double x, double z) { @@ -802,7 +803,7 @@ } } -@@ -1683,6 +1973,20 @@ +@@ -1683,6 +1974,20 @@ return new LivingEntity.Fallsounds(SoundEvents.GENERIC_SMALL_FALL, SoundEvents.GENERIC_BIG_FALL); } @@ -823,7 +824,7 @@ public Optional getLastClimbablePos() { return this.lastClimbablePos; } -@@ -1757,9 +2061,14 @@ +@@ -1757,9 +2062,14 @@ int i = this.calculateFallDamage(fallDistance, damageMultiplier); if (i > 0) { @@ -839,7 +840,7 @@ return true; } else { return flag; -@@ -1830,7 +2139,7 @@ +@@ -1830,7 +2140,7 @@ protected float getDamageAfterArmorAbsorb(DamageSource source, float amount) { if (!source.is(DamageTypeTags.BYPASSES_ARMOR)) { @@ -848,7 +849,7 @@ amount = CombatRules.getDamageAfterAbsorb(this, amount, source, (float) this.getArmorValue(), (float) this.getAttributeValue(Attributes.ARMOR_TOUGHNESS)); } -@@ -1841,7 +2150,8 @@ +@@ -1841,7 +2151,8 @@ if (source.is(DamageTypeTags.BYPASSES_EFFECTS)) { return amount; } else { @@ -858,7 +859,7 @@ int i = (this.getEffect(MobEffects.DAMAGE_RESISTANCE).getAmplifier() + 1) * 5; int j = 25 - i; float f1 = amount * (float) j; -@@ -1884,18 +2194,144 @@ +@@ -1884,18 +2195,144 @@ } } @@ -1012,7 +1013,7 @@ if (entity instanceof ServerPlayer) { ServerPlayer entityplayer = (ServerPlayer) entity; -@@ -1904,13 +2340,48 @@ +@@ -1904,13 +2341,48 @@ } } @@ -1065,7 +1066,7 @@ } public CombatTracker getCombatTracker() { -@@ -1935,9 +2406,19 @@ +@@ -1935,9 +2407,19 @@ } public final void setArrowCount(int stuckArrowCount) { @@ -1086,7 +1087,7 @@ public final int getStingerCount() { return (Integer) this.entityData.get(LivingEntity.DATA_STINGER_COUNT_ID); } -@@ -1999,7 +2480,7 @@ +@@ -1999,7 +2481,7 @@ this.playSound(soundeffect, this.getSoundVolume(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F); } @@ -1095,7 +1096,7 @@ this.setHealth(0.0F); this.die(this.damageSources().generic()); } -@@ -2182,6 +2663,12 @@ +@@ -2182,6 +2664,12 @@ public abstract ItemStack getItemBySlot(EquipmentSlot slot); @@ -1108,7 +1109,7 @@ public abstract void setItemSlot(EquipmentSlot slot, ItemStack stack); public Iterable getHandSlots() { -@@ -2494,7 +2981,7 @@ +@@ -2494,7 +2982,7 @@ } @@ -1117,7 +1118,7 @@ Vec3 vec3d1 = this.getRiddenInput(controllingPlayer, movementInput); this.tickRidden(controllingPlayer, vec3d1); -@@ -2507,13 +2994,13 @@ +@@ -2507,13 +2995,13 @@ } @@ -1134,7 +1135,7 @@ return this.getSpeed(); } -@@ -2571,7 +3058,7 @@ +@@ -2571,7 +3059,7 @@ double d1 = Mth.clamp(motion.z, -0.15000000596046448D, 0.15000000596046448D); double d2 = Math.max(motion.y, -0.15000000596046448D); @@ -1143,7 +1144,7 @@ d2 = 0.0D; } -@@ -2586,7 +3073,7 @@ +@@ -2586,7 +3074,7 @@ } protected float getFlyingSpeed() { @@ -1152,7 +1153,7 @@ } public float getSpeed() { -@@ -2634,7 +3121,7 @@ +@@ -2634,7 +3122,7 @@ } } @@ -1161,7 +1162,7 @@ if (this.tickCount % 20 == 0) { this.getCombatTracker().recheckStatus(); } -@@ -2741,7 +3228,7 @@ +@@ -2741,7 +3229,7 @@ this.elytraAnimationState.tick(); } @@ -1170,7 +1171,7 @@ Map map = this.collectEquipmentChanges(); if (map != null) { -@@ -3000,7 +3487,7 @@ +@@ -3000,7 +3488,7 @@ { LivingEntity entityliving = this.getControllingPassenger(); @@ -1179,7 +1180,7 @@ if (this.isAlive()) { this.travelRidden(entityhuman, vec3d1); break label112; -@@ -3063,6 +3550,7 @@ +@@ -3063,6 +3551,7 @@ this.checkSlowFallDistance(); if (!this.level().isClientSide) { if (!this.canGlide()) { @@ -1187,7 +1188,7 @@ this.setSharedFlag(7, false); return; } -@@ -3113,7 +3601,7 @@ +@@ -3113,7 +3602,7 @@ Level world = this.level(); if (!(world instanceof ServerLevel worldserver)) { @@ -1196,7 +1197,7 @@ } else { List list = this.level().getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushableBy(this)); -@@ -3305,15 +3793,22 @@ +@@ -3305,15 +3794,22 @@ @Override public boolean isPickable() { @@ -1221,7 +1222,7 @@ public float getYHeadRot() { return this.yHeadRot; } -@@ -3483,8 +3978,31 @@ +@@ -3483,8 +3979,31 @@ this.releaseUsingItem(); } else { if (!this.useItem.isEmpty() && this.isUsingItem()) { @@ -1254,7 +1255,7 @@ if (itemstack != this.useItem) { this.setItemInHand(enumhand, itemstack); } -@@ -3568,12 +4086,18 @@ +@@ -3568,12 +4087,18 @@ } public boolean randomTeleport(double x, double y, double z, boolean particleEffects) { @@ -1275,7 +1276,7 @@ Level world = this.level(); if (world.hasChunkAt(blockposition)) { -@@ -3592,18 +4116,43 @@ +@@ -3592,18 +4117,43 @@ } if (flag2) { @@ -1323,7 +1324,7 @@ world.broadcastEntityEvent(this, (byte) 46); } -@@ -3613,7 +4162,7 @@ +@@ -3613,7 +4163,7 @@ entitycreature.getNavigation().stop(); } @@ -1332,7 +1333,7 @@ } } -@@ -3706,7 +4255,7 @@ +@@ -3706,7 +4256,7 @@ } public void stopSleeping() { @@ -1341,7 +1342,7 @@ Level world = this.level(); java.util.Objects.requireNonNull(world); -@@ -3718,9 +4267,9 @@ +@@ -3718,9 +4268,9 @@ this.level().setBlock(blockposition, (BlockState) iblockdata.setValue(BedBlock.OCCUPIED, false), 3); Vec3 vec3d = (Vec3) BedBlock.findStandUpPosition(this.getType(), this.level(), blockposition, enumdirection, this.getYRot()).orElseGet(() -> { @@ -1353,7 +1354,7 @@ }); Vec3 vec3d1 = Vec3.atBottomCenterOf(blockposition).subtract(vec3d).normalize(); float f = (float) Mth.wrapDegrees(Mth.atan2(vec3d1.z, vec3d1.x) * 57.2957763671875D - 90.0D); -@@ -3740,7 +4289,7 @@ +@@ -3740,7 +4290,7 @@ @Nullable public Direction getBedOrientation() { @@ -1362,7 +1363,7 @@ return blockposition != null ? BedBlock.getBedOrientation(this.level(), blockposition) : null; } -@@ -3905,7 +4454,7 @@ +@@ -3905,7 +4455,7 @@ public float maxUpStep() { float f = (float) this.getAttributeValue(Attributes.STEP_HEIGHT); diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/RecipeManager.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/RecipeManager.java.patch index 946cf370ee..805865ea9e 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/crafting/RecipeManager.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/RecipeManager.java.patch @@ -29,14 +29,13 @@ public class RecipeManager extends SimplePreparableReloadListener implements RecipeAccess { private static final Logger LOGGER = LogUtils.getLogger(); -@@ -109,9 +114,27 @@ - protected void apply(RecipeMap prepared, ResourceManager manager, ProfilerFiller profiler) { - this.recipes = prepared; +@@ -111,7 +116,26 @@ RecipeManager.LOGGER.info("Loaded {} recipes", prepared.values().size()); -+ } -+ + } + + // CraftBukkit start + public void addRecipe(RecipeHolder irecipe) { ++ org.spigotmc.AsyncCatcher.catchOp("Recipe Add"); // Spigot + this.recipes.addRecipe(irecipe); + this.finalizeRecipeLoading(); + } @@ -49,15 +48,15 @@ + + MinecraftServer.getServer().getPlayerList().reloadRecipes(); + } - } - ++ } ++ public void finalizeRecipeLoading(FeatureFlagSet features) { + this.featureflagset = features; + // CraftBukkit end List> list = new ArrayList(); List list1 = RecipeManager.RECIPE_PROPERTY_SETS.entrySet().stream().map((entry) -> { return new RecipeManager.IngredientCollector((ResourceKey) entry.getKey(), (RecipeManager.IngredientExtractor) entry.getValue()); -@@ -130,7 +153,7 @@ +@@ -130,7 +154,7 @@ StonecutterRecipe recipestonecutting = (StonecutterRecipe) irecipe; if (RecipeManager.isIngredientEnabled(features, recipestonecutting.input()) && recipestonecutting.resultDisplay().isEnabled(features)) { @@ -66,7 +65,7 @@ } } -@@ -172,7 +195,10 @@ +@@ -172,7 +196,10 @@ } public > Optional> getRecipeFor(RecipeType type, I input, Level world) { @@ -78,7 +77,7 @@ } public Optional> byKey(ResourceKey> key) { -@@ -183,7 +209,7 @@ +@@ -183,7 +210,7 @@ private > RecipeHolder byKeyTyped(RecipeType type, ResourceKey> key) { RecipeHolder recipeholder = this.recipes.byKey(key); @@ -87,7 +86,7 @@ } public Map, RecipePropertySet> getSynchronizedItemProperties() { -@@ -231,6 +257,22 @@ +@@ -231,6 +258,22 @@ return new RecipeHolder<>(key, irecipe); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/state/BlockBehaviour.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/state/BlockBehaviour.java.patch index ec2972a8ed..cbf17a547b 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/state/BlockBehaviour.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/state/BlockBehaviour.java.patch @@ -17,9 +17,14 @@ public abstract class BlockBehaviour implements FeatureElement { -@@ -158,6 +161,12 @@ +@@ -156,9 +159,18 @@ - protected void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) {} + protected void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, @Nullable Orientation wireOrientation, boolean notify) {} + +- protected void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) {} ++ protected void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) { ++ org.spigotmc.AsyncCatcher.catchOp("block onPlace"); // Spigot ++ } + // CraftBukkit start + protected void onPlace(BlockState iblockdata, Level world, BlockPos blockposition, BlockState iblockdata1, boolean flag, @Nullable UseOnContext context) { @@ -28,9 +33,11 @@ + // CraftBukkit end + protected void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean moved) { ++ org.spigotmc.AsyncCatcher.catchOp("block remove"); // Spigot if (state.hasBlockEntity() && !state.is(newState.getBlock())) { world.removeBlockEntity(pos); -@@ -174,8 +183,10 @@ + } +@@ -174,8 +186,10 @@ BlockEntity tileentity = state.hasBlockEntity() ? world.getBlockEntity(pos) : null; LootParams.Builder lootparams_a = (new LootParams.Builder(world)).withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(pos)).withParameter(LootContextParams.TOOL, ItemStack.EMPTY).withOptionalParameter(LootContextParams.BLOCK_ENTITY, tileentity).withOptionalParameter(LootContextParams.THIS_ENTITY, explosion.getDirectSourceEntity()); @@ -43,7 +50,7 @@ } state.spawnAfterBreak(world, pos, ItemStack.EMPTY, flag); -@@ -1125,9 +1136,15 @@ +@@ -1125,9 +1139,15 @@ } public void onPlace(Level world, BlockPos pos, BlockState state, boolean notify) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 41590d8d87..493c31f046 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -898,6 +898,7 @@ public final class CraftServer implements Server { public boolean dispatchCommand(CommandSender sender, String commandLine) { Preconditions.checkArgument(sender != null, "sender cannot be null"); Preconditions.checkArgument(commandLine != null, "commandLine cannot be null"); + org.spigotmc.AsyncCatcher.catchOp("command dispatch"); // Spigot if (this.commandMap.dispatch(sender, commandLine)) { return true; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 0870eefe60..085bb29a15 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -283,6 +283,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean unloadChunkRequest(int x, int z) { + org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot if (this.isChunkLoaded(x, z)) { this.world.getChunkSource().removeRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 1, Unit.INSTANCE); } @@ -291,6 +292,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { } private boolean unloadChunk0(int x, int z, boolean save) { + org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot if (!this.isChunkLoaded(x, z)) { return true; } @@ -307,6 +309,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean regenerateChunk(int x, int z) { + org.spigotmc.AsyncCatcher.catchOp("chunk regenerate"); // Spigot throw new UnsupportedOperationException("Not supported in this Minecraft version! Unless you can fix it, this is not a bug :)"); /* if (!unloadChunk0(x, z, false)) { @@ -384,6 +387,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean loadChunk(int x, int z, boolean generate) { + org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot ChunkAccess chunk = this.world.getChunkSource().getChunk(x, z, generate ? ChunkStatus.FULL : ChunkStatus.EMPTY, true); // If generate = false, but the chunk already exists, we will get this back. @@ -919,6 +923,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public Collection getNearbyEntities(BoundingBox boundingBox, Predicate filter) { + org.spigotmc.AsyncCatcher.catchOp("getNearbyEntities"); // Spigot Preconditions.checkArgument(boundingBox != null, "BoundingBox cannot be null"); AABB bb = new AABB(boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMinZ(), boundingBox.getMaxX(), boundingBox.getMaxY(), boundingBox.getMaxZ()); @@ -1073,6 +1078,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void save() { + org.spigotmc.AsyncCatcher.catchOp("world save"); // Spigot this.server.checkSaveState(); boolean oldSave = this.world.noSave; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java index e8fba1c702..daa49fdcb7 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -228,6 +228,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { @Override public List getNearbyEntities(double x, double y, double z) { Preconditions.checkState(!this.entity.generation, "Cannot get nearby entities during world generation"); + org.spigotmc.AsyncCatcher.catchOp("getNearbyEntities"); // Spigot List notchEntityList = this.entity.level().getEntities(this.entity, this.entity.getBoundingBox().inflate(x, y, z), Predicates.alwaysTrue()); List bukkitEntityList = new java.util.ArrayList(notchEntityList.size()); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index b77e2990e3..624e8b948f 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -492,6 +492,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @Override public void kickPlayer(String message) { + org.spigotmc.AsyncCatcher.catchOp("player kick"); // Spigot this.getHandle().transferCookieConnection.kickPlayer(CraftChatMessage.fromStringOrEmpty(message, true)); } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java b/paper-server/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java index ffd5ed8c42..40e348cae0 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java @@ -41,6 +41,7 @@ public final class CraftScoreboardManager implements ScoreboardManager { @Override public CraftScoreboard getNewScoreboard() { + org.spigotmc.AsyncCatcher.catchOp("scoreboard creation"); // Spigot CraftScoreboard scoreboard = new CraftScoreboard(new ServerScoreboard(this.server)); this.scoreboards.add(scoreboard); return scoreboard; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java index 2c65f3da1e..8390f5b5b9 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java @@ -12,6 +12,7 @@ public class ServerShutdownThread extends Thread { @Override public void run() { try { + org.spigotmc.AsyncCatcher.enabled = false; // Spigot this.server.close(); } finally { try { diff --git a/paper-server/src/main/java/org/spigotmc/AsyncCatcher.java b/paper-server/src/main/java/org/spigotmc/AsyncCatcher.java new file mode 100644 index 0000000000..bbf0d9d9c4 --- /dev/null +++ b/paper-server/src/main/java/org/spigotmc/AsyncCatcher.java @@ -0,0 +1,17 @@ +package org.spigotmc; + +import net.minecraft.server.MinecraftServer; + +public class AsyncCatcher +{ + + public static boolean enabled = true; + + public static void catchOp(String reason) + { + if ( AsyncCatcher.enabled && Thread.currentThread() != MinecraftServer.getServer().serverThread ) + { + throw new IllegalStateException( "Asynchronous " + reason + "!" ); + } + } +}