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 b78b1987c..5554fe25b 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 @@ -14,7 +14,6 @@ import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.collection.AdaptedMap; import com.google.common.base.Suppliers; -import com.google.common.collect.Iterables; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.StringTag; @@ -64,9 +63,9 @@ import javax.annotation.Nonnull; import java.util.AbstractSet; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -79,7 +78,6 @@ import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Function; import java.util.stream.Collectors; -import java.util.stream.StreamSupport; public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks { @@ -324,21 +322,15 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - @SuppressWarnings("unchecked") public CompoundTag getEntity(UUID uuid) { Entity entity = serverLevel.getEntity(uuid); if (entity != null) { org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); } - for (List entry : /*getChunk().getEntitySlices()*/ new List[0]) { - if (entry != null) { - for (Entity ent : entry) { - if (uuid.equals(ent.getUUID())) { - org.bukkit.entity.Entity bukkitEnt = ent.getBukkitEntity(); - return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); - } - } + for (CompoundTag tag : getEntities()) { + if (uuid.equals(tag.getUUID())) { + return tag; } } return null; @@ -346,21 +338,15 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override public Set getEntities() { - List[] slices = /*getChunk().getEntitySlices()*/ new List[0]; - int size = 0; - for (List slice : slices) { - if (slice != null) { - size += slice.size(); - } - } - if (slices.length == 0) { + List entities = PaperweightPlatformAdapter.getEntities(getChunk()); + if (entities.isEmpty()) { return Collections.emptySet(); } - int finalSize = size; - return new AbstractSet() { + int size = entities.size(); + return new AbstractSet<>() { @Override public int size() { - return finalSize; + return size; } @Override @@ -373,17 +359,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (!(get instanceof CompoundTag getTag)) { return false; } - Map value = getTag.getValue(); - CompoundTag getParts = (CompoundTag) value.get("UUID"); - UUID getUUID = new UUID(getParts.getLong("Most"), getParts.getLong("Least")); - for (List slice : slices) { - if (slice != null) { - for (Entity entity : slice) { - UUID uuid = entity.getUUID(); - if (uuid.equals(getUUID)) { - return true; - } - } + UUID getUUID = getTag.getUUID(); + for (Entity entity : entities) { + UUID uuid = entity.getUUID(); + if (uuid.equals(getUUID)) { + return true; } } return false; @@ -392,9 +372,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Nonnull @Override public Iterator iterator() { - Iterable result = StreamSupport.stream(Iterables.concat(slices).spliterator(), false).map(input -> { + Iterable result = entities.stream().map(input -> { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - return (CompoundTag) adapter.toNative(input.saveWithoutId(tag)); + input.save(tag); + return (CompoundTag) adapter.toNative(tag); }).collect(Collectors.toList()); return result.iterator(); } @@ -630,23 +611,31 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } syncTasks[2] = () -> { - final List[] entities = /*nmsChunk.e()*/ new List[0]; + Set entitiesRemoved = new HashSet<>(); + final List entities = PaperweightPlatformAdapter.getEntities(nmsChunk); - for (final Collection ents : entities) { - if (!ents.isEmpty()) { - final Iterator iter = ents.iterator(); - while (iter.hasNext()) { - final Entity entity = iter.next(); - if (entityRemoves.contains(entity.getUUID())) { - if (createCopy) { - copy.storeEntity(entity); - } - iter.remove(); - removeEntity(entity); - } + for (Entity entity : entities) { + UUID uuid = entity.getUUID(); + if (entityRemoves.contains(uuid)) { + if (createCopy) { + copy.storeEntity(entity); + } + removeEntity(entity); + entitiesRemoved.add(uuid); + entityRemoves.remove(uuid); + } + } + if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { + for (UUID uuid : entityRemoves) { + Entity entity = nmsWorld.entityManager.getEntityGetter().get(uuid); + if (entity != null) { + removeEntity(entity); } } } + // Only save entities that were actually removed to history + set.getEntityRemoves().clear(); + set.getEntityRemoves().addAll(entitiesRemoved); }; } @@ -657,7 +646,9 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } syncTasks[1] = () -> { - for (final CompoundTag nativeTag : entities) { + Iterator iterator = entities.iterator(); + while (iterator.hasNext()) { + final CompoundTag nativeTag = iterator.next(); final Map entityTagMap = nativeTag.getValue(); final StringTag idTag = (StringTag) entityTagMap.get("Id"); final ListTag posTag = (ListTag) entityTagMap.get("Pos"); @@ -684,12 +675,23 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } entity.load(tag); entity.absMoveTo(x, y, z, yaw, pitch); - nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM); + entity.setUUID(nativeTag.getUUID()); + if (!nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { + LOGGER.warn( + "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", + id, + nmsWorld.getWorld().getName(), + x, + y, + z + ); + // Unsuccessful create should not be saved to history + iterator.remove(); + } } } } }; - } // set tiles 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 5d9c56092..de431c718 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,8 @@ 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(); - entities.add((CompoundTag) adapter.toNative(entity.save(compoundTag))); + entity.save(compoundTag); + entities.add((CompoundTag) adapter.toNative(compoundTag)); } @Override @@ -85,18 +86,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { @Override public CompoundTag getEntity(UUID uuid) { for (CompoundTag tag : entities) { - UUID tagUUID; - if (tag.containsKey("UUID")) { - int[] arr = tag.getIntArray("UUID"); - tagUUID = new UUID((long) arr[0] << 32 | (arr[1] & 0xFFFFFFFFL), (long) arr[2] << 32 | (arr[3] & 0xFFFFFFFFL)); - } else if (tag.containsKey("UUIDMost")) { - tagUUID = new UUID(tag.getLong("UUIDMost"), tag.getLong("UUIDLeast")); - } else if (tag.containsKey("PersistentIDMSB")) { - tagUUID = new UUID(tag.getLong("PersistentIDMSB"), tag.getLong("PersistentIDLSB")); - } else { - return null; - } - if (uuid.equals(tagUUID)) { + if (uuid.equals(tag.getUUID())) { return 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/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 8d76d9f7f..4b446d620 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 @@ -30,6 +30,7 @@ import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.BitStorage; +import net.minecraft.world.entity.Entity; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.biome.Biome; @@ -53,6 +54,7 @@ import java.lang.invoke.MethodHandles; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; +import java.util.List; import java.util.Locale; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -470,4 +472,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } } + static List getEntities(LevelChunk chunk) { + return chunk.level.entityManager.getEntities(new ChunkPos(chunk.locX, chunk.locZ)); + } + } 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 9f44912cb..f225bd441 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 @@ -69,6 +69,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -315,21 +316,15 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - @SuppressWarnings("unchecked") public CompoundTag getEntity(UUID uuid) { Entity entity = serverLevel.getEntity(uuid); if (entity != null) { org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); } - for (List entry : /*getChunk().getEntitySlices()*/ new List[0]) { - if (entry != null) { - for (Entity ent : entry) { - if (uuid.equals(ent.getUUID())) { - org.bukkit.entity.Entity bukkitEnt = ent.getBukkitEntity(); - return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); - } - } + for (CompoundTag tag : getEntities()) { + if (uuid.equals(tag.getUUID())) { + return tag; } } return null; @@ -337,21 +332,15 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override public Set getEntities() { - List[] slices = /*getChunk().getEntitySlices()*/ new List[0]; - int size = 0; - for (List slice : slices) { - if (slice != null) { - size += slice.size(); - } - } - if (slices.length == 0) { + List entities = PaperweightPlatformAdapter.getEntities(getChunk()); + if (entities.isEmpty()) { return Collections.emptySet(); } - int finalSize = size; - return new AbstractSet() { + int size = entities.size(); + return new AbstractSet<>() { @Override public int size() { - return finalSize; + return size; } @Override @@ -364,17 +353,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (!(get instanceof CompoundTag getTag)) { return false; } - Map value = getTag.getValue(); - CompoundTag getParts = (CompoundTag) value.get("UUID"); - UUID getUUID = new UUID(getParts.getLong("Most"), getParts.getLong("Least")); - for (List slice : slices) { - if (slice != null) { - for (Entity entity : slice) { - UUID uuid = entity.getUUID(); - if (uuid.equals(getUUID)) { - return true; - } - } + UUID getUUID = getTag.getUUID(); + for (Entity entity : entities) { + UUID uuid = entity.getUUID(); + if (uuid.equals(getUUID)) { + return true; } } return false; @@ -383,9 +366,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Nonnull @Override public Iterator iterator() { - Iterable result = StreamSupport.stream(Iterables.concat(slices).spliterator(), false).map(input -> { + Iterable result = entities.stream().map(input -> { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - return (CompoundTag) adapter.toNative(input.saveWithoutId(tag)); + input.save(tag); + return (CompoundTag) adapter.toNative(tag); }).collect(Collectors.toList()); return result.iterator(); } @@ -677,23 +661,31 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } syncTasks[2] = () -> { - final List[] entities = /*nmsChunk.e()*/ new List[0]; + Set entitiesRemoved = new HashSet<>(); + final List entities = PaperweightPlatformAdapter.getEntities(nmsChunk); - for (final Collection ents : entities) { - if (!ents.isEmpty()) { - final Iterator iter = ents.iterator(); - while (iter.hasNext()) { - final Entity entity = iter.next(); - if (entityRemoves.contains(entity.getUUID())) { - if (createCopy) { - copy.storeEntity(entity); - } - iter.remove(); - removeEntity(entity); - } + for (Entity entity : entities) { + UUID uuid = entity.getUUID(); + if (entityRemoves.contains(uuid)) { + if (createCopy) { + copy.storeEntity(entity); + } + removeEntity(entity); + entitiesRemoved.add(uuid); + entityRemoves.remove(uuid); + } + } + if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { + for (UUID uuid : entityRemoves) { + Entity entity = nmsWorld.entityManager.getEntityGetter().get(uuid); + if (entity != null) { + removeEntity(entity); } } } + // Only save entities that were actually removed to history + set.getEntityRemoves().clear(); + set.getEntityRemoves().addAll(entitiesRemoved); }; } @@ -704,7 +696,9 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } syncTasks[1] = () -> { - for (final CompoundTag nativeTag : entities) { + Iterator iterator = entities.iterator(); + while (iterator.hasNext()) { + final CompoundTag nativeTag = iterator.next(); final Map entityTagMap = nativeTag.getValue(); final StringTag idTag = (StringTag) entityTagMap.get("Id"); final ListTag posTag = (ListTag) entityTagMap.get("Pos"); @@ -731,12 +725,23 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } entity.load(tag); entity.absMoveTo(x, y, z, yaw, pitch); - nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM); + entity.setUUID(nativeTag.getUUID()); + if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { + LOGGER.warn( + "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", + id, + nmsWorld.getWorld().getName(), + x, + y, + z + ); + // Unsuccessful create should not be saved to history + iterator.remove(); + } } } } }; - } // set tiles 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 1404fd1c7..991c3d1f9 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,8 @@ 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(); - entities.add((CompoundTag) adapter.toNative(entity.save(compoundTag))); + entity.save(compoundTag); + entities.add((CompoundTag) adapter.toNative(compoundTag)); } @Override @@ -87,18 +88,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { @Override public CompoundTag getEntity(UUID uuid) { for (CompoundTag tag : entities) { - UUID tagUUID; - if (tag.containsKey("UUID")) { - int[] arr = tag.getIntArray("UUID"); - tagUUID = new UUID((long) arr[0] << 32 | (arr[1] & 0xFFFFFFFFL), (long) arr[2] << 32 | (arr[3] & 0xFFFFFFFFL)); - } else if (tag.containsKey("UUIDMost")) { - tagUUID = new UUID(tag.getLong("UUIDMost"), tag.getLong("UUIDLeast")); - } else if (tag.containsKey("PersistentIDMSB")) { - tagUUID = new UUID(tag.getLong("PersistentIDMSB"), tag.getLong("PersistentIDLSB")); - } else { - return null; - } - if (uuid.equals(tagUUID)) { + if (uuid.equals(tag.getUUID())) { return tag; } } 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 8316ae008..ad3205feb 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 @@ -33,6 +33,7 @@ import net.minecraft.util.BitStorage; import net.minecraft.util.SimpleBitStorage; import net.minecraft.util.ThreadingDetector; import net.minecraft.util.ZeroBitStorage; +import net.minecraft.world.entity.Entity; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.biome.Biome; @@ -599,6 +600,10 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } } + static List getEntities(LevelChunk chunk) { + return chunk.level.entityManager.getEntities(new ChunkPos(chunk.locX, chunk.locZ)); + } + record FakeIdMapBlock(int size) implements IdMap { @Override diff --git a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightGetBlocks.java index b63875d82..3c543d2c7 100644 --- a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightGetBlocks.java @@ -67,9 +67,9 @@ import javax.annotation.Nonnull; import java.util.AbstractSet; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -316,21 +316,15 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - @SuppressWarnings("unchecked") public CompoundTag getEntity(UUID uuid) { Entity entity = serverLevel.getEntity(uuid); if (entity != null) { org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); } - for (List entry : /*getChunk().getEntitySlices()*/ new List[0]) { - if (entry != null) { - for (Entity ent : entry) { - if (uuid.equals(ent.getUUID())) { - org.bukkit.entity.Entity bukkitEnt = ent.getBukkitEntity(); - return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); - } - } + for (CompoundTag tag : getEntities()) { + if (uuid.equals(tag.getUUID())) { + return tag; } } return null; @@ -338,21 +332,15 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override public Set getEntities() { - List[] slices = /*getChunk().getEntitySlices()*/ new List[0]; - int size = 0; - for (List slice : slices) { - if (slice != null) { - size += slice.size(); - } - } - if (slices.length == 0) { + List entities = PaperweightPlatformAdapter.getEntities(getChunk()); + if (entities.isEmpty()) { return Collections.emptySet(); } - int finalSize = size; - return new AbstractSet() { + int size = entities.size(); + return new AbstractSet<>() { @Override public int size() { - return finalSize; + return size; } @Override @@ -365,17 +353,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (!(get instanceof CompoundTag getTag)) { return false; } - Map value = getTag.getValue(); - CompoundTag getParts = (CompoundTag) value.get("UUID"); - UUID getUUID = new UUID(getParts.getLong("Most"), getParts.getLong("Least")); - for (List slice : slices) { - if (slice != null) { - for (Entity entity : slice) { - UUID uuid = entity.getUUID(); - if (uuid.equals(getUUID)) { - return true; - } - } + UUID getUUID = getTag.getUUID(); + for (Entity entity : entities) { + UUID uuid = entity.getUUID(); + if (uuid.equals(getUUID)) { + return true; } } return false; @@ -384,9 +366,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Nonnull @Override public Iterator iterator() { - Iterable result = StreamSupport.stream(Iterables.concat(slices).spliterator(), false).map(input -> { + Iterable result = entities.stream().map(input -> { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - return (CompoundTag) adapter.toNative(input.saveWithoutId(tag)); + input.save(tag); + return (CompoundTag) adapter.toNative(tag); }).collect(Collectors.toList()); return result.iterator(); } @@ -677,23 +660,31 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } syncTasks[2] = () -> { - final List[] entities = /*nmsChunk.e()*/ new List[0]; + Set entitiesRemoved = new HashSet<>(); + final List entities = PaperweightPlatformAdapter.getEntities(nmsChunk); - for (final Collection ents : entities) { - if (!ents.isEmpty()) { - final Iterator iter = ents.iterator(); - while (iter.hasNext()) { - final Entity entity = iter.next(); - if (entityRemoves.contains(entity.getUUID())) { - if (createCopy) { - copy.storeEntity(entity); - } - iter.remove(); - removeEntity(entity); - } + for (Entity entity : entities) { + UUID uuid = entity.getUUID(); + if (entityRemoves.contains(uuid)) { + if (createCopy) { + copy.storeEntity(entity); + } + removeEntity(entity); + entitiesRemoved.add(uuid); + entityRemoves.remove(uuid); + } + } + if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { + for (UUID uuid : entityRemoves) { + Entity entity = nmsWorld.entityManager.getEntityGetter().get(uuid); + if (entity != null) { + removeEntity(entity); } } } + // Only save entities that were actually removed to history + set.getEntityRemoves().clear(); + set.getEntityRemoves().addAll(entitiesRemoved); }; } @@ -704,7 +695,9 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } syncTasks[1] = () -> { - for (final CompoundTag nativeTag : entities) { + Iterator iterator = entities.iterator(); + while (iterator.hasNext()) { + final CompoundTag nativeTag = iterator.next(); final Map entityTagMap = nativeTag.getValue(); final StringTag idTag = (StringTag) entityTagMap.get("Id"); final ListTag posTag = (ListTag) entityTagMap.get("Pos"); @@ -731,12 +724,23 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } entity.load(tag); entity.absMoveTo(x, y, z, yaw, pitch); - nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM); + entity.setUUID(nativeTag.getUUID()); + if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { + LOGGER.warn( + "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", + id, + nmsWorld.getWorld().getName(), + x, + y, + z + ); + // Unsuccessful create should not be saved to history + iterator.remove(); + } } } } }; - } // set tiles diff --git a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightGetBlocks_Copy.java index 33ff20dc1..c0b69ac80 100644 --- a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightGetBlocks_Copy.java @@ -80,7 +80,8 @@ 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(); - entities.add((CompoundTag) adapter.toNative(entity.save(compoundTag))); + entity.save(compoundTag); + entities.add((CompoundTag) adapter.toNative(compoundTag)); } @Override @@ -91,18 +92,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { @Override public CompoundTag getEntity(UUID uuid) { for (CompoundTag tag : entities) { - UUID tagUUID; - if (tag.containsKey("UUID")) { - int[] arr = tag.getIntArray("UUID"); - tagUUID = new UUID((long) arr[0] << 32 | (arr[1] & 0xFFFFFFFFL), (long) arr[2] << 32 | (arr[3] & 0xFFFFFFFFL)); - } else if (tag.containsKey("UUIDMost")) { - tagUUID = new UUID(tag.getLong("UUIDMost"), tag.getLong("UUIDLeast")); - } else if (tag.containsKey("PersistentIDMSB")) { - tagUUID = new UUID(tag.getLong("PersistentIDMSB"), tag.getLong("PersistentIDLSB")); - } else { - return null; - } - if (uuid.equals(tagUUID)) { + if (uuid.equals(tag.getUUID())) { return tag; } } diff --git a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightPlatformAdapter.java index 75464bb61..9a7e73503 100644 --- a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightPlatformAdapter.java @@ -33,6 +33,7 @@ import net.minecraft.util.BitStorage; import net.minecraft.util.SimpleBitStorage; import net.minecraft.util.ThreadingDetector; import net.minecraft.util.ZeroBitStorage; +import net.minecraft.world.entity.Entity; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.biome.Biome; @@ -599,6 +600,10 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } } + static List getEntities(LevelChunk chunk) { + return chunk.level.entityManager.getEntities(new ChunkPos(chunk.locX, chunk.locZ)); + } + record FakeIdMapBlock(int size) implements IdMap { @Override diff --git a/worldedit-bukkit/adapters/adapter-legacy/src/main/resources/fastasyncworldedit-adapters.jar b/worldedit-bukkit/adapters/adapter-legacy/src/main/resources/fastasyncworldedit-adapters.jar index 83d4bb7b7..9000989ef 100644 Binary files a/worldedit-bukkit/adapters/adapter-legacy/src/main/resources/fastasyncworldedit-adapters.jar and b/worldedit-bukkit/adapters/adapter-legacy/src/main/resources/fastasyncworldedit-adapters.jar differ diff --git a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/schematic/ClipboardWorld.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/schematic/ClipboardWorld.java index b164ecfa3..a8190234c 100644 --- a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/schematic/ClipboardWorld.java +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/schematic/ClipboardWorld.java @@ -56,6 +56,7 @@ import java.io.IOException; import java.util.List; import java.util.Locale; import java.util.Set; +import java.util.UUID; public class ClipboardWorld extends AbstractWorld implements Clipboard, CLIWorld { @@ -167,6 +168,15 @@ public class ClipboardWorld extends AbstractWorld implements Clipboard, CLIWorld return clipboard.createEntity(location, entity); } + //FAWE start + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { + dirty = true; + return clipboard.createEntity(location, entity, uuid); + } + //FAWE end + @Override public BlockState getBlock(BlockVector3 position) { return clipboard.getBlock(position); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index 7952a0883..976b8b62a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -621,6 +621,15 @@ public class Settings extends Config { }) public boolean KEEP_ENTITIES_IN_BLOCKS = false; + @Comment({ + "[SAFE] Attempt to remove entities from the world if they were not present in the expected chunk (default: true)", + " - Sometimes an entity may have moved into a different chunk to that which FAWE expected", + " - This option allows FAWE to attempt to remove the entity, even if present in a different chunk", + " - If the entity is in an unloaded or partially loaded chunk, this will fail", + " - If an entity cannot be removed, it is possible duplicate entities may be created when using undo and/or redo" + }) + public boolean REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL = true; + @Comment({ "Other experimental features" }) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java index ac869b630..ce49569ad 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java @@ -22,6 +22,7 @@ import com.sk89q.worldedit.world.block.BlockTypes; import javax.annotation.Nullable; import java.util.Collection; +import java.util.UUID; public abstract class FaweRegionExtent extends ResettableExtent implements IBatchProcessor { @@ -149,6 +150,18 @@ public abstract class FaweRegionExtent extends ResettableExtent implements IBatc return super.createEntity(location, entity); } + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { + if (!contains(location.getBlockX(), location.getBlockY(), location.getBlockZ())) { + if (!limit.MAX_FAILS()) { + WEManager.weManager().cancelEditSafe(this, FaweCache.OUTSIDE_REGION); + } + return null; + } + return super.createEntity(location, entity, uuid); + } + @Override public ProcessorScope getScope() { return ProcessorScope.READING_SET_BLOCKS; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HistoryExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HistoryExtent.java index de29ff473..2fc5133c6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HistoryExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HistoryExtent.java @@ -18,6 +18,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import static com.google.common.base.Preconditions.checkNotNull; @@ -78,6 +79,16 @@ public class HistoryExtent extends AbstractDelegateExtent { return entity; } + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity state, UUID uuid) { + final Entity entity = super.createEntity(location, state, uuid); + if (state != null) { + this.changeSet.addEntityCreate(state.getNbtData()); + } + return entity; + } + @Override public List getEntities() { return this.wrapEntities(super.getEntities()); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java index e4f2bc2b3..e26f5c630 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java @@ -90,6 +90,21 @@ public class LimitExtent extends AbstractDelegateExtent { } } + @Override + @Nullable + public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { + limit.THROW_MAX_CHANGES(); + limit.THROW_MAX_ENTITIES(); + try { + return super.createEntity(location, entity, uuid); + } catch (FaweException e) { + if (!limit.MAX_FAILS()) { + throw e; + } + return null; + } + } + @Override public void removeEntity(int x, int y, int z, UUID uuid) { limit.THROW_MAX_CHANGES(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/NullExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/NullExtent.java index 07a9c4a49..4f0ad4960 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/NullExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/NullExtent.java @@ -36,6 +36,7 @@ import javax.annotation.Nullable; import java.util.Collection; import java.util.List; import java.util.Set; +import java.util.UUID; import java.util.concurrent.Future; //todo This should be removed in favor of com.sk89q.worldedit.extent.NullExtent @@ -87,6 +88,12 @@ public class NullExtent extends FaweRegionExtent implements IBatchProcessor { throw reason; } + @Nullable + @Override + public Entity createEntity(Location arg0, BaseEntity arg1, UUID arg2) { + throw reason; + } + @Override public BlockState getBlock(BlockVector3 position) { throw reason; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ProcessedWEExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ProcessedWEExtent.java index 9635497b2..5abe90348 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ProcessedWEExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ProcessedWEExtent.java @@ -16,6 +16,8 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockTypes; +import java.util.UUID; + public class ProcessedWEExtent extends AbstractDelegateExtent { private final FaweLimit limit; @@ -43,6 +45,18 @@ public class ProcessedWEExtent extends AbstractDelegateExtent { return super.createEntity(location, entity); } + @Override + public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { + if (entity == null) { + return null; + } + if (!limit.MAX_ENTITIES()) { + WEManager.weManager().cancelEditSafe(this, FaweCache.MAX_ENTITIES); + return null; + } + return super.createEntity(location, entity, uuid); + } + @Override public BlockState getBlock(int x, int y, int z) { if (!limit.MAX_CHECKS()) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java index ea35cb424..ded96d5aa 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java @@ -28,6 +28,7 @@ import java.util.Iterator; import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; @@ -65,6 +66,12 @@ public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProc return super.createEntity(location, stripEntityNBT(entity)); } + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { + return super.createEntity(location, stripEntityNBT(entity), uuid); + } + @SuppressWarnings("unchecked") public > B stripBlockNBT(B block) { if (!(block instanceof BaseBlock localBlock)) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/CPUOptimizedClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/CPUOptimizedClipboard.java index fc2122b07..6f566fcb9 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/CPUOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/CPUOptimizedClipboard.java @@ -5,23 +5,16 @@ import com.fastasyncworldedit.core.math.IntTriple; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.entity.Entity; -import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; -import javax.annotation.Nullable; import java.io.IOException; -import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.List; import java.util.Map; public class CPUOptimizedClipboard extends LinearClipboard { @@ -209,22 +202,4 @@ public class CPUOptimizedClipboard extends LinearClipboard { return true; } - @Nullable - @Override - public Entity createEntity(Location location, BaseEntity entity) { - BlockArrayClipboard.ClipboardEntity ret = new BlockArrayClipboard.ClipboardEntity(location, entity); - entities.add(ret); - return ret; - } - - @Override - public List getEntities() { - return new ArrayList<>(entities); - } - - @Override - public void removeEntity(Entity entity) { - this.entities.remove(entity); - } - } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java index f7cbc0531..acdf9fad7 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java @@ -16,12 +16,10 @@ import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.NBTOutputStream; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BaseBlock; @@ -30,7 +28,6 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockTypes; import org.apache.logging.log4j.Logger; -import javax.annotation.Nullable; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.File; @@ -48,7 +45,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.UUID; -import java.util.stream.Collectors; /** * A clipboard with disk backed storage. (lower memory + loads on crash) @@ -714,47 +710,4 @@ public class DiskOptimizedClipboard extends LinearClipboard { return false; } - @Nullable - @Override - public Entity createEntity(Location location, BaseEntity entity) { - BlockArrayClipboard.ClipboardEntity ret = new BlockArrayClipboard.ClipboardEntity(location, entity); - entities.add(ret); - return ret; - } - - @Override - public List getEntities() { - return new ArrayList<>(entities); - } - - @Override - public List getEntities(Region region) { - return entities - .stream() - .filter(e -> region.contains(e.getLocation().toBlockPoint())).collect(Collectors.toList()); - } - - @Override - public void removeEntity(Entity entity) { - if (!(entity instanceof BlockArrayClipboard.ClipboardEntity)) { - Location loc = entity.getLocation(); - removeEntity(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), entity.getState().getNbtData().getUUID()); - } else { - this.entities.remove(entity); - } - } - - @Override - public void removeEntity(int x, int y, int z, UUID uuid) { - Iterator iter = this.entities.iterator(); - while (iter.hasNext()) { - BlockArrayClipboard.ClipboardEntity entity = iter.next(); - UUID entUUID = entity.getState().getNbtData().getUUID(); - if (uuid.equals(entUUID)) { - iter.remove(); - return; - } - } - } - } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/LinearClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/LinearClipboard.java index 16d8acbf1..143168504 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/LinearClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/LinearClipboard.java @@ -5,21 +5,33 @@ import com.fastasyncworldedit.core.function.visitor.Order; import com.fastasyncworldedit.core.jnbt.streamer.IntValueReader; import com.google.common.collect.ForwardingIterator; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.NBTUtils; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard.ClipboardEntity; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.List; +import java.util.Map; import java.util.UUID; +import java.util.stream.Collectors; public abstract class LinearClipboard extends SimpleClipboard { @@ -83,6 +95,25 @@ public abstract class LinearClipboard extends SimpleClipboard { } + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity) { + BlockArrayClipboard.ClipboardEntity ret = new BlockArrayClipboard.ClipboardEntity(location, entity); + entities.add(ret); + return ret; + } + + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { + Map map = new HashMap<>(entity.getNbtData().getValue()); + NBTUtils.addUUIDToMap(map, uuid); + entity.setNbtData(new CompoundTag(map)); + BlockArrayClipboard.ClipboardEntity ret = new BlockArrayClipboard.ClipboardEntity(location, entity); + entities.add(ret); + return ret; + } + @Override public void removeEntity(int x, int y, int z, UUID uuid) { Iterator iter = this.entities.iterator(); @@ -96,6 +127,28 @@ public abstract class LinearClipboard extends SimpleClipboard { } } + @Override + public List getEntities() { + return new ArrayList<>(entities); + } + + @Override + public void removeEntity(Entity entity) { + if (!(entity instanceof BlockArrayClipboard.ClipboardEntity)) { + Location loc = entity.getLocation(); + removeEntity(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), entity.getState().getNbtData().getUUID()); + } else { + this.entities.remove(entity); + } + } + + @Override + public List getEntities(Region region) { + return entities + .stream() + .filter(e -> region.contains(e.getLocation().toBlockPoint())).collect(Collectors.toList()); + } + private class LinearFilter extends AbstractFilterBlock { private int index = -1; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java index 28dc1d3cc..ed76a9d1f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java @@ -7,13 +7,8 @@ import com.fastasyncworldedit.core.util.MainUtil; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.entity.Entity; -import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; -import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard.ClipboardEntity; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BaseBlock; @@ -22,14 +17,10 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; -import javax.annotation.Nullable; import java.io.IOException; -import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.stream.Collectors; public class MemoryOptimizedClipboard extends LinearClipboard { @@ -293,31 +284,4 @@ public class MemoryOptimizedClipboard extends LinearClipboard { return true; } - @Nullable - @Override - public Entity createEntity(Location location, BaseEntity entity) { - BlockArrayClipboard.ClipboardEntity ret = new BlockArrayClipboard.ClipboardEntity(location, entity); - entities.add(ret); - return ret; - } - - @Override - public List getEntities() { - return new ArrayList<>(entities); - } - - @Override - public List getEntities(Region region) { - return entities - .stream() - .filter(e -> region.contains(e.getLocation().toBlockPoint())).collect(Collectors.toList()); - } - - @Override - public void removeEntity(Entity entity) { - if (entity instanceof ClipboardEntity) { - this.entities.remove(entity); - } - } - } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ReadOnlyClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ReadOnlyClipboard.java index e46c58c0e..4f7245d27 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ReadOnlyClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ReadOnlyClipboard.java @@ -2,10 +2,13 @@ package com.fastasyncworldedit.core.extent.clipboard; import com.fastasyncworldedit.core.Fawe; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.NBTUtils; +import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.request.Request; @@ -14,7 +17,11 @@ import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; +import javax.annotation.Nullable; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.UUID; import java.util.function.Supplier; public abstract class ReadOnlyClipboard extends SimpleClipboard { @@ -103,6 +110,12 @@ public abstract class ReadOnlyClipboard extends SimpleClipboard { throw new UnsupportedOperationException("Clipboard is immutable"); } + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { + throw new UnsupportedOperationException("Clipboard is immutable"); + } + @Override public void removeEntity(Entity entity) { throw new UnsupportedOperationException("Clipboard is immutable"); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/MultiTransform.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/MultiTransform.java index edae11174..946ee8ae5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/MultiTransform.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/MultiTransform.java @@ -12,6 +12,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import javax.annotation.Nullable; import java.util.Collection; +import java.util.UUID; public class MultiTransform extends RandomTransform { @@ -90,4 +91,14 @@ public class MultiTransform extends RandomTransform { return created; } + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { + Entity created = null; + for (AbstractDelegateExtent extent : extents) { + created = extent.createEntity(location, entity, uuid); + } + return created; + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/ScaleTransform.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/ScaleTransform.java index fc7424868..29af87055 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/ScaleTransform.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/ScaleTransform.java @@ -13,6 +13,7 @@ import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; import javax.annotation.Nullable; +import java.util.UUID; public class ScaleTransform extends ResettableExtent { @@ -181,4 +182,17 @@ public class ScaleTransform extends ResettableExtent { return super.createEntity(newLoc, entity); } + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { + Location newLoc = new Location(location.getExtent(), + getPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), + location.getYaw(), location.getPitch() + ); + if (!getExtent().contains(newLoc.toBlockPoint())) { + return null; + } + return super.createEntity(newLoc, entity, uuid); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/SelectTransform.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/SelectTransform.java index c5cda5ff7..57f77b2fe 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/SelectTransform.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/SelectTransform.java @@ -14,6 +14,7 @@ import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; import javax.annotation.Nullable; +import java.util.UUID; public abstract class SelectTransform extends ResettableExtent { @@ -52,6 +53,13 @@ public abstract class SelectTransform extends ResettableExtent { .createEntity(position, entity); } + @Nullable + @Override + public Entity createEntity(Location position, BaseEntity entity, UUID uuid) { + return getExtent(position.getBlockX(), position.getBlockY(), position.getBlockZ()) + .createEntity(position, entity, uuid); + } + @Override public boolean setBiome(BlockVector3 position, BiomeType biome) { return getExtent(position).setBiome(position, biome); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/MutableEntityChange.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/MutableEntityChange.java index 2aeca60d3..b99c576ac 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/MutableEntityChange.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/MutableEntityChange.java @@ -53,15 +53,8 @@ public class MutableEntityChange implements Change { @SuppressWarnings({"unchecked"}) public void delete(UndoContext context) { Map map = tag.getValue(); - long most; - long least; - if (map.containsKey("UUIDMost")) { - most = ((LongTag) map.get("UUIDMost")).getValue(); - least = ((LongTag) map.get("UUIDLeast")).getValue(); - } else if (map.containsKey("PersistentIDMSB")) { - most = ((LongTag) map.get("PersistentIDMSB")).getValue(); - least = ((LongTag) map.get("PersistentIDLSB")).getValue(); - } else { + UUID uuid = tag.getUUID(); + if (uuid == null) { LOGGER.info("Skipping entity without uuid."); return; } @@ -69,7 +62,6 @@ public class MutableEntityChange implements Change { int x = MathMan.roundInt(pos.get(0).getValue()); int y = MathMan.roundInt(pos.get(1).getValue()); int z = MathMan.roundInt(pos.get(2).getValue()); - UUID uuid = new UUID(most, least); context.getExtent().removeEntity(x, y, z, uuid); } @@ -89,7 +81,7 @@ public class MutableEntityChange implements Change { String id = tag.getString("Id"); EntityType type = EntityTypes.parse(id); BaseEntity entity = new BaseEntity(type, tag); - context.getExtent().createEntity(location, entity); + extent.createEntity(location, entity, tag.getUUID()); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkExtent.java index e71680515..63c793ebd 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkExtent.java @@ -5,6 +5,7 @@ import com.sk89q.jnbt.DoubleTag; import com.sk89q.jnbt.IntArrayTag; import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.LongTag; +import com.sk89q.jnbt.NBTUtils; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.WorldEditException; @@ -119,6 +120,11 @@ public interface IChunkExtent extends Extent { @Override default Entity createEntity(Location location, BaseEntity entity) { + return createEntity(location, entity, UUID.randomUUID()); + } + + @Override + default Entity createEntity(Location location, BaseEntity entity, UUID uuid) { final IChunk chunk = getOrCreateChunk(location.getBlockX() >> 4, location.getBlockZ() >> 4); Map map = new HashMap<>(entity.getNbtData().getValue()); //do not modify original entity data map.put("Id", new StringTag(entity.getType().getName())); @@ -130,23 +136,10 @@ public interface IChunkExtent extends Extent { posList.add(new DoubleTag(location.getZ())); map.put("Pos", new ListTag(DoubleTag.class, posList)); - //set new uuid - UUID newuuid = UUID.randomUUID(); - int[] uuidArray = new int[4]; - uuidArray[0] = (int) (newuuid.getMostSignificantBits() >> 32); - uuidArray[1] = (int) newuuid.getMostSignificantBits(); - uuidArray[2] = (int) (newuuid.getLeastSignificantBits() >> 32); - uuidArray[3] = (int) newuuid.getLeastSignificantBits(); - map.put("UUID", new IntArrayTag(uuidArray)); - - map.put("UUIDMost", new LongTag(newuuid.getMostSignificantBits())); - map.put("UUIDLeast", new LongTag(newuuid.getLeastSignificantBits())); - - map.put("PersistentIDMSB", new LongTag(newuuid.getMostSignificantBits())); - map.put("PersistentIDLSB", new LongTag(newuuid.getLeastSignificantBits())); + NBTUtils.addUUIDToMap(map, uuid); chunk.setEntity(new CompoundTag(map)); - return new IChunkEntity(this, location, newuuid, entity); + return new IChunkEntity(this, location, uuid, entity); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java index 763087c3b..39b4210ad 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java @@ -1056,14 +1056,17 @@ public class ChunkHolder> implements IQueueChunk { IChunkGet get = getOrCreateGet(); boolean postProcess = !(getExtent().getPostProcessor() instanceof EmptyBatchProcessor); get.setCreateCopy(postProcess); - set = getExtent().processSet(this, get, set); - try { - return get.call(set, finalize); - } finally { - if (postProcess) { - getExtent().postProcess(this, get.getCopy(), set); - } + final IChunkSet iChunkSet = getExtent().processSet(this, get, set); + Runnable finalizer; + if (postProcess) { + finalizer = () -> { + getExtent().postProcess(this, get.getCopy(), iChunkSet); + finalize.run(); + }; + } else { + finalizer = finalize; } + return get.call(set, finalizer); } return null; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/WorldWrapper.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/WorldWrapper.java index 2893b7290..fc176a785 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/WorldWrapper.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/WorldWrapper.java @@ -42,6 +42,7 @@ import javax.annotation.Nullable; import java.util.Collection; import java.util.List; import java.util.Set; +import java.util.UUID; public class WorldWrapper extends AbstractWorld { @@ -326,6 +327,12 @@ public class WorldWrapper extends AbstractWorld { return parent.createEntity(location, entity); } + @Override + @Nullable + public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { + return parent.createEntity(location, entity, uuid); + } + @Override public BlockState getBlock(BlockVector3 position) { return parent.getBlock(position); diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java index 451c4c679..d91aea8fe 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java @@ -340,9 +340,20 @@ public class CompoundTag extends Tag { //FAWE start public UUID getUUID() { - long most = getLong("UUIDMost"); - long least = getLong("UUIDLeast"); - return new UUID(most, least); + UUID uuid; + if (containsKey("UUID")) { + int[] arr = getIntArray("UUID"); + uuid = new UUID((long) arr[0] << 32 | (arr[1] & 0xFFFFFFFFL), (long) arr[2] << 32 | (arr[3] & 0xFFFFFFFFL)); + } else if (containsKey("UUIDMost")) { + uuid = new UUID(getLong("UUIDMost"), getLong("UUIDLeast")); + } else if (containsKey("WorldUUIDMost")) { + uuid = new UUID(getLong("WorldUUIDMost"), getLong("WorldUUIDLeast")); + } else if (containsKey("PersistentIDMSB")) { + uuid = new UUID(getLong("PersistentIDMSB"), getLong("PersistentIDLSB")); + } else { + return null; + } + return uuid; } public Vector3 getEntityPosition() { diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java index f6217e8a7..09f87385e 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java @@ -24,6 +24,7 @@ import com.sk89q.worldedit.util.nbt.BinaryTagTypes; import com.sk89q.worldedit.world.storage.InvalidFormatException; import java.util.Map; +import java.util.UUID; import static com.google.common.base.Preconditions.checkNotNull; @@ -170,4 +171,31 @@ public final class NBTUtils { return expected.cast(tag); } + //FAWE start + /** + * Add a {@link UUID} to a map for use in a {@link CompoundTag} + * + * @param map Map to add uuid to + * @param uuid {@link UUID} to add + * @since TODO + */ + public static void addUUIDToMap(Map map, UUID uuid) { + int[] uuidArray = new int[4]; + uuidArray[0] = (int) (uuid.getMostSignificantBits() >> 32); + uuidArray[1] = (int) uuid.getMostSignificantBits(); + uuidArray[2] = (int) (uuid.getLeastSignificantBits() >> 32); + uuidArray[3] = (int) uuid.getLeastSignificantBits(); + map.put("UUID", new IntArrayTag(uuidArray)); + + map.put("UUIDMost", new LongTag(uuid.getMostSignificantBits())); + map.put("UUIDLeast", new LongTag(uuid.getLeastSignificantBits())); + + map.put("WorldUUIDMost", new LongTag(uuid.getMostSignificantBits())); + map.put("WorldUUIDLeast", new LongTag(uuid.getLeastSignificantBits())); + + map.put("PersistentIDMSB", new LongTag(uuid.getMostSignificantBits())); + map.put("PersistentIDLSB", new LongTag(uuid.getLeastSignificantBits())); + } + //FAWE end + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 0335a2e92..f4bb7bd6a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -3699,6 +3699,15 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { } } + @Override + public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { + try { + return this.getExtent().createEntity(location, entity, uuid); + } catch (WorldEditException e) { + throw new RuntimeException("Unexpected exception", e); + } + } + @Override public void removeEntity(int x, int y, int z, UUID uuid) { try { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java index d3944a153..9dfd373ea 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java @@ -141,6 +141,14 @@ public class AbstractDelegateExtent implements Extent { return extent.createEntity(location, entity); } + //FAWE start + @Override + @Nullable + public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { + return extent.createEntity(location, entity, uuid); + } + //FAWE end + @Override @Nullable public Operation commit() { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/ChangeSetExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/ChangeSetExtent.java index 0239eb1ed..12ac9c428 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/ChangeSetExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/ChangeSetExtent.java @@ -37,6 +37,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import static com.google.common.base.Preconditions.checkNotNull; @@ -78,11 +79,23 @@ public class ChangeSetExtent extends AbstractDelegateExtent { public Entity createEntity(Location location, BaseEntity state) { Entity entity = super.createEntity(location, state); if (entity != null) { - changeSet.add(new EntityCreate(location, state, entity)); + changeSet.add(new EntityCreate(location, entity.getState(), entity)); } return entity; } + //FAWE start + @Override + @Nullable + public Entity createEntity(Location location, BaseEntity state, UUID uuid) { + Entity entity = super.createEntity(location, state, uuid); + if (entity != null) { + changeSet.add(new EntityCreate(location, entity.getState(), entity)); + } + return entity; + } + //FAWE end + @Override public List getEntities() { return wrapEntities(super.getEntities()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java index fa53076eb..fc258893e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java @@ -148,6 +148,21 @@ public interface Extent extends InputExtent, OutputExtent { } //FAWE start + /** + * Create an entity at the given location, forcing a UUID onto the entity + * + * Only use if you are aware of the consequences of forcing a UUID to an entity. + * + * @param entity the entity + * @param location the location + * @param uuid UUID to force the entity to have + * @return a reference to the created entity, or null if the entity could not be created + * @since TODO + */ + @Nullable + default Entity createEntity(Location location, BaseEntity entity, UUID uuid) { + return null; + } /** * Create an entity at the given location. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/NullExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/NullExtent.java index 6c51714c4..934b52204 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/NullExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/NullExtent.java @@ -38,6 +38,7 @@ import com.sk89q.worldedit.world.block.BlockTypes; import javax.annotation.Nullable; import java.util.Collections; import java.util.List; +import java.util.UUID; /** * An extent that returns air blocks for all blocks and does not @@ -73,6 +74,14 @@ public class NullExtent implements Extent { return null; } + //FAWE start + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { + return null; + } + //FAWE end + @Override public BlockState getBlock(BlockVector3 position) { return BlockTypes.AIR.getDefaultState(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/TracingExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/TracingExtent.java index b11278568..231daf9f7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/TracingExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/TracingExtent.java @@ -34,6 +34,7 @@ import javax.annotation.Nullable; import java.util.Collections; import java.util.EnumSet; import java.util.Set; +import java.util.UUID; /** * An extent that can report back if an operation fails due to the extent(s) below it. @@ -106,6 +107,20 @@ public class TracingExtent extends AbstractDelegateExtent { return result; } + //FAWE start + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { + BlockVector3 blockVector3 = location.toVector().toBlockPoint(); + touchedLocations.add(blockVector3); + Entity result = super.createEntity(location, entity, uuid); + if (result == null) { + failedActions.put(blockVector3, Action.CREATE_ENTITY); + } + return result; + } + //FAWE end + @Override public String toString() { return "TracingExtent{delegate=" + getExtent() + "}"; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java index 3625fed4a..ce935754f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java @@ -304,6 +304,18 @@ public class BlockArrayClipboard implements Clipboard { return getParent().createEntity(l, entity); } + @Override + @Nullable + public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { + Location l = new Location(location.getExtent(), + location.getX() - offset.getBlockX(), + location.getY() - offset.getBlockY(), + location.getZ() - offset.getBlockZ(), + location.getYaw(), location.getPitch() + ); + return getParent().createEntity(l, entity, uuid); + } + @Override public void removeEntity(int x, int y, int z, UUID uuid) { x -= offset.getX(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/WatchdogTickingExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/WatchdogTickingExtent.java index da425b11a..fda1acdbb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/WatchdogTickingExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/WatchdogTickingExtent.java @@ -31,6 +31,7 @@ import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; import javax.annotation.Nullable; +import java.util.UUID; /** * Extent that ticks the watchdog before every world-affecting action. @@ -86,6 +87,15 @@ public class WatchdogTickingExtent extends AbstractDelegateExtent { return super.createEntity(location, entity); } + //FAWE start + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { + onOperation(); + return super.createEntity(location, entity, uuid); + } + //FAWE end + @Override public boolean setBiome(BlockVector3 position, BiomeType biome) { onOperation(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java index 4e3fdfd79..88f151e28 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.function.entity; +import com.fastasyncworldedit.core.util.TaskManager; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTagBuilder; import com.sk89q.jnbt.FloatTag; @@ -165,6 +166,8 @@ public class ExtentEntityCopy implements EntityFunction { uuid = new UUID((long) arr[0] << 32 | (arr[1] & 0xFFFFFFFFL), (long) arr[2] << 32 | (arr[3] & 0xFFFFFFFFL)); } else if (tag.containsKey("UUIDMost")) { uuid = new UUID(tag.getLong("UUIDMost"), tag.getLong("UUIDLeast")); + } else if (tag.containsKey("WorldUUIDMost")) { + uuid = new UUID(tag.getLong("WorldUUIDMost"), tag.getLong("WorldUUIDLeast")); } else if (tag.containsKey("PersistentIDMSB")) { uuid = new UUID(tag.getLong("PersistentIDMSB"), tag.getLong("PersistentIDLSB")); } @@ -177,8 +180,8 @@ public class ExtentEntityCopy implements EntityFunction { uuid ); } else { + TaskManager.taskManager().sync(entity::remove); //FAWE end - entity.remove(); } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestExtent.java index 7f9db23fa..2af8232af 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestExtent.java @@ -36,6 +36,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import javax.annotation.Nullable; import java.util.List; +import java.util.UUID; public class RequestExtent implements Extent { @@ -75,6 +76,14 @@ public class RequestExtent implements Extent { return getExtent().createEntity(location, entity); } + //FAWE start + @Override + @Nullable + public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { + return getExtent().createEntity(location, entity, uuid); + } + //FAWE end + @Override public BlockState getBlock(BlockVector3 position) { return getExtent().getBlock(position); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java index 73d9110f0..908e0bac6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java @@ -52,6 +52,7 @@ import javax.annotation.Nullable; import java.util.Collections; import java.util.List; import java.util.Set; +import java.util.UUID; /** * A null implementation of {@link World} that drops all changes and @@ -229,6 +230,14 @@ public class NullWorld extends AbstractWorld { return null; } + //FAWE start + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { + return null; + } + //FAWE end + /** * Return an instance of this null world. *