Async Operation Catching

Catch and throw an exception when a potentially unsafe operation occurs on a thread other than the main server thread.

By: md_5 <git@md-5.net>
This commit is contained in:
CraftBukkit/Spigot 2014-03-25 16:10:01 +11:00
parent 973f52a650
commit 5240271410
12 changed files with 185 additions and 97 deletions

View File

@ -100,7 +100,23 @@
}
void forEachSpawnCandidateChunk(Consumer<ChunkHolder> 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<ServerPlayerConnection> 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);

View File

@ -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> 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<Vec3> optional = Optional.ofNullable((Vec3) serverexplosion.getHitPlayers().get(entityplayer));
@ -593,7 +594,7 @@
}
private Explosion.BlockInteraction getDestroyType(GameRules.Key<GameRules.BooleanValue> decayRule) {
@@ -1226,17 +1417,24 @@
@@ -1226,17 +1418,24 @@
}
public <T extends ParticleOptions> int sendParticles(T parameters, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double speed) {
@ -621,7 +622,7 @@
++j;
}
}
@@ -1292,7 +1490,7 @@
@@ -1292,7 +1491,7 @@
@Nullable
public BlockPos findNearestMapStructure(TagKey<Structure> structureTag, BlockPos pos, int radius, boolean skipReferencedStructures) {
@ -630,7 +631,7 @@
return null;
} else {
Optional<HolderSet.Named<Structure>> 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 <T> String getTypeCount(Iterable<T> items, Function<T, String> classifier) {
try {
Object2IntOpenHashMap<String> 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<Entity> 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);

View File

@ -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<BlockPos> 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<ItemStack> 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<EquipmentSlot, ItemStack> 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);

View File

@ -29,14 +29,13 @@
public class RecipeManager extends SimplePreparableReloadListener<RecipeMap> 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<SelectableRecipe.SingleInputEntry<StonecutterRecipe>> list = new ArrayList();
List<RecipeManager.IngredientCollector> 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 <I extends RecipeInput, T extends Recipe<I>> Optional<RecipeHolder<T>> getRecipeFor(RecipeType<T> type, I input, Level world) {
@ -78,7 +77,7 @@
}
public Optional<RecipeHolder<?>> byKey(ResourceKey<Recipe<?>> key) {
@@ -183,7 +209,7 @@
@@ -183,7 +210,7 @@
private <T extends Recipe<?>> RecipeHolder<T> byKeyTyped(RecipeType<T> type, ResourceKey<Recipe<?>> key) {
RecipeHolder<?> recipeholder = this.recipes.byKey(key);
@ -87,7 +86,7 @@
}
public Map<ResourceKey<RecipePropertySet>, RecipePropertySet> getSynchronizedItemProperties() {
@@ -231,6 +257,22 @@
@@ -231,6 +258,22 @@
return new RecipeHolder<>(key, irecipe);
}

View File

@ -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) {

View File

@ -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;

View File

@ -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<Entity> getNearbyEntities(BoundingBox boundingBox, Predicate<? super Entity> 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;

View File

@ -228,6 +228,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
@Override
public List<org.bukkit.entity.Entity> 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<Entity> notchEntityList = this.entity.level().getEntities(this.entity, this.entity.getBoundingBox().inflate(x, y, z), Predicates.alwaysTrue());
List<org.bukkit.entity.Entity> bukkitEntityList = new java.util.ArrayList<org.bukkit.entity.Entity>(notchEntityList.size());

View File

@ -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));
}

View File

@ -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;

View File

@ -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 {

View File

@ -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 + "!" );
}
}
}