From dccf82ab1b5dbaad48bba1c01af85cc1462ed6e2 Mon Sep 17 00:00:00 2001 From: Jordan Date: Mon, 2 Oct 2023 20:36:21 +0100 Subject: [PATCH] fix: set villager offers temporarily to save NBT without sending event (#2357) --- .../adapter/ext/fawe/PaperweightAdapter.java | 5 ++- .../v1_17_R1_2/PaperweightFaweAdapter.java | 6 +--- .../fawe/v1_17_R1_2/PaperweightGetBlocks.java | 4 +-- .../v1_17_R1_2/PaperweightGetBlocks_Copy.java | 2 +- .../PaperweightPlatformAdapter.java | 31 ++++++++++++++++++ .../ext/fawe/v1_18_R2/PaperweightAdapter.java | 5 ++- .../fawe/v1_18_R2/PaperweightFaweAdapter.java | 6 +--- .../fawe/v1_18_R2/PaperweightGetBlocks.java | 4 +-- .../v1_18_R2/PaperweightGetBlocks_Copy.java | 2 +- .../v1_18_R2/PaperweightPlatformAdapter.java | 32 ++++++++++++++++++- .../ext/fawe/v1_19_R3/PaperweightAdapter.java | 5 ++- .../fawe/v1_19_R3/PaperweightFaweAdapter.java | 6 +--- .../fawe/v1_19_R3/PaperweightGetBlocks.java | 4 +-- .../v1_19_R3/PaperweightGetBlocks_Copy.java | 2 +- .../v1_19_R3/PaperweightPlatformAdapter.java | 31 ++++++++++++++++++ .../ext/fawe/v1_20_R1/PaperweightAdapter.java | 8 +++-- .../fawe/v1_20_R1/PaperweightFaweAdapter.java | 6 +--- .../fawe/v1_20_R1/PaperweightGetBlocks.java | 31 +++++++++++++++--- .../v1_20_R1/PaperweightGetBlocks_Copy.java | 2 +- .../v1_20_R1/PaperweightPlatformAdapter.java | 27 ++++++++++++++++ 20 files changed, 177 insertions(+), 42 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java index f369b8458..52974fb02 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java @@ -38,6 +38,7 @@ import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.PaperweightFaweAdapter; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.PaperweightPlatformAdapter; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.extent.Extent; @@ -288,7 +289,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter getParent() { return parent; @@ -367,7 +363,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); Supplier saveTag = () -> { final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); - readEntityIntoTag(mcEntity, minecraftTag); + PaperweightPlatformAdapter.readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java index aab9e5aa7..d7a1be074 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java @@ -374,7 +374,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc public Iterator iterator() { Iterable result = entities.stream().map(input -> { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - input.save(tag); + PaperweightPlatformAdapter.readEntityIntoTag(input, tag); return (CompoundTag) adapter.toNative(tag); }).collect(Collectors.toList()); return result.iterator(); @@ -394,7 +394,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @SuppressWarnings("rawtypes") public synchronized > T call(IChunkSet set, Runnable finalizer) { forceLoadSections = false; - copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; + copy = createCopy ? new PaperweightGetBlocks_Copy(getChunk()) : null; try { ServerLevel nmsWorld = serverLevel; LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks_Copy.java index de431c718..65b16ee3b 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks_Copy.java @@ -74,7 +74,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { protected void storeEntity(Entity entity) { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); + PaperweightPlatformAdapter.readEntityIntoTag(entity, compoundTag); entities.add((CompoundTag) adapter.toNative(compoundTag)); } diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java index 0854fc7ad..16dfd7bd8 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java @@ -34,6 +34,8 @@ import net.minecraft.server.level.TicketType; import net.minecraft.util.BitStorage; import net.minecraft.util.Unit; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.npc.AbstractVillager; +import net.minecraft.world.item.trading.MerchantOffers; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.biome.Biome; @@ -90,6 +92,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final Field fieldGameEventDispatcherSections; private static final MethodHandle methodremoveBlockEntityTicker; + private static final Field fieldOffers; + private static final MerchantOffers OFFERS = new MerchantOffers(); + private static final Field fieldRemove; private static final Logger LOGGER = LogManagerCompat.getLogger(); @@ -145,6 +150,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p")); fieldRemove.setAccessible(true); + + fieldOffers = AbstractVillager.class.getDeclaredField(Refraction.pickName("offers", "bU")); + fieldOffers.setAccessible(true); } catch (RuntimeException e) { throw e; } catch (Throwable rethrow) { @@ -492,4 +500,27 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return chunk.level.entityManager.getEntities(chunk.getPos()); } + public static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { + boolean isVillager = entity instanceof AbstractVillager && !Fawe.isMainThread(); + boolean unset = false; + if (isVillager) { + try { + if (fieldOffers.get(entity) != null) { + fieldOffers.set(entity, OFFERS); + unset = true; + } + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to set offers field to villager to avoid async catcher.", e); + } + } + entity.save(compoundTag); + if (unset) { + try { + fieldOffers.set(entity, null); + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to set offers field to null again on villager.", e); + } + } + } + } diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2/PaperweightAdapter.java index 47389b357..1edc3be1d 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2/PaperweightAdapter.java @@ -34,6 +34,7 @@ import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.PaperweightPlatformAdapter; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.extent.Extent; @@ -270,7 +271,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter getParent() { return parent; @@ -360,7 +356,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); Supplier saveTag = () -> { final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); - readEntityIntoTag(mcEntity, minecraftTag); + PaperweightPlatformAdapter.readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java index 91a5abede..fba567a5b 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java @@ -368,7 +368,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc public Iterator iterator() { Iterable result = entities.stream().map(input -> { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - input.save(tag); + PaperweightPlatformAdapter.readEntityIntoTag(input, tag); return (CompoundTag) adapter.toNative(tag); }).collect(Collectors.toList()); return result.iterator(); @@ -388,7 +388,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @SuppressWarnings("rawtypes") public synchronized > T call(IChunkSet set, Runnable finalizer) { forceLoadSections = false; - copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; + copy = createCopy ? new PaperweightGetBlocks_Copy(getChunk()) : null; try { ServerLevel nmsWorld = serverLevel; LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks_Copy.java index 991c3d1f9..5c68de6fe 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks_Copy.java @@ -76,7 +76,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { protected void storeEntity(Entity entity) { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); + PaperweightPlatformAdapter.readEntityIntoTag(entity, compoundTag); entities.add((CompoundTag) adapter.toNative(compoundTag)); } diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightPlatformAdapter.java index 1075694b4..06281908d 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightPlatformAdapter.java @@ -35,6 +35,8 @@ import net.minecraft.util.ThreadingDetector; import net.minecraft.util.Unit; import net.minecraft.util.ZeroBitStorage; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.npc.AbstractVillager; +import net.minecraft.world.item.trading.MerchantOffers; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.biome.Biome; @@ -98,6 +100,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final MethodHandle methodRemoveGameEventListener; private static final MethodHandle methodremoveTickingBlockEntity; + private static final Field fieldOffers; + private static final MerchantOffers OFFERS = new MerchantOffers(); + private static final Field fieldRemove; private static final Logger LOGGER = LogManagerCompat.getLogger(); @@ -158,6 +163,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p")); fieldRemove.setAccessible(true); + + fieldOffers = AbstractVillager.class.getDeclaredField(Refraction.pickName("offers", "bW")); + fieldOffers.setAccessible(true); } catch (RuntimeException e) { throw e; } catch (Throwable rethrow) { @@ -571,7 +579,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return BiomeTypes.get(biome.unwrapKey().orElseThrow().location().toString()); } - @SuppressWarnings("unchecked") static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { try { // Do the method ourselves to avoid trying to reflect generic method parameters @@ -595,6 +602,29 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return chunk.level.entityManager.getEntities(chunk.getPos()); } + public static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { + boolean isVillager = entity instanceof AbstractVillager && !Fawe.isMainThread(); + boolean unset = false; + if (isVillager) { + try { + if (fieldOffers.get(entity) != null) { + fieldOffers.set(entity, OFFERS); + unset = true; + } + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to set offers field to villager to avoid async catcher.", e); + } + } + entity.save(compoundTag); + if (unset) { + try { + fieldOffers.set(entity, null); + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to set offers field to null again on villager.", e); + } + } + } + record FakeIdMapBlock(int size) implements IdMap { @Override diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java index e106c7d56..22c5a07b2 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java @@ -35,6 +35,7 @@ import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.PaperweightPlatformAdapter; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.extent.Extent; @@ -276,7 +277,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter getParent() { return parent; @@ -321,7 +317,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); Supplier saveTag = () -> { final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); - readEntityIntoTag(mcEntity, minecraftTag); + PaperweightPlatformAdapter.readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java index c715e5fc2..0840b4aac 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java @@ -369,7 +369,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc public Iterator iterator() { Iterable result = entities.stream().map(input -> { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - input.save(tag); + PaperweightPlatformAdapter.readEntityIntoTag(input, tag); return (CompoundTag) adapter.toNative(tag); }).collect(Collectors.toList()); return result.iterator(); @@ -389,7 +389,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @SuppressWarnings("rawtypes") public synchronized > T call(IChunkSet set, Runnable finalizer) { forceLoadSections = false; - copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; + copy = createCopy ? new PaperweightGetBlocks_Copy(getChunk()) : null; try { ServerLevel nmsWorld = serverLevel; LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java index b6557ef0b..0c5d62692 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java @@ -80,7 +80,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { protected void storeEntity(Entity entity) { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); + PaperweightPlatformAdapter.readEntityIntoTag(entity, compoundTag); entities.add((CompoundTag) adapter.toNative(compoundTag)); } diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java index 16210db38..d0ce1c555 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java @@ -38,6 +38,8 @@ import net.minecraft.util.ThreadingDetector; import net.minecraft.util.Unit; import net.minecraft.util.ZeroBitStorage; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.npc.AbstractVillager; +import net.minecraft.world.item.trading.MerchantOffers; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.biome.Biome; @@ -105,6 +107,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final MethodHandle methodRemoveGameEventListener; private static final MethodHandle methodremoveTickingBlockEntity; + private static final Field fieldOffers; + private static final MerchantOffers OFFERS = new MerchantOffers(); + private static final Field fieldRemove; private static final Logger LOGGER = LogManagerCompat.getLogger(); @@ -196,6 +201,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } catch (NoSuchFieldException ignored) { } POST_CHUNK_REWRITE = chunkRewrite; + + fieldOffers = AbstractVillager.class.getDeclaredField(Refraction.pickName("offers", "bT")); + fieldOffers.setAccessible(true); } catch (RuntimeException | Error e) { throw e; } catch (Exception e) { @@ -656,6 +664,29 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return List.of(); } + public static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { + boolean isVillager = entity instanceof AbstractVillager && !Fawe.isMainThread(); + boolean unset = false; + if (isVillager) { + try { + if (fieldOffers.get(entity) != null) { + fieldOffers.set(entity, OFFERS); + unset = true; + } + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to set offers field to villager to avoid async catcher.", e); + } + } + entity.save(compoundTag); + if (unset) { + try { + fieldOffers.set(entity, null); + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to set offers field to null again on villager.", e); + } + } + } + record FakeIdMapBlock(int size) implements IdMap { @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java index 428176c5f..b40c12b1a 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java @@ -27,7 +27,6 @@ import com.google.common.collect.Sets; import com.google.common.util.concurrent.Futures; import com.mojang.datafixers.util.Either; import com.mojang.serialization.Lifecycle; -import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.NBTConstants; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; @@ -35,6 +34,7 @@ import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.PaperweightPlatformAdapter; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.extent.Extent; @@ -138,6 +138,7 @@ import org.bukkit.generator.ChunkGenerator; import org.spigotmc.SpigotConfig; import org.spigotmc.WatchdogThread; +import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -159,7 +160,6 @@ import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; -import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; @@ -277,7 +277,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter getParent() { return parent; @@ -321,7 +317,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); Supplier saveTag = () -> { final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); - readEntityIntoTag(mcEntity, minecraftTag); + PaperweightPlatformAdapter.readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java index 08d2f1069..e0e746109 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java @@ -29,7 +29,11 @@ import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BlockTypesCache; import io.papermc.lib.PaperLib; import io.papermc.paper.event.block.BeaconDeactivatedEvent; -import net.minecraft.core.*; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.IdMap; +import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.nbt.IntTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvents; @@ -42,7 +46,14 @@ import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.entity.BeaconBlockEntity; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.*; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.HashMapPalette; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.LinearPalette; +import net.minecraft.world.level.chunk.Palette; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.lighting.LevelLightEngine; import org.apache.logging.log4j.Logger; @@ -52,7 +63,17 @@ import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlock; import org.bukkit.event.entity.CreatureSpawnEvent; import javax.annotation.Nonnull; -import java.util.*; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.Semaphore; @@ -347,7 +368,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc public Iterator iterator() { Iterable result = entities.stream().map(input -> { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - input.save(tag); + PaperweightPlatformAdapter.readEntityIntoTag(input, tag); return (CompoundTag) adapter.toNative(tag); }).collect(Collectors.toList()); return result.iterator(); @@ -367,7 +388,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @SuppressWarnings("rawtypes") public synchronized > T call(IChunkSet set, Runnable finalizer) { forceLoadSections = false; - copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; + copy = createCopy ? new PaperweightGetBlocks_Copy(getChunk()) : null; try { ServerLevel nmsWorld = serverLevel; LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java index 7a387a887..a23000249 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java @@ -80,7 +80,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { protected void storeEntity(Entity entity) { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); + PaperweightPlatformAdapter.readEntityIntoTag(entity, compoundTag); entities.add((CompoundTag) adapter.toNative(compoundTag)); } diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java index 2fe34894d..8083e3fde 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java @@ -38,6 +38,9 @@ import net.minecraft.util.ThreadingDetector; import net.minecraft.util.Unit; import net.minecraft.util.ZeroBitStorage; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.npc.AbstractVillager; +import net.minecraft.world.entity.npc.Villager; +import net.minecraft.world.item.trading.MerchantOffers; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.biome.Biome; @@ -108,6 +111,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final MethodHandle methodRemoveGameEventListener; private static final MethodHandle methodremoveTickingBlockEntity; + private static final Field fieldOffers; + private static final MerchantOffers OFFERS = new MerchantOffers(); + /* * This is a workaround for the changes from https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/1fddefce1cdce44010927b888432bf70c0e88cde#src/main/java/org/bukkit/craftbukkit/CraftChunk.java * and is only needed to support 1.19.4 versions before *and* after this change. @@ -205,6 +211,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } catch (NoSuchFieldException ignored) { } POST_CHUNK_REWRITE = chunkRewrite; + + fieldOffers = AbstractVillager.class.getDeclaredField(Refraction.pickName("offers", "bU")); + fieldOffers.setAccessible(true); } catch (RuntimeException | Error e) { throw e; } catch (Exception e) { @@ -674,6 +683,24 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return List.of(); } + public static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { + boolean unset = false; + if (entity instanceof Villager villager && !Fawe.isMainThread()) { + try { + if (fieldOffers.get(entity) == null) { + villager.setOffers(OFFERS); + unset = true; + } + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to set offers field to villager to avoid async catcher.", e); + } + } + entity.save(compoundTag); + if (unset) { + ((Villager) entity).setOffers(null); + } + } + record FakeIdMapBlock(int size) implements IdMap { @Override