diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 1b79270374..67e0d06cd1 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -50,7 +50,8 @@ dependencies { implementation("org.ajoberstar.grgit:grgit-gradle:4.1.0") implementation("gradle.plugin.com.github.johnrengelman:shadow:7.1.0") implementation("org.jfrog.buildinfo:build-info-extractor-gradle:4.24.23") - implementation("org.spongepowered:SpongeGradle:0.11.5") + implementation("org.spongepowered:spongegradle-plugin-development:1.1.0") + implementation("org.spongepowered:vanillagradle:0.1") implementation("net.minecraftforge.gradle:ForgeGradle:5.1.26") implementation("net.fabricmc:fabric-loom:$loomVersion") implementation("net.fabricmc:sponge-mixin:$mixinVersion") diff --git a/buildSrc/src/main/kotlin/LibsConfig.kt b/buildSrc/src/main/kotlin/LibsConfig.kt index 5a422a4d8d..07a558e7dc 100644 --- a/buildSrc/src/main/kotlin/LibsConfig.kt +++ b/buildSrc/src/main/kotlin/LibsConfig.kt @@ -51,6 +51,9 @@ fun Project.applyLibrariesConfiguration() { exclude(dependency("org.checkerframework:checker-qual")) exclude(dependency("org.apache.logging.log4j:log4j-api")) exclude(dependency("com.google.code.findbugs:jsr305")) + exclude { + it.moduleGroup == "org.jetbrains.kotlin" + } } relocations.forEach { (from, to) -> diff --git a/worldedit-core/build.gradle.kts b/worldedit-core/build.gradle.kts index 0e7c38abfb..0b7d45f1c4 100644 --- a/worldedit-core/build.gradle.kts +++ b/worldedit-core/build.gradle.kts @@ -39,7 +39,7 @@ dependencies { "implementation"("org.mozilla:rhino-runtime:1.7.13") "implementation"("org.yaml:snakeyaml:1.26") "implementation"("com.google.guava:guava") - "implementation"("com.google.code.findbugs:jsr305:1.3.9") + "compileOnlyApi"("com.google.code.findbugs:jsr305:1.3.9") "implementation"("com.google.code.gson:gson") "implementation"("org.apache.logging.log4j:log4j-api:${Versions.LOG4J}") { diff --git a/worldedit-libs/sponge/build.gradle.kts b/worldedit-libs/sponge/build.gradle.kts index 47bd7e59c5..7f10cf0124 100644 --- a/worldedit-libs/sponge/build.gradle.kts +++ b/worldedit-libs/sponge/build.gradle.kts @@ -8,5 +8,4 @@ repositories { } } dependencies { - "shade"("net.kyori:text-adapter-spongeapi:${Versions.TEXT_EXTRAS}") } diff --git a/worldedit-sponge/build.gradle.kts b/worldedit-sponge/build.gradle.kts index affa68b86a..41d82822e6 100644 --- a/worldedit-sponge/build.gradle.kts +++ b/worldedit-sponge/build.gradle.kts @@ -1,54 +1,77 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import org.spongepowered.gradle.plugin.config.PluginLoaders +import org.spongepowered.plugin.metadata.PluginDependency plugins { id("org.spongepowered.gradle.plugin") + id("org.spongepowered.gradle.vanilla") } applyPlatformAndCoreConfiguration() applyShadowConfiguration() -// I can't believe sponge sets this in a base plugin with no opt-out -convention.getPlugin(JavaPluginConvention::class.java).apply { - setSourceCompatibility(null) - setTargetCompatibility(null) +repositories { + mavenCentral() } -repositories { - maven { url = uri("https://repo.codemc.org/repository/maven-public") } +minecraft { + version("1.16.5") +} + +sponge { + apiVersion("8.0.0") + plugin("worldedit") { + loader(PluginLoaders.JAVA_PLAIN) + displayName("WorldEdit") + version(project.ext["internalVersion"].toString()) + mainClass("com.sk89q.worldedit.sponge.SpongeWorldEdit") + description("WorldEdit is an easy-to-use in-game world editor for Minecraft, supporting both single- and multi-player.") + links { + homepage("https://enginehub.org/worldedit/") + source("https://github.com/EngineHub/WorldEdit") + issues("https://github.com/EngineHub/WorldEdit/issues") + } + contributor("EngineHub") { + description("Various members of the EngineHub team") + } + dependency("spongeapi") { + loadOrder(PluginDependency.LoadOrder.AFTER) + optional(false) + } + } } dependencies { api(project(":worldedit-core")) api(project(":worldedit-libs:sponge")) - api("org.spongepowered:spongeapi:7.1.0") { + api("org.spongepowered:spongeapi:8.0.0-SNAPSHOT") { exclude(group = "org.slf4j", module = "slf4j-api") } implementation(platform("org.apache.logging.log4j:log4j-bom:${Versions.LOG4J}") { because("Sponge 8 (will?) provides Log4J") }) api("org.apache.logging.log4j:log4j-api") - api("org.bstats:bstats-sponge:1.7") - testImplementation("org.mockito:mockito-core:1.9.0-rc1") + // bStats isn't updated yet :( + // api("org.bstats:bstats-sponge:2.2.1") + testImplementation("org.mockito:mockito-core:${Versions.MOCKITO}") } addJarManifest(WorldEditKind.Mod, includeClasspath = true) tasks.named("shadowJar") { dependencies { - relocate ("org.bstats", "com.sk89q.worldedit.sponge.bstats") { - include(dependency("org.bstats:bstats-sponge:1.7")) + relocate("org.bstats", "com.sk89q.worldedit.sponge.bstats") { + include(dependency("org.bstats:bstats-sponge")) } - } -} + include(dependency(":worldedit-core")) -if (project.hasProperty("signing")) { - apply(plugin = "signing") - - configure { - sign("shadowJar") - } - - tasks.named("build").configure { - dependsOn("signShadowJar") + relocate("org.antlr.v4", "com.sk89q.worldedit.sponge.antlr4") + include(dependency("org.antlr:antlr4-runtime")) + relocate("it.unimi.dsi.fastutil", "com.sk89q.worldedit.sponge.fastutil") { + include(dependency("it.unimi.dsi:fastutil")) + } } } +tasks.named("assemble").configure { + dependsOn("shadowJar") +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CUIChannelHandler.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CUIChannelHandler.java index 8e342f79ca..79f23a134c 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CUIChannelHandler.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CUIChannelHandler.java @@ -20,42 +20,48 @@ package com.sk89q.worldedit.sponge; import com.sk89q.worldedit.LocalSession; -import org.spongepowered.api.Platform; -import org.spongepowered.api.Sponge; -import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.network.ChannelBinding; -import org.spongepowered.api.network.ChannelBuf; -import org.spongepowered.api.network.PlayerConnection; -import org.spongepowered.api.network.RawDataListener; -import org.spongepowered.api.network.RemoteConnection; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.util.lifecycle.SimpleLifecycled; +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; +import org.spongepowered.api.event.Listener; +import org.spongepowered.api.event.lifecycle.RegisterChannelEvent; +import org.spongepowered.api.network.ServerPlayerConnection; +import org.spongepowered.api.network.channel.ChannelBuf; +import org.spongepowered.api.network.channel.raw.RawDataChannel; +import org.spongepowered.api.network.channel.raw.play.RawPlayDataHandler; import java.nio.charset.StandardCharsets; -public class CUIChannelHandler implements RawDataListener { - public static final String CUI_PLUGIN_CHANNEL = "worldedit:cui"; +public class CUIChannelHandler implements RawPlayDataHandler { + public static final ResourceKey CUI_PLUGIN_CHANNEL = ResourceKey.of("worldedit", "cui"); + private static final SimpleLifecycled CHANNEL = SimpleLifecycled.invalid(); - private static ChannelBinding.RawDataChannel channel; - - public static void init() { - channel = Sponge.getChannelRegistrar().createRawChannel(SpongeWorldEdit.inst(), CUI_PLUGIN_CHANNEL); - channel.addListener(Platform.Type.SERVER, new CUIChannelHandler()); + public static final class RegistrationHandler { + @Listener + public void onChannelRegistration(RegisterChannelEvent event) { + RawDataChannel channel = event.register(CUI_PLUGIN_CHANNEL, RawDataChannel.class); + channel.play().addHandler(ServerPlayerConnection.class, new CUIChannelHandler()); + CHANNEL.newValue(channel); + } } - - public static ChannelBinding.RawDataChannel getActiveChannel() { - return channel; + public static RawDataChannel channel() { + return CHANNEL.valueOrThrow(); } @Override - public void handlePayload(ChannelBuf data, RemoteConnection connection, Platform.Type side) { - if (connection instanceof PlayerConnection) { - Player player = ((PlayerConnection) connection).getPlayer(); + public void handlePayload(ChannelBuf data, ServerPlayerConnection connection) { + ServerPlayer player = connection.player(); - LocalSession session = SpongeWorldEdit.inst().getSession(player); + SpongePlayer spongePlayer = SpongeAdapter.adapt(player); + LocalSession session = WorldEdit.getInstance().getSessionManager().get( + spongePlayer + ); - final SpongePlayer actor = SpongeWorldEdit.inst().wrapPlayer(player); - session.handleCUIInitializationMessage(new String(data.readBytes(data.available()), StandardCharsets.UTF_8), - actor); - } + session.handleCUIInitializationMessage( + new String(data.readBytes(data.available()), StandardCharsets.UTF_8), + spongePlayer + ); } } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CommandAdapter.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CommandAdapter.java index 261d811b8d..a8404ba428 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CommandAdapter.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CommandAdapter.java @@ -20,18 +20,17 @@ package com.sk89q.worldedit.sponge; import com.sk89q.worldedit.command.util.PermissionCondition; +import com.sk89q.worldedit.sponge.internal.LocaleResolver; +import net.kyori.adventure.text.Component; +import org.checkerframework.checker.nullness.qual.NonNull; import org.enginehub.piston.Command; -import org.spongepowered.api.command.CommandCallable; -import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.text.Text; +import org.spongepowered.api.command.CommandCause; import java.util.Collections; import java.util.Optional; import java.util.Set; -import static com.sk89q.worldedit.sponge.SpongeTextAdapter.convert; - -public abstract class CommandAdapter implements CommandCallable { +public abstract class CommandAdapter implements org.spongepowered.api.command.Command.Raw { private final Command command; protected CommandAdapter(Command command) { @@ -39,12 +38,12 @@ protected CommandAdapter(Command command) { } @Override - public boolean testPermission(CommandSource source) { + public boolean canExecute(CommandCause cause) { Set permissions = command.getCondition().as(PermissionCondition.class) .map(PermissionCondition::getPermissions) .orElseGet(Collections::emptySet); for (String perm : permissions) { - if (source.hasPermission(perm)) { + if (cause.hasPermission(perm)) { return true; } } @@ -52,19 +51,25 @@ public boolean testPermission(CommandSource source) { } @Override - public Optional getShortDescription(CommandSource source) { + public Optional shortDescription(CommandCause cause) { return Optional.of(command.getDescription()) - .map(desc -> SpongeTextAdapter.convert(desc, source.getLocale())); + .map(desc -> SpongeTextAdapter.convert(desc, LocaleResolver.resolveLocale(cause.audience()))); + } + + @Override + public Optional extendedDescription(CommandCause cause) { + return command.getFooter() + .map(footer -> SpongeTextAdapter.convert(footer, LocaleResolver.resolveLocale(cause.audience()))); } @Override - public Optional getHelp(CommandSource source) { + public Optional help(@NonNull CommandCause cause) { return Optional.of(command.getFullHelp()) - .map(help -> SpongeTextAdapter.convert(help, source.getLocale())); + .map(help -> SpongeTextAdapter.convert(help, LocaleResolver.resolveLocale(cause.audience()))); } @Override - public Text getUsage(CommandSource source) { - return convert(command.getUsage(), source.getLocale()); + public Component usage(CommandCause cause) { + return SpongeTextAdapter.convert(command.getUsage(), LocaleResolver.resolveLocale(cause.audience())); } } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/adapter/AdapterLoadException.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/Constants.java similarity index 65% rename from worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/adapter/AdapterLoadException.java rename to worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/Constants.java index f2698fc729..7edfd16c6f 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/adapter/AdapterLoadException.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/Constants.java @@ -17,25 +17,23 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.sponge.adapter; +package com.sk89q.worldedit.sponge; + +import org.spongepowered.api.data.persistence.DataQuery; /** - * Thrown when no adapter can be found. + * Kinda mirrors Sponge Common's Constants class. + * + *

Internal. Do not use.

*/ -public class AdapterLoadException extends Exception { - - public AdapterLoadException() { - } - - public AdapterLoadException(String message) { - super(message); - } +public class Constants { + public static class Sponge { + public static final DataQuery UNSAFE_NBT = DataQuery.of("UnsafeData"); - public AdapterLoadException(String message, Throwable cause) { - super(message, cause); + private Sponge() { + } } - public AdapterLoadException(Throwable cause) { - super(cause); + private Constants() { } } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeAdapter.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeAdapter.java index 5f720b679c..6cec6affc7 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeAdapter.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeAdapter.java @@ -19,15 +19,37 @@ package com.sk89q.worldedit.sponge; -import com.flowpowered.math.vector.Vector3d; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.sponge.internal.NbtAdapter; +import com.sk89q.worldedit.sponge.internal.SpongeTransmogrifier; +import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.item.ItemTypes; +import net.minecraft.world.level.block.Block; +import org.spongepowered.api.ResourceKey; import org.spongepowered.api.Sponge; +import org.spongepowered.api.data.persistence.DataContainer; +import org.spongepowered.api.data.persistence.DataView; import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; +import org.spongepowered.api.item.inventory.ItemStack; +import org.spongepowered.api.registry.RegistryKey; +import org.spongepowered.api.registry.RegistryReference; +import org.spongepowered.api.registry.RegistryTypes; +import org.spongepowered.api.world.biome.Biome; +import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.api.world.server.ServerWorld; +import org.spongepowered.math.vector.Vector3d; +import org.spongepowered.math.vector.Vector3i; + +import java.util.Objects; import static com.google.common.base.Preconditions.checkNotNull; @@ -36,22 +58,21 @@ */ public class SpongeAdapter { - private SpongeAdapter() { + public static org.spongepowered.api.block.BlockState adapt(BlockState blockState) { + int blockStateId = BlockStateIdAccess.getBlockStateId(blockState); + if (!BlockStateIdAccess.isValidInternalId(blockStateId)) { + return SpongeTransmogrifier.transmogToMinecraft(blockState); + } + return (org.spongepowered.api.block.BlockState) Block.stateById(blockStateId); } - /** - * Create a WorldEdit world from a Sponge extent. - * - * @param world the Sponge extent - * @return a WorldEdit world - */ - public static World checkWorld(org.spongepowered.api.world.extent.Extent world) { - checkNotNull(world); - if (world instanceof org.spongepowered.api.world.World) { - return adapt((org.spongepowered.api.world.World) world); - } else { - throw new IllegalArgumentException("Extent type is not a world"); + public static BlockState adapt(org.spongepowered.api.block.BlockState blockState) { + int blockStateId = Block.getId((net.minecraft.world.level.block.state.BlockState) blockState); + BlockState worldEdit = BlockStateIdAccess.getBlockStateById(blockStateId); + if (worldEdit == null) { + return SpongeTransmogrifier.transmogToWorldEdit(blockState); } + return worldEdit; } /** @@ -60,9 +81,9 @@ public static World checkWorld(org.spongepowered.api.world.extent.Extent world) * @param world the Sponge world * @return a WorldEdit world */ - public static World adapt(org.spongepowered.api.world.World world) { + public static World adapt(ServerWorld world) { checkNotNull(world); - return SpongeWorldEdit.inst().getWorld(world); + return new SpongeWorld(world); } /** @@ -71,12 +92,13 @@ public static World adapt(org.spongepowered.api.world.World world) { * @param player The Sponge player * @return The WorldEdit player */ - public static SpongePlayer adapt(Player player) { - return SpongeWorldEdit.inst().wrapPlayer(player); + public static SpongePlayer adapt(ServerPlayer player) { + Objects.requireNonNull(player); + return new SpongePlayer(player); } /** - * Create a Bukkit Player from a WorldEdit Player. + * Create a Sponge Player from a WorldEdit Player. * * @param player The WorldEdit player * @return The Bukkit player @@ -91,12 +113,15 @@ public static Player adapt(com.sk89q.worldedit.entity.Player player) { * @param world the WorldEdit world * @return a Sponge world */ - public static org.spongepowered.api.world.World adapt(World world) { + public static ServerWorld adapt(World world) { checkNotNull(world); if (world instanceof SpongeWorld) { return ((SpongeWorld) world).getWorld(); } else { - org.spongepowered.api.world.World match = Sponge.getServer().getWorld(world.getName()).orElse(null); + // Currently this is 99% certain to fail, we don't have consistent world name/id mapping + ServerWorld match = Sponge.server().worldManager().world( + ResourceKey.resolve(world.getName()) + ).orElse(null); if (match != null) { return match; } else { @@ -105,12 +130,9 @@ public static org.spongepowered.api.world.World adapt(World world) { } } - public static BiomeType adapt(org.spongepowered.api.world.biome.BiomeType biomeType) { - return BiomeTypes.get(biomeType.getId()); - } - - public static org.spongepowered.api.world.biome.BiomeType adapt(BiomeType biomeType) { - return Sponge.getRegistry().getType(org.spongepowered.api.world.biome.BiomeType.class, biomeType.getId()).orElse(null); + public static RegistryReference adapt(BiomeType biomeType) { + return RegistryKey.of(RegistryTypes.BIOME, ResourceKey.resolve(biomeType.getId())) + .asReference(); } /** @@ -119,14 +141,15 @@ public static org.spongepowered.api.world.biome.BiomeType adapt(BiomeType biomeT * @param location the Sponge location * @return a WorldEdit location */ - public static Location adapt(org.spongepowered.api.world.Location location, Vector3d rotation) { + public static Location adapt(ServerLocation location, Vector3d rotation) { checkNotNull(location); Vector3 position = asVector(location); return new Location( - adapt(location.getExtent()), - position, - (float) rotation.getX(), - (float) rotation.getY()); + adapt(location.world()), + position, + (float) rotation.x(), + (float) rotation.y() + ); } /** @@ -135,12 +158,13 @@ public static Location adapt(org.spongepowered.api.world.Location adapt(Location location) { + public static ServerLocation adapt(Location location) { checkNotNull(location); Vector3 position = location.toVector(); - return new org.spongepowered.api.world.Location<>( - adapt((World) location.getExtent()), - position.getX(), position.getY(), position.getZ()); + return ServerLocation.of( + adapt((World) location.getExtent()), + position.getX(), position.getY(), position.getZ() + ); } /** @@ -155,24 +179,66 @@ public static Vector3d adaptRotation(Location location) { } /** - * Create a WorldEdit Vector from a Bukkit location. + * Create a WorldEdit Vector from a Sponge location. * - * @param location The Bukkit location + * @param location The Sponge location * @return a WorldEdit vector */ - public static Vector3 asVector(org.spongepowered.api.world.Location location) { + public static Vector3 asVector(ServerLocation location) { checkNotNull(location); - return Vector3.at(location.getX(), location.getY(), location.getZ()); + return Vector3.at(location.x(), location.y(), location.z()); } /** - * Create a WorldEdit BlockVector from a Bukkit location. + * Create a WorldEdit BlockVector from a Sponge location. * - * @param location The Bukkit location + * @param location The Sponge location * @return a WorldEdit vector */ - public static BlockVector3 asBlockVector(org.spongepowered.api.world.Location location) { + public static BlockVector3 asBlockVector(ServerLocation location) { checkNotNull(location); - return BlockVector3.at(location.getX(), location.getY(), location.getZ()); + return BlockVector3.at(location.x(), location.y(), location.z()); } + + public static BaseItemStack adapt(ItemStack itemStack) { + CompoundTag tag = itemStack.toContainer().getView(Constants.Sponge.UNSAFE_NBT) + .map(NbtAdapter::adaptToWorldEdit) + .orElse(null); + return new BaseItemStack( + ItemTypes.get(itemStack.type().key(RegistryTypes.ITEM_TYPE).asString()), + tag, + itemStack.quantity() + ); + } + + public static ItemStack adapt(BaseItemStack itemStack) { + ItemStack stack = ItemStack.builder() + .itemType(() -> Sponge.game().registries().registry(RegistryTypes.ITEM_TYPE) + .value(ResourceKey.resolve(itemStack.getType().getId()))) + .quantity(itemStack.getAmount()) + .build(); + if (itemStack.getNbtData() != null) { + stack.setRawData( + DataContainer.createNew(DataView.SafetyMode.NO_DATA_CLONED) + .set(Constants.Sponge.UNSAFE_NBT, NbtAdapter.adaptFromWorldEdit(itemStack.getNbtData())) + ); + } + return stack; + } + + public static Direction adapt(org.spongepowered.api.util.Direction direction) { + return Direction.valueOf(direction.name()); + } + + public static Vector3i adaptVector3i(BlockVector3 bv3) { + return new Vector3i(bv3.getX(), bv3.getY(), bv3.getZ()); + } + + public static BlockVector3 adaptVector3i(Vector3i vec3i) { + return BlockVector3.at(vec3i.x(), vec3i.y(), vec3i.z()); + } + + private SpongeAdapter() { + } + } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBiomeRegistry.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBiomeRegistry.java index fd012d2941..48dafb6a2e 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBiomeRegistry.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBiomeRegistry.java @@ -24,7 +24,8 @@ import com.sk89q.worldedit.util.translation.TranslationManager; import com.sk89q.worldedit.world.biome.BiomeData; import com.sk89q.worldedit.world.registry.BiomeRegistry; -import org.spongepowered.api.world.biome.BiomeType; +import org.spongepowered.api.registry.RegistryReference; +import org.spongepowered.api.world.biome.Biome; import javax.annotation.Nullable; @@ -49,21 +50,21 @@ public BiomeData getData(com.sk89q.worldedit.world.biome.BiomeType biome) { @Deprecated private static class SpongeBiomeData implements BiomeData { - private final BiomeType biome; + private final RegistryReference biome; /** * Create a new instance. * * @param biome the base biome */ - private SpongeBiomeData(BiomeType biome) { + private SpongeBiomeData(RegistryReference biome) { this.biome = biome; } @SuppressWarnings("deprecation") @Override public String getName() { - return biome.getName(); + return biome.location().asString(); } } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBlockCategoryRegistry.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBlockCategoryRegistry.java new file mode 100644 index 0000000000..8990fd9487 --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBlockCategoryRegistry.java @@ -0,0 +1,44 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.registry.BlockCategoryRegistry; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.BlockTags; +import net.minecraft.tags.Tag; + +import java.util.Collections; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +public class SpongeBlockCategoryRegistry implements BlockCategoryRegistry { + @Override + public Set getCategorisedByName(String category) { + return Optional.ofNullable(BlockTags.getAllTags().getTag(new ResourceLocation(category))) + .map(Tag::getValues) + .orElse(Collections.emptyList()) + .stream() + .map(b -> BlockType.REGISTRY.get(Registry.BLOCK.getKey(b).toString())) + .collect(Collectors.toSet()); + } +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBlockMaterial.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBlockMaterial.java new file mode 100644 index 0000000000..b204f20451 --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBlockMaterial.java @@ -0,0 +1,96 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.sk89q.worldedit.world.registry.BlockMaterial; +import com.sk89q.worldedit.world.registry.PassthroughBlockMaterial; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Material; +import net.minecraft.world.level.material.PushReaction; + +import javax.annotation.Nullable; + +/** + * Fabric block material that pulls as much info as possible from the Minecraft + * Material, and passes the rest to another implementation, typically the + * bundled block info. + */ +public class SpongeBlockMaterial extends PassthroughBlockMaterial { + + private final Material delegate; + private final BlockState block; + + public SpongeBlockMaterial(Material delegate, BlockState block, @Nullable BlockMaterial secondary) { + super(secondary); + this.delegate = delegate; + this.block = block; + } + + @Override + public boolean isAir() { + return delegate == Material.AIR || super.isAir(); + } + + @Override + public boolean isOpaque() { + return delegate.isSolidBlocking(); + } + + @Override + public boolean isLiquid() { + return delegate.isLiquid(); + } + + @Override + public boolean isSolid() { + return delegate.isSolid(); + } + + @Override + public boolean isFragileWhenPushed() { + return delegate.getPushReaction() == PushReaction.DESTROY; + } + + @Override + public boolean isUnpushable() { + return delegate.getPushReaction() == PushReaction.BLOCK; + } + + @Override + public boolean isMovementBlocker() { + return delegate.blocksMotion(); + } + + @Override + public boolean isBurnable() { + return delegate.isFlammable(); + } + + @Override + public boolean isToolRequired() { + return block.requiresCorrectToolForDrops(); + } + + @Override + public boolean isReplacedDuringPlacement() { + return delegate.isReplaceable(); + } + +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBlockRegistry.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBlockRegistry.java new file mode 100644 index 0000000000..c9630bceb0 --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBlockRegistry.java @@ -0,0 +1,92 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.sponge.internal.SpongeTransmogrifier; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.registry.BlockMaterial; +import com.sk89q.worldedit.world.registry.BundledBlockRegistry; +import net.minecraft.world.level.block.Block; +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.registry.RegistryTypes; +import org.spongepowered.api.state.StateProperty; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.OptionalInt; +import java.util.TreeMap; + +public class SpongeBlockRegistry extends BundledBlockRegistry { + + private final Map materialMap = + new HashMap<>(); + + @Override + public Component getRichName(BlockType blockType) { + return SpongeTextAdapter.convert(Sponge.game().registries().registry(RegistryTypes.BLOCK_TYPE) + .value(ResourceKey.resolve(blockType.getId())).asComponent()); + } + + @Override + public BlockMaterial getMaterial(BlockType blockType) { + org.spongepowered.api.block.BlockType spongeBlockType = + Sponge.game().registries().registry(RegistryTypes.BLOCK_TYPE) + .value(ResourceKey.resolve(blockType.getId())); + return materialMap.computeIfAbsent( + spongeBlockType.defaultState(), + m -> { + net.minecraft.world.level.block.state.BlockState blockState = + (net.minecraft.world.level.block.state.BlockState) m; + return new SpongeBlockMaterial( + blockState.getMaterial(), + blockState, + super.getMaterial(blockType) + ); + } + ); + } + + @Override + public Map> getProperties(BlockType blockType) { + org.spongepowered.api.block.BlockType spongeBlockType = + Sponge.game().registries().registry(RegistryTypes.BLOCK_TYPE) + .value(ResourceKey.resolve(blockType.getId())); + Map> map = new TreeMap<>(); + Collection> propertyKeys = spongeBlockType + .defaultState().stateProperties(); + for (StateProperty key : propertyKeys) { + map.put(key.name(), SpongeTransmogrifier.transmogToWorldEditProperty(key)); + } + return map; + } + + @Override + public OptionalInt getInternalBlockStateId(BlockState state) { + org.spongepowered.api.block.BlockState equivalent = SpongeAdapter.adapt(state); + return OptionalInt.of(Block.getId( + (net.minecraft.world.level.block.state.BlockState) equivalent + )); + } +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeCommandSender.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeCommandSender.java index 39b8cfd2c8..a75ee8fc6c 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeCommandSender.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeCommandSender.java @@ -23,21 +23,15 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.session.SessionKey; -import com.sk89q.worldedit.util.auth.AuthorizationException; -import com.sk89q.worldedit.util.formatting.WorldEditText; import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.adapter.spongeapi.TextAdapter; -import org.spongepowered.api.command.CommandSource; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; +import net.kyori.adventure.audience.Audience; import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.text.format.TextColor; -import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.text.serializer.TextSerializers; import java.io.File; import java.util.Locale; import java.util.UUID; -import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; @@ -49,15 +43,15 @@ public class SpongeCommandSender implements Actor { */ private static final UUID DEFAULT_ID = UUID.fromString("a233eb4b-4cab-42cd-9fd9-7e7b9a3f74be"); - private final CommandSource sender; - private final SpongeWorldEdit plugin; + private final Audience sender; - public SpongeCommandSender(SpongeWorldEdit plugin, CommandSource sender) { - checkNotNull(plugin); + public SpongeCommandSender(Audience sender) { checkNotNull(sender); - checkArgument(!(sender instanceof Player), "Cannot wrap a player"); + checkArgument( + !(sender instanceof Player), + "Players should be wrapped using the specialized class" + ); - this.plugin = plugin; this.sender = sender; } @@ -68,42 +62,44 @@ public UUID getUniqueId() { @Override public String getName() { - return sender.getName(); + return "Console"; } - @SuppressWarnings("deprecation") @Override + @Deprecated public void printRaw(String msg) { for (String part : msg.split("\n")) { - sender.sendMessage(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(part)); + sender.sendMessage(net.kyori.adventure.text.Component.text(part)); } } @Override + @Deprecated public void print(String msg) { - sendColorized(msg, TextColors.LIGHT_PURPLE); + for (String part : msg.split("\n")) { + print(TextComponent.of(part, TextColor.LIGHT_PURPLE)); + } } @Override + @Deprecated public void printDebug(String msg) { - sendColorized(msg, TextColors.GRAY); + for (String part : msg.split("\n")) { + print(TextComponent.of(part, TextColor.GRAY)); + } } @Override + @Deprecated public void printError(String msg) { - sendColorized(msg, TextColors.RED); + for (String part : msg.split("\n")) { + print(TextComponent.of(part, TextColor.RED)); + } } @Override public void print(Component component) { - TextAdapter.sendMessage(sender, WorldEditText.format(component, getLocale())); - } - - @SuppressWarnings("deprecation") - private void sendColorized(String msg, TextColor formatting) { - for (String part : msg.split("\n")) { - sender.sendMessage(Text.of(formatting, TextSerializers.LEGACY_FORMATTING_CODE.deserialize(part))); - } + sender.sendMessage(SpongeTextAdapter.convert(component, getLocale())); } @Override @@ -122,7 +118,7 @@ public boolean hasPermission(String perm) { } @Override - public void checkPermission(String permission) throws AuthorizationException { + public void checkPermission(String permission) { } @Override @@ -152,20 +148,19 @@ public Locale getLocale() { @Override public SessionKey getSessionKey() { return new SessionKey() { - @Nullable @Override public String getName() { - return null; + return "Console"; } @Override public boolean isActive() { - return false; + return true; } @Override public boolean isPersistent() { - return false; + return true; } @Override diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeEntity.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeEntity.java index 532a366082..9902ebbfcc 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeEntity.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeEntity.java @@ -19,14 +19,17 @@ package com.sk89q.worldedit.sponge; -import com.flowpowered.math.vector.Vector3d; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.metadata.EntityProperties; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.sponge.internal.NbtAdapter; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.NullWorld; -import org.spongepowered.api.world.World; +import com.sk89q.worldedit.world.entity.EntityType; +import org.spongepowered.api.registry.RegistryTypes; +import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.math.vector.Vector3d; import java.lang.ref.WeakReference; import javax.annotation.Nullable; @@ -46,7 +49,14 @@ class SpongeEntity implements Entity { public BaseEntity getState() { org.spongepowered.api.entity.Entity entity = entityRef.get(); if (entity != null) { - return SpongeWorldEdit.inst().getAdapter().createBaseEntity(entity); + return new BaseEntity( + EntityType.REGISTRY.get( + entity.type().key(RegistryTypes.ENTITY_TYPE).asString() + ), + entity.toContainer().getView(Constants.Sponge.UNSAFE_NBT) + .map(NbtAdapter::adaptToWorldEdit) + .orElse(null) + ); } else { return null; } @@ -56,10 +66,10 @@ public BaseEntity getState() { public Location getLocation() { org.spongepowered.api.entity.Entity entity = entityRef.get(); if (entity != null) { - org.spongepowered.api.world.Location entityLoc = entity.getLocation(); - Vector3d entityRot = entity.getRotation(); + ServerLocation entityLoc = entity.serverLocation(); + Vector3d entityRot = entity.rotation(); - return SpongeWorldEdit.inst().getAdapter().adapt(entityLoc, entityRot); + return SpongeAdapter.adapt(entityLoc, entityRot); } else { return new Location(NullWorld.getInstance()); } @@ -79,7 +89,7 @@ public boolean setLocation(Location location) { public Extent getExtent() { org.spongepowered.api.entity.Entity entity = entityRef.get(); if (entity != null) { - return SpongeWorldEdit.inst().getAdapter().getWorld(entity.getWorld()); + return SpongeAdapter.adapt(entity.serverLocation().world()); } else { return NullWorld.getInstance(); } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeEntityProperties.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeEntityProperties.java index 7373ae642f..f7b0269a7f 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeEntityProperties.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeEntityProperties.java @@ -20,29 +20,27 @@ package com.sk89q.worldedit.sponge; import com.sk89q.worldedit.entity.metadata.EntityProperties; -import org.spongepowered.api.data.key.Keys; +import org.spongepowered.api.data.Keys; import org.spongepowered.api.entity.Entity; import org.spongepowered.api.entity.ExperienceOrb; import org.spongepowered.api.entity.FallingBlock; import org.spongepowered.api.entity.Item; -import org.spongepowered.api.entity.explosive.PrimedTNT; +import org.spongepowered.api.entity.explosive.fused.PrimedTNT; import org.spongepowered.api.entity.hanging.ItemFrame; import org.spongepowered.api.entity.hanging.Painting; import org.spongepowered.api.entity.living.Ambient; import org.spongepowered.api.entity.living.ArmorStand; +import org.spongepowered.api.entity.living.ComplexLivingPart; import org.spongepowered.api.entity.living.Humanoid; import org.spongepowered.api.entity.living.Living; -import org.spongepowered.api.entity.living.Villager; import org.spongepowered.api.entity.living.animal.Animal; -import org.spongepowered.api.entity.living.complex.ComplexLivingPart; +import org.spongepowered.api.entity.living.aquatic.Aquatic; import org.spongepowered.api.entity.living.golem.Golem; import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.entity.living.trader.Trader; import org.spongepowered.api.entity.projectile.Projectile; import org.spongepowered.api.entity.vehicle.Boat; import org.spongepowered.api.entity.vehicle.minecart.Minecart; -import org.spongepowered.api.text.Text; - -import java.util.Optional; import static com.google.common.base.Preconditions.checkNotNull; @@ -122,7 +120,7 @@ public boolean isAmbient() { @Override public boolean isNPC() { - return entity instanceof Villager; + return entity instanceof Trader; } @Override @@ -132,12 +130,12 @@ public boolean isGolem() { @Override public boolean isTamed() { - return entity.get(Keys.TAMED_OWNER).orElse(Optional.empty()).isPresent(); + return entity.get(Keys.IS_TAMED).orElse(false); } @Override public boolean isTagged() { - return !entity.get(Keys.DISPLAY_NAME).orElse(Text.EMPTY).isEmpty(); + return entity.get(Keys.CUSTOM_NAME).isPresent(); } @Override @@ -152,6 +150,6 @@ public boolean isPasteable() { @Override public boolean isWaterCreature() { - return false; // TODO api8 + return entity instanceof Aquatic; } } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeItemCategoryRegistry.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeItemCategoryRegistry.java new file mode 100644 index 0000000000..b417c34da2 --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeItemCategoryRegistry.java @@ -0,0 +1,44 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.registry.ItemCategoryRegistry; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.ItemTags; +import net.minecraft.tags.Tag; + +import java.util.Collections; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +public class SpongeItemCategoryRegistry implements ItemCategoryRegistry { + @Override + public Set getCategorisedByName(String category) { + return Optional.ofNullable(ItemTags.getAllTags().getTag(new ResourceLocation(category))) + .map(Tag::getValues) + .orElse(Collections.emptyList()) + .stream() + .map(b -> ItemType.REGISTRY.get(Registry.ITEM.getKey(b).toString())) + .collect(Collectors.toSet()); + } +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeItemRegistry.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeItemRegistry.java new file mode 100644 index 0000000000..d057e7bb22 --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeItemRegistry.java @@ -0,0 +1,47 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.registry.BundledItemRegistry; +import net.minecraft.world.item.ItemStack; +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.registry.RegistryTypes; + +public class SpongeItemRegistry extends BundledItemRegistry { + + @Override + public Component getRichName(ItemType itemType) { + return SpongeTextAdapter.convert(Sponge.game().registries().registry(RegistryTypes.ITEM_TYPE) + .value(ResourceKey.resolve(itemType.getId())).asComponent()); + } + + @Override + public Component getRichName(BaseItemStack itemStack) { + return TranslatableComponent.of( + ((ItemStack) (Object) SpongeAdapter.adapt(itemStack)).getDescriptionId() + ); + } + +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePermissionsProvider.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePermissionsProvider.java index 0e8fc89c94..da99c0eca6 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePermissionsProvider.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePermissionsProvider.java @@ -20,28 +20,28 @@ package com.sk89q.worldedit.sponge; import org.spongepowered.api.Sponge; -import org.spongepowered.api.command.CommandCallable; -import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; import org.spongepowered.api.service.permission.PermissionDescription; import org.spongepowered.api.service.permission.PermissionService; import org.spongepowered.api.service.permission.SubjectReference; public class SpongePermissionsProvider { - public boolean hasPermission(Player player, String permission) { + public boolean hasPermission(ServerPlayer player, String permission) { return player.hasPermission(permission); } - public void registerPermission(CommandCallable command, String permission) { - Sponge.getGame().getServiceManager().getRegistration(PermissionService.class).ifPresent((permissionService -> { - PermissionDescription.Builder permissionBuilder = permissionService.getProvider().newDescriptionBuilder(SpongeWorldEdit.inst()); + public void registerPermission(String permission) { + Sponge.game().serviceProvider().registration(PermissionService.class).ifPresent((permissionService -> { + PermissionDescription.Builder permissionBuilder = permissionService.service() + .newDescriptionBuilder(SpongeWorldEdit.inst().getPluginContainer()); permissionBuilder.id(permission).register(); })); } - public String[] getGroups(Player player) { - return player.getParents().stream() - .map(SubjectReference::getSubjectIdentifier) - .toArray(String[]::new); + public String[] getGroups(ServerPlayer player) { + return player.parents().stream() + .map(SubjectReference::subjectIdentifier) + .toArray(String[]::new); } } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java index 804c2def4c..9358c847e1 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java @@ -19,31 +19,25 @@ package com.sk89q.worldedit.sponge; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.event.platform.CommandEvent; -import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; import com.sk89q.worldedit.extension.platform.AbstractPlatform; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.MultiUserPlatform; import com.sk89q.worldedit.extension.platform.Preference; -import com.sk89q.worldedit.internal.command.CommandUtil; import com.sk89q.worldedit.sponge.config.SpongeConfiguration; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.registry.Registries; -import org.enginehub.piston.Command; import org.enginehub.piston.CommandManager; +import org.spongepowered.api.ResourceKey; import org.spongepowered.api.Sponge; -import org.spongepowered.api.command.CommandException; -import org.spongepowered.api.command.CommandResult; -import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.entity.EntityType; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; +import org.spongepowered.api.registry.RegistryTypes; import org.spongepowered.api.scheduler.Task; -import org.spongepowered.api.world.Location; +import org.spongepowered.api.util.Ticks; +import org.spongepowered.api.world.server.ServerWorld; import java.util.ArrayList; import java.util.Collection; @@ -76,13 +70,13 @@ public Registries getRegistries() { @Override public int getDataVersion() { - // TODO add to adapter - org.spongepowered.common.data.util.DataUtil#MINECRAFT_DATA_VERSION - return 1631; + return Sponge.platform().minecraftVersion().dataVersion().orElse(-1); } @Override public boolean isValidMobType(String type) { - return Sponge.getRegistry().getType(EntityType.class, type).isPresent(); + return Sponge.game().registries().registry(RegistryTypes.ENTITY_TYPE) + .findValue(ResourceKey.resolve(type)).isPresent(); } @Override @@ -93,16 +87,21 @@ public void reload() { @Override public int schedule(long delay, long period, Runnable task) { - Task.builder().delayTicks(delay).intervalTicks(period).execute(task).submit(SpongeWorldEdit.inst()); - return 0; // TODO This isn't right, but we only check for -1 values + Task t = Task.builder() + .delay(Ticks.of(delay)) + .interval(Ticks.of(period)) + .execute(task) + .plugin(SpongeWorldEdit.inst().getPluginContainer()) + .build(); + return Math.abs(t.name().hashCode()); // TODO This isn't right, but we only check for -1 values } @Override public List getWorlds() { - Collection worlds = Sponge.getServer().getWorlds(); + Collection worlds = Sponge.server().worldManager().worlds(); List ret = new ArrayList<>(worlds.size()); - for (org.spongepowered.api.world.World world : worlds) { - ret.add(SpongeWorldEdit.inst().getAdapter().getWorld(world)); + for (ServerWorld world : worlds) { + ret.add(SpongeAdapter.adapt(world)); } return ret; } @@ -113,8 +112,8 @@ public Player matchPlayer(Player player) { if (player instanceof SpongePlayer) { return player; } else { - Optional optPlayer = Sponge.getServer().getPlayer(player.getUniqueId()); - return optPlayer.map(player1 -> new SpongePlayer(this, player1)).orElse(null); + Optional optPlayer = Sponge.server().player(player.getUniqueId()); + return optPlayer.map(SpongePlayer::new).orElse(null); } } @@ -124,9 +123,10 @@ public World matchWorld(World world) { if (world instanceof SpongeWorld) { return world; } else { - for (org.spongepowered.api.world.World ws : Sponge.getServer().getWorlds()) { - if (ws.getName().equals(world.getName())) { - return SpongeWorldEdit.inst().getAdapter().getWorld(ws); + // TODO this needs fixing for world name shenanigans + for (ServerWorld spongeWorld : Sponge.server().worldManager().worlds()) { + if (spongeWorld.key().toString().equals(world.getName())) { + return SpongeAdapter.adapt(spongeWorld); } } @@ -136,26 +136,6 @@ public World matchWorld(World world) { @Override public void registerCommands(CommandManager manager) { - for (Command command : manager.getAllCommands().collect(toList())) { - CommandAdapter adapter = new CommandAdapter(command) { - @Override - public CommandResult process(CommandSource source, String arguments) throws org.spongepowered.api.command.CommandException { - CommandEvent weEvent = new CommandEvent(SpongeWorldEdit.inst().wrapCommandSource(source), command.getName() + " " + arguments); - WorldEdit.getInstance().getEventBus().post(weEvent); - return weEvent.isCancelled() ? CommandResult.success() : CommandResult.empty(); - } - - @Override - public List getSuggestions(CommandSource source, String arguments, @Nullable Location targetPosition) throws CommandException { - CommandSuggestionEvent weEvent = new CommandSuggestionEvent(SpongeWorldEdit.inst().wrapCommandSource(source), command.getName() + " " + arguments); - WorldEdit.getInstance().getEventBus().post(weEvent); - return CommandUtil.fixSuggestions(arguments, weEvent.getSuggestions()); - } - }; - ImmutableList.Builder aliases = ImmutableList.builder(); - aliases.add(command.getName()).addAll(command.getAliases()); - Sponge.getCommandManager().register(SpongeWorldEdit.inst(), adapter, aliases.build()); - } } @Override @@ -197,15 +177,14 @@ public Map getCapabilities() { @Override public Set getSupportedSideEffects() { - return ImmutableSet.of(); + return ImmutableSet.of( + SideEffect.UPDATE, SideEffect.ENTITY_AI, SideEffect.LIGHTING, SideEffect.NEIGHBORS, + SideEffect.VALIDATION + ); } @Override public Collection getConnectedUsers() { - List users = new ArrayList<>(); - for (org.spongepowered.api.entity.living.player.Player player : Sponge.getServer().getOnlinePlayers()) { - users.add(new SpongePlayer(this, player)); - } - return users; + return Sponge.server().onlinePlayers().stream().map(SpongePlayer::new).collect(toList()); } } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java index f0f814d74f..d370199272 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java @@ -19,7 +19,7 @@ package com.sk89q.worldedit.sponge; -import com.flowpowered.math.vector.Vector3d; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.util.StringUtil; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.entity.BaseEntity; @@ -29,63 +29,68 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.session.SessionKey; +import com.sk89q.worldedit.sponge.internal.NbtAdapter; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.formatting.WorldEditText; import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.adapter.spongeapi.TextAdapter; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.gamemode.GameMode; import com.sk89q.worldedit.world.gamemode.GameModes; -import com.sk89q.worldedit.world.item.ItemTypes; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextColor; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import net.minecraft.core.BlockPos; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import org.spongepowered.api.ResourceKey; import org.spongepowered.api.Sponge; -import org.spongepowered.api.data.key.Keys; +import org.spongepowered.api.data.Keys; import org.spongepowered.api.data.type.HandTypes; import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.item.ItemType; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; import org.spongepowered.api.item.inventory.ItemStack; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.text.format.TextColor; -import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.text.serializer.TextSerializers; -import org.spongepowered.api.world.World; +import org.spongepowered.api.registry.RegistryTypes; +import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.math.vector.Vector3d; import java.nio.charset.StandardCharsets; import java.util.Locale; -import java.util.Optional; import java.util.UUID; import javax.annotation.Nullable; public class SpongePlayer extends AbstractPlayerActor { + private static final int STRUCTURE_BLOCK_PACKET_ID = 7; - private final Player player; + private final ServerPlayer player; - protected SpongePlayer(SpongePlatform platform, Player player) { + protected SpongePlayer(ServerPlayer player) { this.player = player; ThreadSafeCache.getInstance().getOnlineIds().add(getUniqueId()); } @Override public UUID getUniqueId() { - return player.getUniqueId(); + return player.uniqueId(); } @Override public BaseItemStack getItemInHand(HandSide handSide) { - Optional is = this.player.getItemInHand(handSide == HandSide.MAIN_HAND - ? HandTypes.MAIN_HAND : HandTypes.OFF_HAND); - return is.map(itemStack -> new BaseItemStack(ItemTypes.get(itemStack.getType().getId()))).orElse(null); + ItemStack is = this.player.itemInHand( + handSide == HandSide.MAIN_HAND ? HandTypes.MAIN_HAND : HandTypes.OFF_HAND + ); + return SpongeAdapter.adapt(is); } @Override public String getName() { - return this.player.getName(); + return this.player.name(); } @SuppressWarnings("deprecation") @Override public String getDisplayName() { - return player.getDisplayNameData().displayName().getDirect().map(TextSerializers.LEGACY_FORMATTING_CODE::serialize).orElse(getName()); + return LegacyComponentSerializer.legacySection().serialize(player.displayName().get()); } @Override @@ -95,10 +100,10 @@ public BaseEntity getState() { @Override public Location getLocation() { - org.spongepowered.api.world.Location entityLoc = this.player.getLocation(); - Vector3d entityRot = this.player.getRotation(); + ServerLocation entityLoc = this.player.serverLocation(); + Vector3d entityRot = this.player.rotation(); - return SpongeWorldEdit.inst().getAdapter().adapt(entityLoc, entityRot); + return SpongeAdapter.adapt(entityLoc, entityRot); } @Override @@ -108,15 +113,12 @@ public boolean setLocation(Location location) { @Override public com.sk89q.worldedit.world.World getWorld() { - return SpongeWorldEdit.inst().getAdapter().getWorld(player.getWorld()); + return SpongeAdapter.adapt(player.serverLocation().world()); } @Override public void giveItem(BaseItemStack itemStack) { - this.player.getInventory().offer( - ItemStack.of(Sponge.getGame().getRegistry().getType(ItemType.class, itemStack.getType().getId()).get(), - itemStack.getAmount()) - ); + this.player.inventory().offer(SpongeAdapter.adapt(itemStack)); } @Override @@ -128,46 +130,55 @@ public void dispatchCUIEvent(CUIEvent event) { } String finalData = send; - CUIChannelHandler.getActiveChannel().sendTo(player, buffer -> buffer.writeBytes(finalData.getBytes(StandardCharsets.UTF_8))); + CUIChannelHandler.channel().play().sendTo( + player, + buffer -> buffer.writeBytes(finalData.getBytes(StandardCharsets.UTF_8)) + ); } @Override + @Deprecated public void printRaw(String msg) { for (String part : msg.split("\n")) { - this.player.sendMessage(TextSerializers.FORMATTING_CODE.deserialize(part)); + this.player.sendMessage(LegacyComponentSerializer.legacySection().deserialize(part)); } } @Override + @Deprecated public void printDebug(String msg) { - sendColorized(msg, TextColors.GRAY); + sendColorized(msg, NamedTextColor.GRAY); } @Override + @Deprecated public void print(String msg) { - sendColorized(msg, TextColors.LIGHT_PURPLE); + sendColorized(msg, NamedTextColor.LIGHT_PURPLE); } @Override + @Deprecated public void printError(String msg) { - sendColorized(msg, TextColors.RED); + sendColorized(msg, NamedTextColor.RED); } @Override public void print(Component component) { - TextAdapter.sendMessage(player, WorldEditText.format(component, getLocale())); + player.sendMessage(SpongeTextAdapter.convert(component, getLocale())); } private void sendColorized(String msg, TextColor formatting) { for (String part : msg.split("\n")) { - this.player.sendMessage(Text.of(formatting, TextSerializers.FORMATTING_CODE.deserialize(part))); + this.player.sendMessage( + LegacyComponentSerializer.legacySection().deserialize(part).color(formatting) + ); } } @Override public boolean trySetPosition(Vector3 pos, float pitch, float yaw) { - org.spongepowered.api.world.Location loc = new org.spongepowered.api.world.Location<>( - this.player.getWorld(), pos.getX(), pos.getY(), pos.getZ() + ServerLocation loc = ServerLocation.of( + this.player.world(), pos.getX(), pos.getY(), pos.getZ() ); return this.player.setLocationAndRotation(loc, new Vector3d(pitch, yaw, 0)); @@ -196,13 +207,16 @@ public T getFacet(Class cls) { @Override public GameMode getGameMode() { - return GameModes.get(player.getGameModeData().type().get().getId()); + return GameModes.get(player.gameMode().get().key(RegistryTypes.GAME_MODE).asString()); } @Override public void setGameMode(GameMode gameMode) { - player.getGameModeData().type().set(Sponge.getRegistry().getType(org.spongepowered.api.entity.living.player.gamemode.GameMode.class, - gameMode.getId()).get()); + player.gameMode().set( + Sponge.game().registries().registry(RegistryTypes.GAME_MODE).value( + ResourceKey.resolve(gameMode.getId()) + ) + ); } @Override @@ -217,24 +231,34 @@ public void setFlying(boolean flying) { @Override public > void sendFakeBlock(BlockVector3 pos, B block) { - org.spongepowered.api.world.Location loc = player.getWorld().getLocation(pos.getX(), pos.getY(), pos.getZ()); if (block == null) { - player.sendBlockChange(loc.getBlockPosition(), loc.getBlock()); + player.resetBlockChange(pos.getX(), pos.getY(), pos.getZ()); } else { - // TODO - // player.sendBlockChange(loc, BukkitAdapter.adapt(block)); - // if (block instanceof BaseBlock && ((BaseBlock) block).hasNbtData()) { - // BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); - // if (adapter != null) { - // adapter.sendFakeNBT(player, pos, ((BaseBlock) block).getNbtData()); - // } - // } + net.minecraft.server.level.ServerPlayer mcPlayer = + ((net.minecraft.server.level.ServerPlayer) player); + final ClientboundBlockUpdatePacket packetOut = new ClientboundBlockUpdatePacket( + new BlockPos(pos.getX(), pos.getY(), pos.getZ()), + (net.minecraft.world.level.block.state.BlockState) + SpongeAdapter.adapt(block.toImmutableState()) + ); + mcPlayer.connection.send(packetOut); + if (block instanceof BaseBlock && block.getBlockType().equals(com.sk89q.worldedit.world.block.BlockTypes.STRUCTURE_BLOCK)) { + final BaseBlock baseBlock = (BaseBlock) block; + final CompoundTag nbtData = baseBlock.getNbtData(); + if (nbtData != null) { + mcPlayer.connection.send(new ClientboundBlockEntityDataPacket( + new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()), + STRUCTURE_BLOCK_PACKET_ID, + NbtAdapter.adaptNMSToWorldEdit(nbtData)) + ); + } + } } } @Override public Locale getLocale() { - return player.getLocale(); + return player.locale(); } @Override @@ -249,8 +273,8 @@ static class SessionKeyImpl implements SessionKey { private final String name; SessionKeyImpl(Player player) { - this.uuid = player.getUniqueId(); - this.name = player.getName(); + this.uuid = player.uniqueId(); + this.name = player.name(); } @Override diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeRegistries.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeRegistries.java index 47b83250e2..04baa39365 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeRegistries.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeRegistries.java @@ -20,7 +20,11 @@ package com.sk89q.worldedit.sponge; import com.sk89q.worldedit.world.registry.BiomeRegistry; +import com.sk89q.worldedit.world.registry.BlockCategoryRegistry; +import com.sk89q.worldedit.world.registry.BlockRegistry; import com.sk89q.worldedit.world.registry.BundledRegistries; +import com.sk89q.worldedit.world.registry.ItemCategoryRegistry; +import com.sk89q.worldedit.world.registry.ItemRegistry; /** * World data for the Sponge platform. @@ -28,20 +32,39 @@ class SpongeRegistries extends BundledRegistries { private static final SpongeRegistries INSTANCE = new SpongeRegistries(); + + public static SpongeRegistries getInstance() { + return INSTANCE; + } + private final BiomeRegistry biomeRegistry = new SpongeBiomeRegistry(); + private final BlockRegistry blockRegistry = new SpongeBlockRegistry(); + private final BlockCategoryRegistry blockCategoryRegistry = new SpongeBlockCategoryRegistry(); + private final ItemRegistry itemRegistry = new SpongeItemRegistry(); + private final ItemCategoryRegistry itemCategoryRegistry = new SpongeItemCategoryRegistry(); @Override public BiomeRegistry getBiomeRegistry() { return biomeRegistry; } - /** - * Get a static instance. - * - * @return an instance - */ - public static SpongeRegistries getInstance() { - return INSTANCE; + @Override + public BlockRegistry getBlockRegistry() { + return blockRegistry; } + @Override + public BlockCategoryRegistry getBlockCategoryRegistry() { + return blockCategoryRegistry; + } + + @Override + public ItemRegistry getItemRegistry() { + return itemRegistry; + } + + @Override + public ItemCategoryRegistry getItemCategoryRegistry() { + return itemCategoryRegistry; + } } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeTextAdapter.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeTextAdapter.java index 1731f98d13..7709737e43 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeTextAdapter.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeTextAdapter.java @@ -22,16 +22,22 @@ import com.sk89q.worldedit.util.formatting.WorldEditText; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.serializer.gson.GsonComponentSerializer; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.text.serializer.TextSerializers; import java.util.Locale; public class SpongeTextAdapter { - public static Text convert(Component component, Locale locale) { + public static net.kyori.adventure.text.Component convert(Component component, Locale locale) { component = WorldEditText.format(component, locale); - return TextSerializers.JSON.deserialize(GsonComponentSerializer.INSTANCE.serialize(component)); + return net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson() + .deserialize(GsonComponentSerializer.INSTANCE.serialize(component)); + } + + public static Component convert(net.kyori.adventure.text.Component component) { + return GsonComponentSerializer.INSTANCE.deserialize( + net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson() + .serialize(component) + ); } private SpongeTextAdapter() { diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java index c37535160c..ec7d617bf6 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java @@ -19,8 +19,8 @@ package com.sk89q.worldedit.sponge; -import com.flowpowered.math.vector.Vector3d; -import com.flowpowered.math.vector.Vector3i; +import com.google.common.collect.Sets; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItemStack; @@ -30,39 +30,49 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.sponge.internal.NbtAdapter; +import com.sk89q.worldedit.sponge.internal.SpongeWorldNativeAccess; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.world.AbstractWorld; import com.sk89q.worldedit.world.RegenOptions; -import com.sk89q.worldedit.world.WorldUnloadedException; 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 com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.weather.WeatherType; import com.sk89q.worldedit.world.weather.WeatherTypes; +import net.minecraft.core.BlockPos; +import net.minecraft.data.worldgen.Features; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import org.spongepowered.api.ResourceKey; import org.spongepowered.api.Sponge; -import org.spongepowered.api.block.BlockSnapshot; -import org.spongepowered.api.block.BlockState; -import org.spongepowered.api.block.BlockType; -import org.spongepowered.api.block.BlockTypes; -import org.spongepowered.api.block.tileentity.TileEntity; -import org.spongepowered.api.data.key.Keys; -import org.spongepowered.api.data.property.block.GroundLuminanceProperty; -import org.spongepowered.api.data.property.block.SkyLuminanceProperty; +import org.spongepowered.api.data.persistence.DataContainer; +import org.spongepowered.api.data.persistence.DataView; import org.spongepowered.api.entity.EntityType; import org.spongepowered.api.entity.EntityTypes; -import org.spongepowered.api.world.BlockChangeFlags; -import org.spongepowered.api.world.World; -import org.spongepowered.api.world.weather.Weather; +import org.spongepowered.api.entity.Item; +import org.spongepowered.api.registry.RegistryTypes; +import org.spongepowered.api.util.Ticks; +import org.spongepowered.api.world.LightTypes; +import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.api.world.server.ServerWorld; +import org.spongepowered.api.world.volume.stream.StreamOptions; +import org.spongepowered.math.vector.Vector3d; +import org.spongepowered.math.vector.Vector3i; import java.lang.ref.WeakReference; import java.nio.file.Path; -import java.util.ArrayList; import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Optional; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.Collectors; import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkNotNull; @@ -70,43 +80,33 @@ /** * An adapter to Minecraft worlds for WorldEdit. */ -public abstract class SpongeWorld extends AbstractWorld { +public final class SpongeWorld extends AbstractWorld { - private final WeakReference worldRef; + private static final Random random = new Random(); + + private final WeakReference worldRef; + private final SpongeWorldNativeAccess worldNativeAccess; /** * Construct a new world. * * @param world the world */ - protected SpongeWorld(World world) { + protected SpongeWorld(ServerWorld world) { checkNotNull(world); this.worldRef = new WeakReference<>(world); + this.worldNativeAccess = new SpongeWorldNativeAccess(new WeakReference<>((ServerLevel) world)); } /** * Get the underlying handle to the world. * * @return the world - * @throws WorldEditException thrown if a reference to the world was lost (i.e. world was unloaded) + * @throws RuntimeException thrown if a reference to the world was lost (i.e. world was + * unloaded) */ - public World getWorldChecked() throws WorldEditException { - World world = worldRef.get(); - if (world != null) { - return world; - } else { - throw new WorldUnloadedException(); - } - } - - /** - * Get the underlying handle to the world. - * - * @return the world - * @throws RuntimeException thrown if a reference to the world was lost (i.e. world was unloaded) - */ - public World getWorld() { - World world = worldRef.get(); + ServerWorld getWorld() { + ServerWorld world = worldRef.get(); if (world != null) { return world; } else { @@ -114,101 +114,151 @@ public World getWorld() { } } + // This is sus but leaving it for later world name/id reworks @Override public String getName() { - return getWorld().getName(); + return getWorld().key().asString(); } @Override public String getId() { - return getName().replace(" ", "_").toLowerCase(Locale.ROOT) - + getWorld().getDimension().getType().getName().toLowerCase(Locale.ROOT); + return getWorld().key().asString(); } @Override public Path getStoragePath() { - return getWorld().getDirectory(); + return getWorld().directory(); } - @SuppressWarnings("WeakerAccess") - protected BlockState getBlockState(BlockStateHolder block) { - if (block instanceof com.sk89q.worldedit.world.block.BlockState) { - BlockState state = Sponge.getRegistry().getType(BlockType.class, block.getBlockType().getId()).orElse(BlockTypes.AIR).getDefaultState(); - for (Map.Entry, Object> entry : block.getStates().entrySet()) { - // TODO Convert across states - } - return state; - } else { - throw new UnsupportedOperationException("Missing Sponge adapter for WorldEdit!"); - } + @Override + public BlockState getBlock(BlockVector3 position) { + return SpongeAdapter.adapt(getWorld().block( + position.getX(), position.getY(), position.getZ() + )); } - @SuppressWarnings("WeakerAccess") - protected abstract void applyTileEntityData(TileEntity entity, BaseBlock block); - - private static final BlockSnapshot.Builder builder = BlockSnapshot.builder(); + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + CompoundTag entity = getWorld() + .blockEntity(position.getX(), position.getY(), position.getZ()) + .map(e -> NbtAdapter.adaptToWorldEdit(e.createArchetype().blockEntityData())) + .orElse(null); + return getBlock(position).toBaseBlock(entity); + } @Override - public > boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException { + public > boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException { checkNotNull(position); checkNotNull(block); - World world = getWorldChecked(); - - // First set the block - Vector3i pos = new Vector3i(position.getX(), position.getY(), position.getZ()); - BlockState newState = getBlockState(block); + // Switch back to https://gist.github.com/octylFractal/d1fd5b46574b43e13bb4eb673e53deda + // When applySideEffects can be implemented in API and we don't need WNA! + return worldNativeAccess.setBlock(position, block, sideEffects); + } - BlockSnapshot snapshot = builder.reset() - .blockState(newState) - .position(pos) - .world(world.getProperties()) - .build(); + @Override + public Set applySideEffects(BlockVector3 position, com.sk89q.worldedit.world.block.BlockState previousType, SideEffectSet sideEffectSet) throws WorldEditException { + checkNotNull(position); - snapshot.restore(true, notifyAndLight ? BlockChangeFlags.ALL : BlockChangeFlags.NONE); + worldNativeAccess.applySideEffects(position, previousType, sideEffectSet); - // Create the TileEntity - if (block instanceof BaseBlock && ((BaseBlock) block).hasNbtData()) { - // Kill the old TileEntity - world.getTileEntity(pos).ifPresent(tileEntity -> applyTileEntityData(tileEntity, (BaseBlock) block)); - } + return Sets.intersection( + SpongeWorldEdit.inst().getInternalPlatform().getSupportedSideEffects(), + sideEffectSet.getSideEffectsToApply() + ); + } + @Override + public boolean clearContainerBlockContents(BlockVector3 position) { + getWorld().removeBlockEntity(position.getX(), position.getY(), position.getZ()); return true; } @Override - public boolean notifyAndLightBlock(BlockVector3 position, com.sk89q.worldedit.world.block.BlockState previousType) throws WorldEditException { - // TODO Move this to adapter + public boolean regenerate(Region region, Extent extent, RegenOptions options) { + // TODO get sponge team to implement this for us return false; } + + @Nullable + private static ConfiguredFeature createTreeFeatureGenerator(TreeGenerator.TreeType type) { + switch (type) { + // Based off of the SaplingGenerator class, as well as uses of DefaultBiomeFeatures fields + case TREE: + return Features.OAK; + case BIG_TREE: + return Features.FANCY_OAK; + case REDWOOD: + return Features.SPRUCE; + case TALL_REDWOOD: + return Features.MEGA_SPRUCE; + case MEGA_REDWOOD: + return Features.MEGA_PINE; + case BIRCH: + return Features.BIRCH; + case JUNGLE: + return Features.MEGA_JUNGLE_TREE; + case SMALL_JUNGLE: + return Features.JUNGLE_TREE; + case SHORT_JUNGLE: + return Features.JUNGLE_TREE_NO_VINE; + case JUNGLE_BUSH: + return Features.JUNGLE_BUSH; + case SWAMP: + return Features.SWAMP_TREE; + case ACACIA: + return Features.ACACIA; + case DARK_OAK: + return Features.DARK_OAK; + case TALL_BIRCH: + return Features.BIRCH_TALL; + case RED_MUSHROOM: + return Features.HUGE_RED_MUSHROOM; + case BROWN_MUSHROOM: + return Features.HUGE_BROWN_MUSHROOM; + case WARPED_FUNGUS: + return Features.WARPED_FUNGI; + case CRIMSON_FUNGUS: + return Features.CRIMSON_FUNGI; + case CHORUS_PLANT: + return Features.CHORUS_PLANT; + case RANDOM: + return createTreeFeatureGenerator(TreeGenerator.TreeType.values()[ThreadLocalRandom.current().nextInt(TreeGenerator.TreeType.values().length)]); + default: + return null; + } + } + @Override - public boolean regenerate(Region region, Extent extent, RegenOptions options) { - return false; + public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 position) { + ConfiguredFeature generator = createTreeFeatureGenerator(type); + ServerLevel world = (ServerLevel) getWorld(); + return generator != null && generator.place( + world, world.getChunkSource().getGenerator(), random, + new BlockPos(position.getX(), position.getY(), position.getZ()) + ); } @Override public int getBlockLightLevel(BlockVector3 position) { checkNotNull(position); - BlockState state = getWorld().getBlock(new Vector3i(position.getX(), position.getY(), position.getZ())); - - Optional groundLuminanceProperty = state.getProperty(GroundLuminanceProperty.class); - Optional skyLuminanceProperty = state.getProperty(SkyLuminanceProperty.class); - - if (!groundLuminanceProperty.isPresent() || !skyLuminanceProperty.isPresent()) { - return 0; - } + int skyLight = getWorld().light(LightTypes.SKY, position.getX(), position.getY(), position.getZ()); + int groundLight = getWorld().light(LightTypes.BLOCK, position.getX(), position.getY(), position.getZ()); - //noinspection ConstantConditions - return (int) Math.max(groundLuminanceProperty.get().getValue(), skyLuminanceProperty.get().getValue()); + return Math.max(skyLight, groundLight); } @Override public BiomeType getBiome(BlockVector3 position) { checkNotNull(position); - return SpongeAdapter.adapt(getWorld().getBiome(position.getBlockX(), position.getBlockY(), position.getBlockZ())); + return BiomeType.REGISTRY.get( + getWorld().registries().registry(RegistryTypes.BIOME) + .valueKey(getWorld().biome(position.getBlockX(), position.getBlockY(), position.getBlockZ())) + .asString() + ); } @Override @@ -216,7 +266,12 @@ public boolean setBiome(BlockVector3 position, BiomeType biome) { checkNotNull(position); checkNotNull(biome); - getWorld().setBiome(position.getBlockX(), position.getY(), position.getBlockZ(), SpongeAdapter.adapt(biome)); + getWorld().setBiome( + position.getBlockX(), position.getY(), position.getBlockZ(), + getWorld().registries().registry(RegistryTypes.BIOME).value( + ResourceKey.resolve(biome.getId()) + ) + ); return true; } @@ -229,24 +284,32 @@ public void dropItem(Vector3 position, BaseItemStack item) { return; } - org.spongepowered.api.entity.Entity entity = getWorld().createEntity( - EntityTypes.ITEM, - new Vector3d(position.getX(), position.getY(), position.getZ()) + Item itemEntity = getWorld().createEntity( + EntityTypes.ITEM, + new Vector3d(position.getX(), position.getY(), position.getZ()) ); - entity.offer(Keys.REPRESENTED_ITEM, SpongeWorldEdit.toSpongeItemStack(item).createSnapshot()); - getWorld().spawnEntity(entity); + itemEntity.item().set( + SpongeAdapter.adapt(item).createSnapshot() + ); + getWorld().spawnEntity(itemEntity); } @Override public void simulateBlockMine(BlockVector3 position) { - // TODO + getWorld().destroyBlock( + new Vector3i(position.getX(), position.getY(), position.getZ()), + true + ); } @Override public boolean canPlaceAt(BlockVector3 position, com.sk89q.worldedit.world.block.BlockState blockState) { - // TODO - return true; + return ((net.minecraft.world.level.block.state.BlockState) SpongeAdapter.adapt(blockState)) + .canSurvive( + ((LevelReader) getWorld()), + new BlockPos(position.getX(), position.getY(), position.getZ()) + ); } @Override @@ -260,57 +323,60 @@ public boolean equals(Object o) { return false; } else if ((o instanceof SpongeWorld)) { SpongeWorld other = ((SpongeWorld) o); - World otherWorld = other.worldRef.get(); - World thisWorld = worldRef.get(); + ServerWorld otherWorld = other.worldRef.get(); + ServerWorld thisWorld = worldRef.get(); return otherWorld != null && otherWorld.equals(thisWorld); } else { return o instanceof com.sk89q.worldedit.world.World - && ((com.sk89q.worldedit.world.World) o).getName().equals(getName()); + && ((com.sk89q.worldedit.world.World) o).getName().equals(getName()); } } @Override public List getEntities(Region region) { - List entities = new ArrayList<>(); - for (org.spongepowered.api.entity.Entity entity : getWorld().getEntities()) { - org.spongepowered.api.world.Location loc = entity.getLocation(); - if (region.contains(BlockVector3.at(loc.getX(), loc.getY(), loc.getZ()))) { - entities.add(new SpongeEntity(entity)); - } - } - return entities; + return getWorld() + .entityStream( + SpongeAdapter.adaptVector3i(region.getMinimumPoint()), + SpongeAdapter.adaptVector3i(region.getMaximumPoint()), + // We don't need to force load or clone to copy entities + StreamOptions.builder() + .setCarbonCopy(false) + .setLoadingStyle(StreamOptions.LoadingStyle.NONE) + .build() + ) + .toStream() + .map(ve -> new SpongeEntity(ve.type())) + .collect(Collectors.toList()); } @Override public List getEntities() { - List entities = new ArrayList<>(); - for (org.spongepowered.api.entity.Entity entity : getWorld().getEntities()) { - entities.add(new SpongeEntity(entity)); - } - return entities; + return getWorld().entities().stream() + .map(SpongeEntity::new) + .collect(Collectors.toList()); } - protected abstract void applyEntityData(org.spongepowered.api.entity.Entity entity, BaseEntity data); - @Nullable @Override public Entity createEntity(Location location, BaseEntity entity) { - World world = getWorld(); + ServerWorld world = getWorld(); - EntityType entityType = Sponge.getRegistry().getType(EntityType.class, entity.getType().getId()).get(); + EntityType entityType = Sponge.game().registries().registry(RegistryTypes.ENTITY_TYPE) + .value(ResourceKey.resolve(entity.getType().getId())); Vector3d pos = new Vector3d(location.getX(), location.getY(), location.getZ()); org.spongepowered.api.entity.Entity newEnt = world.createEntity(entityType, pos); if (entity.hasNbtData()) { - applyEntityData(newEnt, entity); + newEnt.setRawData(DataContainer.createNew(DataView.SafetyMode.NO_DATA_CLONED) + .set(Constants.Sponge.UNSAFE_NBT, entity.getNbtData())); } // Overwrite any data set by the NBT application Vector3 dir = location.getDirection(); newEnt.setLocationAndRotation( - new org.spongepowered.api.world.Location<>(getWorld(), pos), - new Vector3d(dir.getX(), dir.getY(), dir.getZ()) + ServerLocation.of(getWorld(), pos), + new Vector3d(dir.getX(), dir.getY(), dir.getZ()) ); if (world.spawnEntity(newEnt)) { @@ -322,27 +388,38 @@ public Entity createEntity(Location location, BaseEntity entity) { @Override public WeatherType getWeather() { - return WeatherTypes.get(getWorld().getWeather().getId()); + return WeatherTypes.get( + getWorld().weather().type().key(RegistryTypes.WEATHER_TYPE).asString() + ); } @Override public long getRemainingWeatherDuration() { - return getWorld().getRemainingDuration(); + return getWorld().weather().remainingDuration().ticks(); } @Override public void setWeather(WeatherType weatherType) { - getWorld().setWeather(Sponge.getRegistry().getType(Weather.class, weatherType.getId()).get()); + getWorld().setWeather( + Sponge.game().registries().registry(RegistryTypes.WEATHER_TYPE).value( + ResourceKey.resolve(weatherType.getId()) + ) + ); } @Override public void setWeather(WeatherType weatherType, long duration) { - getWorld().setWeather(Sponge.getRegistry().getType(Weather.class, weatherType.getId()).get(), duration); + getWorld().setWeather( + Sponge.game().registries().registry(RegistryTypes.WEATHER_TYPE).value( + ResourceKey.resolve(weatherType.getId()) + ), + Ticks.of(duration) + ); } @Override public BlockVector3 getSpawnPosition() { - return SpongeAdapter.asBlockVector(getWorld().getSpawnLocation()); + return SpongeAdapter.adaptVector3i(getWorld().properties().spawnPosition()); } } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java index c9b218a4d6..05e59719b7 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java @@ -20,226 +20,268 @@ package com.sk89q.worldedit.sponge; import com.google.inject.Inject; -import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.command.util.PermissionCondition; +import com.sk89q.worldedit.event.platform.CommandEvent; +import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; import com.sk89q.worldedit.event.platform.PlatformReadyEvent; +import com.sk89q.worldedit.event.platform.PlatformUnreadyEvent; +import com.sk89q.worldedit.event.platform.PlatformsRegisteredEvent; import com.sk89q.worldedit.event.platform.SessionIdleEvent; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extension.platform.PlatformManager; import com.sk89q.worldedit.internal.anvil.ChunkDeleter; -import com.sk89q.worldedit.sponge.adapter.AdapterLoadException; -import com.sk89q.worldedit.sponge.adapter.SpongeImplAdapter; -import com.sk89q.worldedit.sponge.adapter.SpongeImplLoader; +import com.sk89q.worldedit.internal.command.CommandUtil; import com.sk89q.worldedit.sponge.config.SpongeConfiguration; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockCategory; +import com.sk89q.worldedit.world.item.ItemCategory; +import net.kyori.adventure.audience.Audience; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.BlockTags; +import net.minecraft.tags.ItemTags; import org.apache.logging.log4j.Logger; -import org.bstats.sponge.Metrics2; +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.Server; import org.spongepowered.api.Sponge; import org.spongepowered.api.block.BlockSnapshot; import org.spongepowered.api.block.BlockType; import org.spongepowered.api.block.BlockTypes; -import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.command.Command; +import org.spongepowered.api.command.CommandCause; +import org.spongepowered.api.command.CommandCompletion; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.parameter.ArgumentReader; import org.spongepowered.api.config.ConfigDir; -import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.entity.EntityType; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.block.InteractBlockEvent; import org.spongepowered.api.event.filter.cause.Root; -import org.spongepowered.api.event.game.state.GameAboutToStartServerEvent; -import org.spongepowered.api.event.game.state.GameInitializationEvent; -import org.spongepowered.api.event.game.state.GamePostInitializationEvent; -import org.spongepowered.api.event.game.state.GamePreInitializationEvent; -import org.spongepowered.api.event.game.state.GameStartedServerEvent; -import org.spongepowered.api.event.game.state.GameStoppingServerEvent; import org.spongepowered.api.event.item.inventory.InteractItemEvent; -import org.spongepowered.api.event.network.ClientConnectionEvent; +import org.spongepowered.api.event.lifecycle.ConstructPluginEvent; +import org.spongepowered.api.event.lifecycle.RegisterCommandEvent; +import org.spongepowered.api.event.lifecycle.StartedEngineEvent; +import org.spongepowered.api.event.lifecycle.StartingEngineEvent; +import org.spongepowered.api.event.lifecycle.StoppingEngineEvent; +import org.spongepowered.api.event.network.ServerSideConnectionEvent; import org.spongepowered.api.item.ItemType; -import org.spongepowered.api.item.inventory.ItemStack; -import org.spongepowered.api.plugin.Plugin; -import org.spongepowered.api.plugin.PluginContainer; +import org.spongepowered.api.registry.RegistryEntry; +import org.spongepowered.api.registry.RegistryTypes; import org.spongepowered.api.scheduler.Task; -import org.spongepowered.api.world.Location; -import org.spongepowered.api.world.World; +import org.spongepowered.api.world.biome.Biome; +import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.api.world.server.ServerWorld; +import org.spongepowered.math.vector.Vector3d; +import org.spongepowered.plugin.PluginContainer; +import org.spongepowered.plugin.jvm.Plugin; -import java.io.File; -import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Collections; +import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.concurrent.TimeUnit; -import static com.google.common.base.Preconditions.checkNotNull; import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME; +import static java.util.stream.Collectors.toList; /** * The Sponge implementation of WorldEdit. */ -@Plugin(id = SpongeWorldEdit.MOD_ID, name = "WorldEdit", - description = "WorldEdit is an easy-to-use in-game world editor for Minecraft", - url = "https://enginehub.org/worldedit/") +@Plugin(SpongeWorldEdit.MOD_ID) public class SpongeWorldEdit { - // I think this breaks right now b/c SpongeAPI 7 injects an slf4j logger - // But it should be fine in 8, where they're also Log4j - @Inject - private Logger logger; - - private final Metrics2 metrics; - public static final String MOD_ID = "worldedit"; private static final int BSTATS_PLUGIN_ID = 3329; - private SpongePermissionsProvider provider; - - @Inject - private PluginContainer container; - private static SpongeWorldEdit inst; - public static PluginContainer container() { - return inst.container; - } - public static SpongeWorldEdit inst() { return inst; } - private SpongePlatform platform; - private SpongeImplAdapter spongeAdapter; - - @Inject - private SpongeConfiguration config; + private final Logger logger; + private final PluginContainer container; + private final SpongeConfiguration config; + private final Path workingDir; - @Inject @ConfigDir(sharedRoot = false) - private File workingDir; + private SpongePermissionsProvider provider; + private SpongePlatform platform; @Inject - public SpongeWorldEdit(Metrics2.Factory metricsFactory) { + public SpongeWorldEdit(Logger logger, + PluginContainer container, + SpongeConfiguration config, + @ConfigDir(sharedRoot = false) + Path workingDir) { + this.logger = logger; + this.container = container; + this.config = config; + this.workingDir = workingDir; inst = this; - metrics = metricsFactory.make(BSTATS_PLUGIN_ID); } @Listener - public void preInit(GamePreInitializationEvent event) { - // Load configuration - config.load(); - - Task.builder().interval(30, TimeUnit.SECONDS).execute(ThreadSafeCache.getInstance()).submit(this); - } + public void onPluginConstruction(ConstructPluginEvent event) { + this.platform = new SpongePlatform(this); + WorldEdit.getInstance().getPlatformManager().register(platform); - @Listener - public void init(GameInitializationEvent event) { - CUIChannelHandler.init(); - } + this.provider = new SpongePermissionsProvider(); - @Listener - public void postInit(GamePostInitializationEvent event) { + Task.builder() + .plugin(container) + .interval(30, TimeUnit.SECONDS) + .name("WorldEdit ThreadSafeCache") + .execute(ThreadSafeCache.getInstance()) + .build(); + + event.game().eventManager().registerListeners( + container, + new CUIChannelHandler.RegistrationHandler() + ); logger.info("WorldEdit for Sponge (version " + getInternalVersion() + ") is loaded"); } @Listener - public void serverAboutToStart(GameAboutToStartServerEvent event) { - if (this.platform != null) { - logger.warn("GameAboutToStartServerEvent occurred when GameStoppingServerEvent hasn't"); - WorldEdit.getInstance().getPlatformManager().unregister(platform); - } - - final Path delChunks = workingDir.toPath().resolve(DELCHUNKS_FILE_NAME); + public void serverStarting(StartingEngineEvent event) { + final Path delChunks = workingDir.resolve(DELCHUNKS_FILE_NAME); if (Files.exists(delChunks)) { ChunkDeleter.runFromFile(delChunks, true); } + } - this.platform = new SpongePlatform(this); - this.provider = new SpongePermissionsProvider(); - - for (BlockType blockType : Sponge.getRegistry().getAllOf(BlockType.class)) { - // TODO Handle blockstate stuff - String id = blockType.getId(); + @Listener + public void serverStarted(StartedEngineEvent event) { + for (RegistryEntry blockType : event.game().registries().registry(RegistryTypes.BLOCK_TYPE)) { + String id = blockType.key().asString(); if (!com.sk89q.worldedit.world.block.BlockType.REGISTRY.keySet().contains(id)) { - com.sk89q.worldedit.world.block.BlockType.REGISTRY.register(id, new com.sk89q.worldedit.world.block.BlockType(id)); + com.sk89q.worldedit.world.block.BlockType.REGISTRY.register(id, new com.sk89q.worldedit.world.block.BlockType( + id, + input -> { + BlockType spongeBlockType = Sponge.game().registries().registry(RegistryTypes.BLOCK_TYPE).value( + ResourceKey.resolve(input.getBlockType().getId()) + ); + return SpongeAdapter.adapt(spongeBlockType.defaultState()); + } + )); } } - for (ItemType itemType : Sponge.getRegistry().getAllOf(ItemType.class)) { - String id = itemType.getId(); + for (RegistryEntry itemType : event.game().registries().registry(RegistryTypes.ITEM_TYPE)) { + String id = itemType.key().asString(); if (!com.sk89q.worldedit.world.item.ItemType.REGISTRY.keySet().contains(id)) { com.sk89q.worldedit.world.item.ItemType.REGISTRY.register(id, new com.sk89q.worldedit.world.item.ItemType(id)); } } - WorldEdit.getInstance().getPlatformManager().register(platform); + for (RegistryEntry> entityType : event.game().registries().registry(RegistryTypes.ENTITY_TYPE)) { + String id = entityType.key().asString(); + if (!com.sk89q.worldedit.world.entity.EntityType.REGISTRY.keySet().contains(id)) { + com.sk89q.worldedit.world.entity.EntityType.REGISTRY.register(id, new com.sk89q.worldedit.world.entity.EntityType(id)); + } + } + + for (ServerWorld world : event.engine().worldManager().worlds()) { + for (RegistryEntry biomeType : world.registries().registry(RegistryTypes.BIOME)) { + String id = biomeType.key().asString(); + if (!BiomeType.REGISTRY.keySet().contains(id)) { + BiomeType.REGISTRY.register(id, new BiomeType(id)); + } + } + } + + for (ResourceLocation name : BlockTags.getAllTags().getAvailableTags()) { + if (BlockCategory.REGISTRY.get(name.toString()) == null) { + BlockCategory.REGISTRY.register(name.toString(), new BlockCategory(name.toString())); + } + } + for (ResourceLocation name : ItemTags.getAllTags().getAvailableTags()) { + if (ItemCategory.REGISTRY.get(name.toString()) == null) { + ItemCategory.REGISTRY.register(name.toString(), new ItemCategory(name.toString())); + } + } + + config.load(); + WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent(platform)); } @Listener - public void serverStopping(GameStoppingServerEvent event) { + public void serverStopping(StoppingEngineEvent event) { WorldEdit worldEdit = WorldEdit.getInstance(); worldEdit.getSessionManager().unload(); - worldEdit.getPlatformManager().unregister(platform); + WorldEdit.getInstance().getEventBus().post(new PlatformUnreadyEvent(platform)); } @Listener - public void serverStarted(GameStartedServerEvent event) { - WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent(platform)); - - loadAdapter(); - } - - private void loadAdapter() { - WorldEdit worldEdit = WorldEdit.getInstance(); + public void registerCommand(RegisterCommandEvent event) { + WorldEdit.getInstance().getEventBus().post(new PlatformsRegisteredEvent()); + PlatformManager manager = WorldEdit.getInstance().getPlatformManager(); + Platform commandsPlatform = manager.queryCapability(Capability.USER_COMMANDS); + if (commandsPlatform != platform || !platform.isHookingEvents()) { + // We're not in control of commands/events -- do not register. + return; + } - // Attempt to load a Sponge adapter - SpongeImplLoader adapterLoader = new SpongeImplLoader(); + List commands = manager.getPlatformCommandManager().getCommandManager() + .getAllCommands().collect(toList()); + for (org.enginehub.piston.Command command : commands) { + registerAdaptedCommand(event, command); - try { - adapterLoader.addFromPath(getClass().getClassLoader()); - } catch (IOException e) { - logger.warn("Failed to search path for Sponge adapters"); + Set perms = command.getCondition().as(PermissionCondition.class) + .map(PermissionCondition::getPermissions) + .orElseGet(Collections::emptySet); + if (!perms.isEmpty()) { + perms.forEach(getPermissionsProvider()::registerPermission); + } } + } - try { - adapterLoader.addFromJar(container.getSource().get().toFile()); - } catch (IOException e) { - logger.warn("Failed to search " + container.getSource().get().toFile() + " for Sponge adapters", e); - } - try { - spongeAdapter = adapterLoader.loadAdapter(); - logger.info("Using " + spongeAdapter.getClass().getCanonicalName() + " as the Sponge adapter"); - } catch (AdapterLoadException e) { - Platform platform = worldEdit.getPlatformManager().queryCapability(Capability.WORLD_EDITING); - if (platform instanceof SpongePlatform) { - logger.warn(e.getMessage()); - } else { - logger.info("WorldEdit could not find a Sponge adapter for this MC version, " - + "but it seems that you have another implementation of WorldEdit installed (" + platform.getPlatformName() + ") " - + "that handles the world editing."); + private void registerAdaptedCommand(RegisterCommandEvent event, org.enginehub.piston.Command command) { + CommandAdapter adapter = new CommandAdapter(command) { + @Override + public CommandResult process(CommandCause cause, ArgumentReader.Mutable arguments) { + CommandEvent weEvent = new CommandEvent(SpongeWorldEdit.inst().wrapCommandCause(cause), command.getName() + " " + arguments.remaining()); + WorldEdit.getInstance().getEventBus().post(weEvent); + return weEvent.isCancelled() ? CommandResult.success() : CommandResult.empty(); } - } + + @Override + public List complete(CommandCause cause, ArgumentReader.Mutable arguments) { + CommandSuggestionEvent weEvent = new CommandSuggestionEvent(SpongeWorldEdit.inst().wrapCommandCause(cause), command.getName() + " " + arguments.remaining()); + WorldEdit.getInstance().getEventBus().post(weEvent); + return CommandUtil.fixSuggestions(arguments.remaining(), weEvent.getSuggestions()) + .stream().map(CommandCompletion::of).collect(toList()); + } + }; + event.register( + container, adapter, command.getName(), command.getAliases().toArray(new String[0]) + ); } - public SpongeImplAdapter getAdapter() { - return this.spongeAdapter; + private boolean isHookingEvents() { + return platform != null && platform.isHookingEvents(); } @Listener - public void onPlayerItemInteract(InteractItemEvent.Secondary event, @Root Player spongePlayer) { - if (platform == null) { + public void onPlayerItemInteract(InteractItemEvent.Secondary event, @Root ServerPlayer spongePlayer) { + if (!isHookingEvents()) { return; } - if (!platform.isHookingEvents()) { - return; // We have to be told to catch these events - } - WorldEdit we = WorldEdit.getInstance(); - SpongePlayer player = wrapPlayer(spongePlayer); + SpongePlayer player = SpongeAdapter.adapt(spongePlayer); if (we.handleRightClick(player)) { event.setCancelled(true); } } @Listener - public void onPlayerInteract(InteractBlockEvent event, @Root Player spongePlayer) { + public void onPlayerInteract(InteractBlockEvent event, @Root ServerPlayer spongePlayer) { if (platform == null) { return; } @@ -250,62 +292,60 @@ public void onPlayerInteract(InteractBlockEvent event, @Root Player spongePlayer WorldEdit we = WorldEdit.getInstance(); - SpongePlayer player = wrapPlayer(spongePlayer); - com.sk89q.worldedit.world.World world = player.getWorld(); + SpongePlayer player = SpongeAdapter.adapt(spongePlayer); - BlockSnapshot targetBlock = event.getTargetBlock(); - Optional> optLoc = targetBlock.getLocation(); + BlockSnapshot targetBlock = event.block(); + Optional optLoc = targetBlock.location(); - BlockType interactedType = targetBlock.getState().getType(); - if (event instanceof InteractBlockEvent.Primary) { - if (interactedType != BlockTypes.AIR) { + BlockType interactedType = targetBlock.state().type(); + if (event instanceof InteractBlockEvent.Primary.Start) { + InteractBlockEvent.Primary.Start eventCast = ((InteractBlockEvent.Primary.Start) event); + if (interactedType != BlockTypes.AIR.get()) { if (!optLoc.isPresent()) { return; } - Location loc = optLoc.get(); - com.sk89q.worldedit.util.Location pos = new com.sk89q.worldedit.util.Location( - world, loc.getX(), loc.getY(), loc.getZ()); - - if (we.handleBlockLeftClick(player, pos)) { - event.setCancelled(true); - } + ServerLocation loc = optLoc.get(); + com.sk89q.worldedit.util.Location pos = SpongeAdapter.adapt( + loc, Vector3d.ZERO + ); - if (we.handleArmSwing(player)) { - event.setCancelled(true); - } - } else { - if (we.handleArmSwing(player)) { - event.setCancelled(true); + if (we.handleBlockLeftClick(player, pos, SpongeAdapter.adapt(eventCast.targetSide()))) { + eventCast.setCancelled(true); } } + if (we.handleArmSwing(player)) { + eventCast.setCancelled(true); + } } else if (event instanceof InteractBlockEvent.Secondary) { if (!optLoc.isPresent()) { return; } + InteractBlockEvent.Secondary eventCast = ((InteractBlockEvent.Secondary) event); - Location loc = optLoc.get(); - com.sk89q.worldedit.util.Location pos = new com.sk89q.worldedit.util.Location( - world, loc.getX(), loc.getY(), loc.getZ()); + ServerLocation loc = optLoc.get(); + com.sk89q.worldedit.util.Location pos = SpongeAdapter.adapt( + loc, Vector3d.ZERO + ); - if (we.handleBlockRightClick(player, pos)) { - event.setCancelled(true); + if (we.handleBlockRightClick(player, pos, SpongeAdapter.adapt(eventCast.targetSide()))) { + eventCast.setCancelled(true); } if (we.handleRightClick(player)) { - event.setCancelled(true); + eventCast.setCancelled(true); } } } @Listener - public void onPlayerQuit(ClientConnectionEvent.Disconnect event) { + public void onPlayerQuit(ServerSideConnectionEvent.Disconnect event) { WorldEdit.getInstance().getEventBus() - .post(new SessionIdleEvent(new SpongePlayer.SessionKeyImpl(event.getTargetEntity()))); + .post(new SessionIdleEvent(new SpongePlayer.SessionKeyImpl(event.player()))); } - public static ItemStack toSpongeItemStack(BaseItemStack item) { - return inst().getAdapter().makeSpongeStack(item); + public PluginContainer getPluginContainer() { + return container; } /** @@ -317,46 +357,18 @@ SpongeConfiguration getConfig() { return this.config; } - /** - * Get the WorldEdit proxy for the given player. - * - * @param player the player - * @return the WorldEdit player - */ - public SpongePlayer wrapPlayer(Player player) { - checkNotNull(player); - return new SpongePlayer(platform, player); - } - - public Actor wrapCommandSource(CommandSource sender) { - if (sender instanceof Player) { - return wrapPlayer((Player) sender); + public Actor wrapCommandCause(CommandCause cause) { + Object rootCause = cause.root(); + if (rootCause instanceof ServerPlayer) { + return SpongeAdapter.adapt((ServerPlayer) rootCause); + } + if (rootCause instanceof Audience) { + return new SpongeCommandSender((Audience) rootCause); } - return new SpongeCommandSender(this, sender); + throw new UnsupportedOperationException("Cannot wrap " + rootCause.getClass()); } - /** - * Get the session for a player. - * - * @param player the player - * @return the session - */ - public LocalSession getSession(Player player) { - checkNotNull(player); - return WorldEdit.getInstance().getSessionManager().get(wrapPlayer(player)); - } - - /** - * Get the WorldEdit proxy for the given world. - * - * @param world the world - * @return the WorldEdit world - */ - public SpongeWorld getWorld(World world) { - checkNotNull(world); - return getAdapter().getWorld(world); - } /** * Get the WorldEdit proxy for the platform. @@ -367,13 +379,17 @@ public Platform getPlatform() { return this.platform; } + SpongePlatform getInternalPlatform() { + return this.platform; + } + /** * Get the working directory where WorldEdit's files are stored. * * @return the working directory */ public Path getWorkingDir() { - return this.workingDir.toPath(); + return this.workingDir; } /** @@ -382,7 +398,7 @@ public Path getWorkingDir() { * @return a version string */ String getInternalVersion() { - return container.getVersion().orElse("Unknown"); + return container.metadata().version(); } public void setPermissionsProvider(SpongePermissionsProvider provider) { diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/ThreadSafeCache.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/ThreadSafeCache.java index fea9026657..b6f131444f 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/ThreadSafeCache.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/ThreadSafeCache.java @@ -20,7 +20,7 @@ package com.sk89q.worldedit.sponge; import org.spongepowered.api.Sponge; -import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; import java.util.ArrayList; import java.util.List; @@ -49,8 +49,8 @@ public Set getOnlineIds() { public void run() { List onlineIds = new ArrayList<>(); - for (Player player : Sponge.getServer().getOnlinePlayers()) { - onlineIds.add(player.getUniqueId()); + for (ServerPlayer player : Sponge.server().onlinePlayers()) { + onlineIds.add(player.uniqueId()); } this.onlineIds = new CopyOnWriteArraySet<>(onlineIds); diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/adapter/SpongeImplAdapter.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/adapter/SpongeImplAdapter.java deleted file mode 100644 index fcb2dc333a..0000000000 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/adapter/SpongeImplAdapter.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.sponge.adapter; - -import com.flowpowered.math.vector.Vector3d; -import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.math.Vector3; -import com.sk89q.worldedit.sponge.SpongeWorld; -import com.sk89q.worldedit.util.Location; -import org.spongepowered.api.entity.Entity; -import org.spongepowered.api.item.inventory.ItemStack; -import org.spongepowered.api.world.World; - -/** - * An interface for various things that can't be done through the Sponge API. - */ -public interface SpongeImplAdapter { - - BaseEntity createBaseEntity(Entity entity); - - ItemStack makeSpongeStack(BaseItemStack itemStack); - - SpongeWorld getWorld(World world); - - default boolean isBest() { - return true; - } - - default Location adapt(org.spongepowered.api.world.Location loc, Vector3d rot) { - Vector3 position = Vector3.at(loc.getX(), loc.getY(), loc.getZ()); - - return new Location(getWorld(loc.getExtent()), position, (float) rot.getY(), (float) rot.getX()); - } -} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/adapter/SpongeImplLoader.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/adapter/SpongeImplLoader.java deleted file mode 100644 index 47303b9d1f..0000000000 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/adapter/SpongeImplLoader.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.sponge.adapter; - -import com.google.common.collect.Lists; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.util.io.Closer; -import org.apache.logging.log4j.Logger; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; - -/** - * Loads Sponge implementation adapters. - */ -public class SpongeImplLoader { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - private final List adapterCandidates = new ArrayList<>(); - private String customCandidate; - - private static final String SEARCH_PACKAGE = "com.sk89q.worldedit.sponge.adapter.impl"; - private static final String SEARCH_PACKAGE_DOT = SEARCH_PACKAGE + "."; - private static final String SEARCH_PATH = SEARCH_PACKAGE.replace(".", "/"); - private static final String CLASS_SUFFIX = ".class"; - - private static final String LOAD_ERROR_MESSAGE = - "\n**********************************************\n" - + "** This WorldEdit version does not support your version of Sponge.\n" - + "** WorldEdit will not function! \n" - + "** \n" - + "** Please ensure you are running the latest version\n" - + "**********************************************\n"; - - /** - * Create a new instance. - */ - public SpongeImplLoader() { - addDefaults(); - } - - /** - * Add default candidates, such as any defined with - * {@code -Dworldedit.sponge.adapter}. - */ - private void addDefaults() { - String className = System.getProperty("worldedit.sponge.adapter"); - if (className != null) { - customCandidate = className; - adapterCandidates.add(className); - LOGGER.info("-Dworldedit.sponge.adapter used to add " + className + " to the list of available Sponge adapters"); - } - } - - /** - * Search the given JAR for candidate implementations. - * - * @param file the file - * @throws IOException thrown on I/O error - */ - public void addFromJar(File file) throws IOException { - Closer closer = Closer.create(); - JarFile jar = closer.register(new JarFile(file)); - try { - Enumeration entries = jar.entries(); - while (entries.hasMoreElements()) { - JarEntry jarEntry = (JarEntry) entries.nextElement(); - - String className = jarEntry.getName().replaceAll("[/\\\\]+", "."); - - if (!className.startsWith(SEARCH_PACKAGE_DOT) || jarEntry.isDirectory() || className.contains("$")) { - continue; - } - - int beginIndex = 0; - int endIndex = className.length() - CLASS_SUFFIX.length(); - className = className.substring(beginIndex, endIndex); - adapterCandidates.add(className); - } - } finally { - closer.close(); - } - } - - /** - * Search for classes stored as separate files available via the given - * class loader. - * - * @param classLoader the class loader - * @throws IOException thrown on error - */ - public void addFromPath(ClassLoader classLoader) throws IOException { - Enumeration resources = classLoader.getResources(SEARCH_PATH); - while (resources.hasMoreElements()) { - File file = new File(resources.nextElement().getFile()); - addFromPath(file); - } - } - - /** - * Search for classes stored as separate files available via the given - * path. - * - * @param file the path - */ - private void addFromPath(File file) { - String resource = SEARCH_PACKAGE_DOT + file.getName(); - if (file.isDirectory()) { - File[] files = file.listFiles(); - if (files != null) { - for (File child : files) { - addFromPath(child); - } - } - } else if (resource.endsWith(CLASS_SUFFIX)) { - int beginIndex = 0; - int endIndex = resource.length() - CLASS_SUFFIX.length(); - String className = resource.substring(beginIndex, endIndex); - if (!className.contains("$")) { - adapterCandidates.add(className); - } - } - } - - /** - * Iterate through the list of candidates and load an adapter. - * - * @return an adapter - * @throws AdapterLoadException thrown if no adapter could be found - */ - public SpongeImplAdapter loadAdapter() throws AdapterLoadException { - List suitableAdapters = Lists.newArrayList(); - for (String className : adapterCandidates) { - try { - Class cls = Class.forName(className); - if (SpongeImplAdapter.class.isAssignableFrom(cls)) { - suitableAdapters.add((SpongeImplAdapter) cls.newInstance()); - } else { - LOGGER.warn("Failed to load the Sponge adapter class '" + className - + "' because it does not implement " + SpongeImplAdapter.class.getCanonicalName()); - } - } catch (ClassNotFoundException e) { - LOGGER.warn("Failed to load the Sponge adapter class '" + className - + "' that is not supposed to be missing", e); - } catch (IllegalAccessException e) { - LOGGER.warn("Failed to load the Sponge adapter class '" + className - + "' that is not supposed to be raising this error", e); - } catch (Throwable e) { - if (className.equals(customCandidate)) { - LOGGER.warn("Failed to load the Sponge adapter class '" + className + "'", e); - } - } - } - - if (suitableAdapters.isEmpty()) { - throw new AdapterLoadException(LOAD_ERROR_MESSAGE); - } else { - if (suitableAdapters.size() == 1) { - return suitableAdapters.get(0); - } else { - return suitableAdapters.stream().sorted((o1, o2) -> { - if (o1.isBest() && !o2.isBest()) { - return -1; - } else if (!o1.isBest() && o2.isBest()) { - return 1; - } - return 0; - }).findFirst().orElse(suitableAdapters.get(0)); - } - } - } -} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java index 7435d69887..6c88509858 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java @@ -19,17 +19,17 @@ package com.sk89q.worldedit.sponge.config; -import com.google.common.reflect.TypeToken; +import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.session.SessionManager; import com.sk89q.worldedit.util.report.Unreported; import com.sk89q.worldedit.world.registry.LegacyMapper; -import ninja.leaping.configurate.ConfigurationOptions; -import ninja.leaping.configurate.commented.CommentedConfigurationNode; -import ninja.leaping.configurate.loader.ConfigurationLoader; -import ninja.leaping.configurate.objectmapping.ObjectMappingException; import org.apache.logging.log4j.Logger; +import org.spongepowered.configurate.CommentedConfigurationNode; +import org.spongepowered.configurate.ConfigurationOptions; +import org.spongepowered.configurate.loader.ConfigurationLoader; +import org.spongepowered.configurate.serialize.SerializationException; import java.io.IOException; import java.util.HashSet; @@ -37,10 +37,13 @@ public class ConfigurateConfiguration extends LocalConfiguration { - @Unreported protected final ConfigurationLoader config; - @Unreported protected final Logger logger; + @Unreported + protected final ConfigurationLoader config; + @Unreported + protected final Logger logger; - @Unreported protected CommentedConfigurationNode node; + @Unreported + protected CommentedConfigurationNode node; public ConfigurateConfiguration(ConfigurationLoader config, Logger logger) { this.config = config; @@ -51,87 +54,94 @@ public ConfigurateConfiguration(ConfigurationLoader public void load() { try { ConfigurationOptions options = ConfigurationOptions.defaults(); - options = options.setShouldCopyDefaults(true); + options = options.shouldCopyDefaults(true); node = config.load(options); } catch (IOException e) { logger.warn("Error loading WorldEdit configuration", e); } - profile = node.getNode("debug").getBoolean(profile); - traceUnflushedSessions = node.getNode("debugging", "trace-unflushed-sessions").getBoolean(traceUnflushedSessions); - wandItem = node.getNode("wand-item").getString(wandItem).toLowerCase(Locale.ROOT); + profile = node.node("debug").getBoolean(profile); + traceUnflushedSessions = node.node("debugging", "trace-unflushed-sessions").getBoolean(traceUnflushedSessions); + wandItem = node.node("wand-item").getString(wandItem).toLowerCase(Locale.ROOT); try { wandItem = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(wandItem)).getId(); } catch (Throwable ignored) { } - defaultChangeLimit = Math.max(-1, node.getNode("limits", "max-blocks-changed", "default").getInt(defaultChangeLimit)); - maxChangeLimit = Math.max(-1, node.getNode("limits", "max-blocks-changed", "maximum").getInt(maxChangeLimit)); + defaultChangeLimit = Math.max(-1, node.node("limits", "max-blocks-changed", "default").getInt(defaultChangeLimit)); + maxChangeLimit = Math.max(-1, node.node("limits", "max-blocks-changed", "maximum").getInt(maxChangeLimit)); - defaultVerticalHeight = Math.max(1, node.getNode("limits", "vertical-height", "default").getInt(defaultVerticalHeight)); + defaultVerticalHeight = Math.max(1, node.node("limits", "vertical-height", "default").getInt(defaultVerticalHeight)); - defaultMaxPolygonalPoints = Math.max(-1, node.getNode("limits", "max-polygonal-points", "default").getInt(defaultMaxPolygonalPoints)); - maxPolygonalPoints = Math.max(-1, node.getNode("limits", "max-polygonal-points", "maximum").getInt(maxPolygonalPoints)); + defaultMaxPolygonalPoints = Math.max(-1, node.node("limits", "max-polygonal-points", "default").getInt(defaultMaxPolygonalPoints)); + maxPolygonalPoints = Math.max(-1, node.node("limits", "max-polygonal-points", "maximum").getInt(maxPolygonalPoints)); - maxRadius = Math.max(-1, node.getNode("limits", "max-radius").getInt(maxRadius)); - maxBrushRadius = node.getNode("limits", "max-brush-radius").getInt(maxBrushRadius); - maxSuperPickaxeSize = Math.max(1, node.getNode("limits", "max-super-pickaxe-size").getInt(maxSuperPickaxeSize)); + maxRadius = Math.max(-1, node.node("limits", "max-radius").getInt(maxRadius)); + maxBrushRadius = node.node("limits", "max-brush-radius").getInt(maxBrushRadius); + maxSuperPickaxeSize = Math.max(1, node.node("limits", "max-super-pickaxe-size").getInt(maxSuperPickaxeSize)); - butcherDefaultRadius = Math.max(-1, node.getNode("limits", "butcher-radius", "default").getInt(butcherDefaultRadius)); - butcherMaxRadius = Math.max(-1, node.getNode("limits", "butcher-radius", "maximum").getInt(butcherMaxRadius)); + butcherDefaultRadius = Math.max(-1, node.node("limits", "butcher-radius", "default").getInt(butcherDefaultRadius)); + butcherMaxRadius = Math.max(-1, node.node("limits", "butcher-radius", "maximum").getInt(butcherMaxRadius)); try { - disallowedBlocks = new HashSet<>(node.getNode("limits", "disallowed-blocks").getList(TypeToken.of(String.class))); - } catch (ObjectMappingException e) { + disallowedBlocks = new HashSet<>( + node.node("limits", "disallowed-blocks").getList( + String.class, + ImmutableList.copyOf(getDefaultDisallowedBlocks()) + ) + ); + } catch (SerializationException e) { logger.warn("Error loading WorldEdit configuration", e); } try { - allowedDataCycleBlocks = new HashSet<>(node.getNode("limits", "allowed-data-cycle-blocks").getList(TypeToken.of(String.class))); - } catch (ObjectMappingException e) { + allowedDataCycleBlocks = new HashSet<>( + node.node("limits", "allowed-data-cycle-blocks").getList(String.class, ImmutableList.of()) + ); + } catch (SerializationException e) { logger.warn("Error loading WorldEdit configuration", e); } - registerHelp = node.getNode("register-help").getBoolean(true); - logCommands = node.getNode("logging", "log-commands").getBoolean(logCommands); - logFile = node.getNode("logging", "file").getString(logFile); - logFormat = node.getNode("logging", "format").getString(logFormat); + registerHelp = node.node("register-help").getBoolean(true); + logCommands = node.node("logging", "log-commands").getBoolean(logCommands); + logFile = node.node("logging", "file").getString(logFile); + logFormat = node.node("logging", "format").getString(logFormat); - superPickaxeDrop = node.getNode("super-pickaxe", "drop-items").getBoolean(superPickaxeDrop); - superPickaxeManyDrop = node.getNode("super-pickaxe", "many-drop-items").getBoolean(superPickaxeManyDrop); + superPickaxeDrop = node.node("super-pickaxe", "drop-items").getBoolean(superPickaxeDrop); + superPickaxeManyDrop = node.node("super-pickaxe", "many-drop-items").getBoolean(superPickaxeManyDrop); - useInventory = node.getNode("use-inventory", "enable").getBoolean(useInventory); - useInventoryOverride = node.getNode("use-inventory", "allow-override").getBoolean(useInventoryOverride); - useInventoryCreativeOverride = node.getNode("use-inventory", "creative-mode-overrides").getBoolean(useInventoryCreativeOverride); + useInventory = node.node("use-inventory", "enable").getBoolean(useInventory); + useInventoryOverride = node.node("use-inventory", "allow-override").getBoolean(useInventoryOverride); + useInventoryCreativeOverride = node.node("use-inventory", "creative-mode-overrides").getBoolean(useInventoryCreativeOverride); - navigationWand = node.getNode("navigation-wand", "item").getString(navigationWand).toLowerCase(Locale.ROOT); + navigationWand = node.node("navigation-wand", "item").getString(navigationWand).toLowerCase(Locale.ROOT); try { navigationWand = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(navigationWand)).getId(); } catch (Throwable ignored) { } - navigationWandMaxDistance = node.getNode("navigation-wand", "max-distance").getInt(navigationWandMaxDistance); - navigationUseGlass = node.getNode("navigation", "use-glass").getBoolean(navigationUseGlass); + navigationWandMaxDistance = node.node("navigation-wand", "max-distance").getInt(navigationWandMaxDistance); + navigationUseGlass = node.node("navigation", "use-glass").getBoolean(navigationUseGlass); - scriptTimeout = node.getNode("scripting", "timeout").getInt(scriptTimeout); - scriptsDir = node.getNode("scripting", "dir").getString(scriptsDir); + scriptTimeout = node.node("scripting", "timeout").getInt(scriptTimeout); + scriptsDir = node.node("scripting", "dir").getString(scriptsDir); - saveDir = node.getNode("saving", "dir").getString(saveDir); + saveDir = node.node("saving", "dir").getString(saveDir); - allowSymlinks = node.getNode("files", "allow-symbolic-links").getBoolean(false); - LocalSession.MAX_HISTORY_SIZE = Math.max(0, node.getNode("history", "size").getInt(15)); - SessionManager.EXPIRATION_GRACE = node.getNode("history", "expiration").getInt(10) * 60 * 1000; + allowSymlinks = node.node("files", "allow-symbolic-links").getBoolean(false); + LocalSession.MAX_HISTORY_SIZE = Math.max(0, node.node("history", "size").getInt(15)); + SessionManager.EXPIRATION_GRACE = node.node("history", "expiration").getInt(10) * 60 * 1000; - showHelpInfo = node.getNode("show-help-on-first-use").getBoolean(true); - serverSideCUI = node.getNode("server-side-cui").getBoolean(true); + showHelpInfo = node.node("show-help-on-first-use").getBoolean(true); + serverSideCUI = node.node("server-side-cui").getBoolean(true); - String snapshotsDir = node.getNode("snapshots", "directory").getString(""); - boolean experimentalSnapshots = node.getNode("snapshots", "experimental").getBoolean(false); + String snapshotsDir = node.node("snapshots", "directory").getString(""); + boolean experimentalSnapshots = node.node("snapshots", "experimental").getBoolean(false); initializeSnapshotConfiguration(snapshotsDir, experimentalSnapshots); - String type = node.getNode("shell-save-type").getString("").trim(); + String type = node.node("shell-save-type").getString("").trim(); shellSaveType = type.equals("") ? null : type; - extendedYLimit = node.getNode("compat", "extended-y-limit").getBoolean(false); - setDefaultLocaleName(node.getNode("default-locale").getString(defaultLocaleName)); + extendedYLimit = node.node("compat", "extended-y-limit").getBoolean(false); + setDefaultLocaleName(node.node("default-locale").getString(defaultLocaleName)); } } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/SpongeConfiguration.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/SpongeConfiguration.java index 05e9cd2e17..bb58a5d8c4 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/SpongeConfiguration.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/SpongeConfiguration.java @@ -21,10 +21,10 @@ import com.google.inject.Inject; import com.sk89q.worldedit.sponge.SpongeWorldEdit; -import ninja.leaping.configurate.commented.CommentedConfigurationNode; -import ninja.leaping.configurate.loader.ConfigurationLoader; import org.apache.logging.log4j.Logger; import org.spongepowered.api.config.DefaultConfig; +import org.spongepowered.configurate.CommentedConfigurationNode; +import org.spongepowered.configurate.loader.ConfigurationLoader; import java.io.IOException; import java.nio.file.Path; @@ -35,7 +35,9 @@ public class SpongeConfiguration extends ConfigurateConfiguration { public boolean cheatMode = false; @Inject - public SpongeConfiguration(@DefaultConfig(sharedRoot = false) ConfigurationLoader config, Logger logger) { + public SpongeConfiguration(@DefaultConfig(sharedRoot = false) + ConfigurationLoader config, + Logger logger) { super(config, logger); } @@ -43,8 +45,8 @@ public SpongeConfiguration(@DefaultConfig(sharedRoot = false) ConfigurationLoade public void load() { super.load(); - creativeEnable = node.getNode("use-in-creative").getBoolean(false); - cheatMode = node.getNode("cheat-mode").getBoolean(false); + creativeEnable = node.node("use-in-creative").getBoolean(false); + cheatMode = node.node("cheat-mode").getBoolean(false); try { config.save(node); diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/internal/ExtendedChunk.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/internal/ExtendedChunk.java new file mode 100644 index 0000000000..47e0451e27 --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/internal/ExtendedChunk.java @@ -0,0 +1,43 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge.internal; + +import com.sk89q.worldedit.util.SideEffect; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; + +import javax.annotation.Nullable; + +public interface ExtendedChunk { + /** + * {@link LevelChunk#setBlockState(BlockPos, BlockState, boolean)} with the extra + * {@link SideEffect#UPDATE} flag. + * + * @param pos the position to set + * @param state the state to set + * @param moved I honestly have no idea and can't be bothered to investigate, we pass {@code + * false} + * @param update the update flag, see side-effect for details + * @return the old block state, or {@code null} if unchanged + */ + @Nullable + BlockState setBlockState(BlockPos pos, BlockState state, boolean moved, boolean update); +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/internal/LocaleResolver.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/internal/LocaleResolver.java new file mode 100644 index 0000000000..4f7f4c8a54 --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/internal/LocaleResolver.java @@ -0,0 +1,35 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge.internal; + +import com.sk89q.worldedit.WorldEdit; +import net.kyori.adventure.audience.Audience; +import org.spongepowered.api.util.locale.LocaleSource; + +import java.util.Locale; + +public class LocaleResolver { + public static Locale resolveLocale(Audience audience) { + if (audience instanceof LocaleSource) { + return ((LocaleSource) audience).locale(); + } + return WorldEdit.getInstance().getConfiguration().defaultLocale; + } +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/internal/NbtAdapter.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/internal/NbtAdapter.java new file mode 100644 index 0000000000..5cf4229111 --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/internal/NbtAdapter.java @@ -0,0 +1,279 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge.internal; + +import com.sk89q.jnbt.ByteArrayTag; +import com.sk89q.jnbt.ByteTag; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.CompoundTagBuilder; +import com.sk89q.jnbt.DoubleTag; +import com.sk89q.jnbt.EndTag; +import com.sk89q.jnbt.FloatTag; +import com.sk89q.jnbt.IntArrayTag; +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.ListTagBuilder; +import com.sk89q.jnbt.LongArrayTag; +import com.sk89q.jnbt.LongTag; +import com.sk89q.jnbt.ShortTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import org.spongepowered.api.data.persistence.DataContainer; +import org.spongepowered.api.data.persistence.DataQuery; +import org.spongepowered.api.data.persistence.DataSerializable; +import org.spongepowered.api.data.persistence.DataView; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class NbtAdapter { + /** + * A separator to introduce errors if there is something to be separated. We should only see + * single-part keys. + */ + private static final String BREAKING_SEPARATOR = "if you see this, something is wrong"; + + public static CompoundTag adaptToWorldEdit(DataView view) { + CompoundTagBuilder builder = CompoundTagBuilder.create(); + for (Map.Entry entry : view.values(false).entrySet()) { + builder.put( + entry.getKey().asString(BREAKING_SEPARATOR), + adaptUnknownToWorldEdit(entry.getValue()) + ); + } + return builder.build(); + } + + private static Tag adaptUnknownToWorldEdit(Object object) { + if (object instanceof DataView) { + return adaptToWorldEdit((DataView) object); + } + if (object instanceof Boolean) { + return new ByteTag((byte) ((Boolean) object ? 1 : 0)); + } + if (object instanceof Byte) { + return new ByteTag((Byte) object); + } + if (object instanceof Short) { + return new ShortTag(((Short) object)); + } + if (object instanceof Integer) { + return new IntTag(((Integer) object)); + } + if (object instanceof Long) { + return new LongTag(((Long) object)); + } + if (object instanceof Float) { + return new FloatTag(((Float) object)); + } + if (object instanceof Double) { + return new DoubleTag(((Double) object)); + } + if (object instanceof String) { + return new StringTag((String) object); + } + if (object instanceof byte[]) { + return new ByteArrayTag(((byte[]) object)); + } + if (object instanceof Byte[]) { + Byte[] array = (Byte[]) object; + byte[] copy = new byte[array.length]; + for (int i = 0; i < copy.length; i++) { + copy[i] = array[i]; + } + return new ByteArrayTag(copy); + } + if (object instanceof int[]) { + return new IntArrayTag(((int[]) object)); + } + if (object instanceof Integer[]) { + Integer[] array = (Integer[]) object; + int[] copy = new int[array.length]; + for (int i = 0; i < copy.length; i++) { + copy[i] = array[i]; + } + return new IntArrayTag(copy); + } + if (object instanceof long[]) { + return new LongArrayTag(((long[]) object)); + } + if (object instanceof Long[]) { + Long[] array = (Long[]) object; + long[] copy = new long[array.length]; + for (int i = 0; i < copy.length; i++) { + copy[i] = array[i]; + } + return new LongArrayTag(copy); + } + if (object instanceof List) { + List objects = (List) object; + if (objects.isEmpty()) { + return new ListTag(EndTag.class, Collections.emptyList()); + } + Tag[] entries = new Tag[objects.size()]; + for (int i = 0; i < objects.size(); i++) { + Object value = objects.get(i); + entries[i] = adaptUnknownToWorldEdit(value); + } + return ListTagBuilder.createWith(entries).build(); + } + if (object instanceof Map) { + CompoundTagBuilder builder = CompoundTagBuilder.create(); + for (Map.Entry entry : ((Map) object).entrySet()) { + String key = entry.getKey() instanceof DataQuery + ? ((DataQuery) entry.getKey()).asString(BREAKING_SEPARATOR) + : entry.getKey().toString(); + builder.put(key, adaptUnknownToWorldEdit(entry.getValue())); + } + return builder.build(); + } + if (object instanceof DataSerializable) { + return adaptToWorldEdit(((DataSerializable) object).toContainer()); + } + throw new UnsupportedOperationException("Unable to translate into NBT: " + object.getClass()); + } + + public static DataContainer adaptFromWorldEdit(CompoundTag tag) { + // copy to container, no cloning used because it's unlikely to leak + // and it's cheaper this way + DataContainer container = DataContainer.createNew(DataView.SafetyMode.NO_DATA_CLONED); + for (Map.Entry entry : tag.getValue().entrySet()) { + container.set(DataQuery.of(entry.getKey()), adaptTagFromWorldEdit(entry.getValue())); + } + return container; + } + + private static Object adaptTagFromWorldEdit(Tag value) { + if (value instanceof ListTag) { + return ((ListTag) value).getValue().stream() + .map(NbtAdapter::adaptTagFromWorldEdit) + .collect(Collectors.toList()); + } + if (value instanceof CompoundTag) { + return adaptFromWorldEdit(((CompoundTag) value)); + } + // everything else is raw JDK types, so we can use it directly + return value.getValue(); + } + + public static net.minecraft.nbt.Tag adaptNMSToWorldEdit(Tag tag) { + if (tag instanceof IntArrayTag) { + return adaptNMSToWorldEdit((IntArrayTag) tag); + + } else if (tag instanceof ListTag) { + return adaptNMSToWorldEdit((ListTag) tag); + + } else if (tag instanceof LongTag) { + return adaptNMSToWorldEdit((LongTag) tag); + + } else if (tag instanceof LongArrayTag) { + return adaptNMSToWorldEdit((LongArrayTag) tag); + + } else if (tag instanceof StringTag) { + return adaptNMSToWorldEdit((StringTag) tag); + + } else if (tag instanceof IntTag) { + return adaptNMSToWorldEdit((IntTag) tag); + + } else if (tag instanceof ByteTag) { + return adaptNMSToWorldEdit((ByteTag) tag); + + } else if (tag instanceof ByteArrayTag) { + return adaptNMSToWorldEdit((ByteArrayTag) tag); + + } else if (tag instanceof CompoundTag) { + return adaptNMSToWorldEdit((CompoundTag) tag); + + } else if (tag instanceof FloatTag) { + return adaptNMSToWorldEdit((FloatTag) tag); + + } else if (tag instanceof ShortTag) { + return adaptNMSToWorldEdit((ShortTag) tag); + + } else if (tag instanceof DoubleTag) { + return adaptNMSToWorldEdit((DoubleTag) tag); + } else { + throw new IllegalArgumentException("Can't convert tag of type " + tag.getClass().getCanonicalName()); + } + } + + public static net.minecraft.nbt.IntArrayTag adaptNMSToWorldEdit(IntArrayTag tag) { + int[] value = tag.getValue(); + return new net.minecraft.nbt.IntArrayTag(Arrays.copyOf(value, value.length)); + } + + public static net.minecraft.nbt.ListTag adaptNMSToWorldEdit(ListTag tag) { + net.minecraft.nbt.ListTag list = new net.minecraft.nbt.ListTag(); + for (Tag child : tag.getValue()) { + if (child instanceof EndTag) { + continue; + } + list.add(adaptNMSToWorldEdit(child)); + } + return list; + } + + public static net.minecraft.nbt.LongTag adaptNMSToWorldEdit(LongTag tag) { + return net.minecraft.nbt.LongTag.valueOf(tag.getValue()); + } + + public static net.minecraft.nbt.LongArrayTag adaptNMSToWorldEdit(LongArrayTag tag) { + return new net.minecraft.nbt.LongArrayTag(tag.getValue().clone()); + } + + public static net.minecraft.nbt.StringTag adaptNMSToWorldEdit(StringTag tag) { + return net.minecraft.nbt.StringTag.valueOf(tag.getValue()); + } + + public static net.minecraft.nbt.IntTag adaptNMSToWorldEdit(IntTag tag) { + return net.minecraft.nbt.IntTag.valueOf(tag.getValue()); + } + + public static net.minecraft.nbt.ByteTag adaptNMSToWorldEdit(ByteTag tag) { + return net.minecraft.nbt.ByteTag.valueOf(tag.getValue()); + } + + public static net.minecraft.nbt.ByteArrayTag adaptNMSToWorldEdit(ByteArrayTag tag) { + return new net.minecraft.nbt.ByteArrayTag(tag.getValue().clone()); + } + + public static net.minecraft.nbt.CompoundTag adaptNMSToWorldEdit(CompoundTag tag) { + net.minecraft.nbt.CompoundTag compound = new net.minecraft.nbt.CompoundTag(); + for (Map.Entry child : tag.getValue().entrySet()) { + compound.put(child.getKey(), adaptNMSToWorldEdit(child.getValue())); + } + return compound; + } + + public static net.minecraft.nbt.FloatTag adaptNMSToWorldEdit(FloatTag tag) { + return net.minecraft.nbt.FloatTag.valueOf(tag.getValue()); + } + + public static net.minecraft.nbt.ShortTag adaptNMSToWorldEdit(ShortTag tag) { + return net.minecraft.nbt.ShortTag.valueOf(tag.getValue()); + } + + public static net.minecraft.nbt.DoubleTag adaptNMSToWorldEdit(DoubleTag tag) { + return net.minecraft.nbt.DoubleTag.valueOf(tag.getValue()); + } +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/internal/SpongeTransmogrifier.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/internal/SpongeTransmogrifier.java new file mode 100644 index 0000000000..589d52acc2 --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/internal/SpongeTransmogrifier.java @@ -0,0 +1,179 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge.internal; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.registry.state.BooleanProperty; +import com.sk89q.worldedit.registry.state.DirectionalProperty; +import com.sk89q.worldedit.registry.state.EnumProperty; +import com.sk89q.worldedit.registry.state.IntegerProperty; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import net.minecraft.util.StringRepresentable; +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.registry.RegistryTypes; +import org.spongepowered.api.state.BooleanStateProperty; +import org.spongepowered.api.state.EnumStateProperty; +import org.spongepowered.api.state.IntegerStateProperty; +import org.spongepowered.api.state.StateProperty; + +import java.util.Comparator; +import java.util.Map; +import java.util.Optional; +import java.util.TreeMap; +import java.util.stream.Collectors; + +/** + * Raw, un-cached transformations. + */ +public class SpongeTransmogrifier { + + public static Property transmogToWorldEditProperty(StateProperty property) { + if (property instanceof BooleanStateProperty) { + return new BooleanProperty(property.name(), ImmutableList.copyOf(((BooleanStateProperty) property).possibleValues())); + } + if (property instanceof IntegerStateProperty) { + return new IntegerProperty(property.name(), ImmutableList.copyOf(((IntegerStateProperty) property).possibleValues())); + } + if (isDirectionProperty(property)) { + return new DirectionalProperty(property.name(), + ((EnumStateProperty) property).possibleValues().stream() + .map(x -> adaptDirection((net.minecraft.core.Direction) x)) + .collect(Collectors.toList()) + ); + } + if (property instanceof EnumStateProperty) { + return new EnumProperty(property.name(), ((EnumStateProperty) property).possibleValues().stream() + .map(x -> ((StringRepresentable) x).getSerializedName()) + .collect(Collectors.toList())); + } + throw new IllegalStateException("Unknown property type"); + } + + private static Map, Object> transmogToWorldEditProperties(BlockType block, Map, ?> mcProps) { + Map, Object> props = new TreeMap<>(Comparator.comparing(Property::getName)); + for (Map.Entry, ?> prop : mcProps.entrySet()) { + Object value = prop.getValue(); + if (isDirectionProperty(prop.getKey())) { + value = adaptDirection((net.minecraft.core.Direction) value); + } else if (prop.getKey() instanceof EnumStateProperty) { + value = ((StringRepresentable) value).getSerializedName(); + } + props.put(block.getProperty(prop.getKey().name()), value); + } + return props; + } + + private static boolean isDirectionProperty(StateProperty property) { + return property instanceof EnumStateProperty + && property.valueClass().isAssignableFrom(net.minecraft.core.Direction.class); + } + + private static Direction adaptDirection(net.minecraft.core.Direction direction) { + switch (direction) { + case UP: + return Direction.UP; + case DOWN: + return Direction.DOWN; + case EAST: + return Direction.EAST; + case WEST: + return Direction.WEST; + case NORTH: + return Direction.NORTH; + case SOUTH: + return Direction.SOUTH; + default: + throw new AssertionError("New direction added: " + direction); + } + } + + private static net.minecraft.core.Direction adaptDirection(Direction direction) { + switch (direction) { + case UP: + return net.minecraft.core.Direction.UP; + case DOWN: + return net.minecraft.core.Direction.DOWN; + case EAST: + return net.minecraft.core.Direction.EAST; + case WEST: + return net.minecraft.core.Direction.WEST; + case NORTH: + return net.minecraft.core.Direction.NORTH; + case SOUTH: + return net.minecraft.core.Direction.SOUTH; + default: + throw new AssertionError("New direction added: " + direction); + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private static org.spongepowered.api.block.BlockState transmogToMinecraftProperties( + org.spongepowered.api.block.BlockState newState, + Map, Object> states + ) { + org.spongepowered.api.block.BlockType type = newState.type(); + for (Map.Entry, Object> state : states.entrySet()) { + StateProperty property = type.findStateProperty(state.getKey().getName()) + .orElseThrow(() -> new IllegalStateException( + "Missing property in " + type + ": " + state.getKey().getName()) + ); + Comparable value = (Comparable) state.getValue(); + // we may need to adapt this value, depending on the source prop + if (state.getKey() instanceof DirectionalProperty) { + Direction dir = (Direction) value; + value = adaptDirection(dir); + } else if (state.getKey() instanceof EnumProperty) { + String enumName = (String) value; + value = property.parseValue(enumName).orElseThrow(() -> new IllegalStateException( + "Failed to parse '" + enumName + "' into " + state.getKey().getName() + )); + } + + Optional optional = + newState.withStateProperty((StateProperty) property, value); + newState = optional.orElseThrow(() -> new IllegalStateException( + "Failed to change state property " + property.name() + )); + } + return newState; + } + + public static org.spongepowered.api.block.BlockState transmogToMinecraft(BlockState blockState) { + org.spongepowered.api.block.BlockType mcBlock = Sponge.game().registries().registry(RegistryTypes.BLOCK_TYPE) + .value(ResourceKey.resolve(blockState.getBlockType().getId())); + org.spongepowered.api.block.BlockState newState = mcBlock.defaultState(); + Map, Object> states = blockState.getStates(); + return transmogToMinecraftProperties(newState, states); + } + + public static BlockState transmogToWorldEdit(org.spongepowered.api.block.BlockState blockState) { + BlockType blockType = BlockType.REGISTRY.get( + blockState.type().key(RegistryTypes.BLOCK_TYPE).asString() + ); + return blockType.getState(transmogToWorldEditProperties(blockType, blockState.statePropertyMap())); + } + + private SpongeTransmogrifier() { + } +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/internal/SpongeWorldNativeAccess.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/internal/SpongeWorldNativeAccess.java new file mode 100644 index 0000000000..d400039c0a --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/internal/SpongeWorldNativeAccess.java @@ -0,0 +1,147 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge.internal; + +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.sponge.SpongeAdapter; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; + +import java.lang.ref.WeakReference; +import java.util.Objects; +import javax.annotation.Nullable; + +public class SpongeWorldNativeAccess implements WorldNativeAccess { + private static final int UPDATE = 1; + private static final int NOTIFY = 2; + + private final WeakReference world; + private SideEffectSet sideEffectSet; + + public SpongeWorldNativeAccess(WeakReference world) { + this.world = world; + } + + private ServerLevel getWorld() { + return Objects.requireNonNull(world.get(), "The reference to the world was lost"); + } + + @Override + public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { + this.sideEffectSet = sideEffectSet; + } + + @Override + public LevelChunk getChunk(int x, int z) { + return getWorld().getChunk(x, z); + } + + @Override + public BlockState toNative(com.sk89q.worldedit.world.block.BlockState state) { + return (BlockState) SpongeAdapter.adapt(state); + } + + @Override + public BlockState getBlockState(LevelChunk chunk, BlockPos position) { + return chunk.getBlockState(position); + } + + @Nullable + @Override + public BlockState setBlockState(LevelChunk chunk, BlockPos position, BlockState state) { + if (chunk instanceof ExtendedChunk) { + return ((ExtendedChunk) chunk).setBlockState( + position, state, false, sideEffectSet.shouldApply(SideEffect.UPDATE) + ); + } + return chunk.setBlockState(position, state, false); + } + + @Override + public BlockState getValidBlockForPosition(BlockState block, BlockPos position) { + return Block.updateFromNeighbourShapes(block, getWorld(), position); + } + + @Override + public BlockPos getPosition(int x, int y, int z) { + return new BlockPos(x, y, z); + } + + @Override + public void updateLightingForBlock(BlockPos position) { + getWorld().getChunkSource().getLightEngine().checkBlock(position); + } + + @Override + public boolean updateTileEntity(BlockPos position, com.sk89q.jnbt.CompoundTag tag) { + CompoundTag nativeTag = NbtAdapter.adaptNMSToWorldEdit(tag); + BlockEntity tileEntity = getWorld().getChunk(position).getBlockEntity(position); + if (tileEntity == null) { + return false; + } + tileEntity.setLevelAndPosition(getWorld(), position); + tileEntity.load(getWorld().getBlockState(position), nativeTag); + return true; + } + + @Override + public void notifyBlockUpdate(BlockPos position, BlockState oldState, BlockState newState) { + getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY); + } + + @Override + public boolean isChunkTicking(LevelChunk chunk) { + return chunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); + } + + @Override + public void markBlockChanged(BlockPos position) { + getWorld().getChunkSource().blockChanged(position); + } + + @Override + public void notifyNeighbors(BlockPos pos, BlockState oldState, BlockState newState) { + getWorld().updateNeighborsAt(pos, oldState.getBlock()); + if (newState.hasAnalogOutputSignal()) { + getWorld().updateNeighbourForOutputSignal(pos, newState.getBlock()); + } + } + + @Override + public void updateNeighbors(BlockPos pos, BlockState oldState, BlockState newState, int recursionLimit) { + ServerLevel world = getWorld(); + oldState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit); + newState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); + newState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit); + } + + @Override + public void onBlockStateChange(BlockPos pos, BlockState oldState, BlockState newState) { + getWorld().onBlockStateChange(pos, oldState, newState); + } +} diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_10_Impl$1.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_10_Impl$1.class deleted file mode 100644 index 0194fc40b5..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_10_Impl$1.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_10_Impl$SpongeNMSWorld.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_10_Impl$SpongeNMSWorld.class deleted file mode 100644 index 3b24d6c4df..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_10_Impl$SpongeNMSWorld.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_10_Impl$TileEntityBaseBlock.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_10_Impl$TileEntityBaseBlock.class deleted file mode 100644 index 247fa0d3a6..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_10_Impl$TileEntityBaseBlock.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_10_Impl.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_10_Impl.class deleted file mode 100644 index 456c101a41..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_10_Impl.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_2_Impl$1.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_2_Impl$1.class deleted file mode 100644 index 954d9f03a6..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_2_Impl$1.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_2_Impl$SpongeNMSWorld.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_2_Impl$SpongeNMSWorld.class deleted file mode 100644 index ab33bdfa78..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_2_Impl$SpongeNMSWorld.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_2_Impl$TileEntityBaseBlock.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_2_Impl$TileEntityBaseBlock.class deleted file mode 100644 index 05f63946b3..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_2_Impl$TileEntityBaseBlock.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_2_Impl.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_2_Impl.class deleted file mode 100644 index f26ed1ec62..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_2_Impl.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_Impl$1.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_Impl$1.class deleted file mode 100644 index 5b71777263..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_Impl$1.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_Impl$SpongeNMSWorld.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_Impl$SpongeNMSWorld.class deleted file mode 100644 index 4da53c21fa..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_Impl$SpongeNMSWorld.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_Impl$TileEntityBaseBlock.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_Impl$TileEntityBaseBlock.class deleted file mode 100644 index 0f0a4f1e8d..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_Impl$TileEntityBaseBlock.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_Impl.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_Impl.class deleted file mode 100644 index 61273203f1..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_11_Impl.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_1_Impl$1.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_1_Impl$1.class deleted file mode 100644 index 256a056619..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_1_Impl$1.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_1_Impl$SpongeNMSWorld.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_1_Impl$SpongeNMSWorld.class deleted file mode 100644 index 61ce0a7dbb..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_1_Impl$SpongeNMSWorld.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_1_Impl$TileEntityBaseBlock.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_1_Impl$TileEntityBaseBlock.class deleted file mode 100644 index 1c5b4c31ce..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_1_Impl$TileEntityBaseBlock.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_1_Impl.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_1_Impl.class deleted file mode 100644 index cdc162c16a..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_1_Impl.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_2_Impl$1.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_2_Impl$1.class deleted file mode 100644 index cb18d7835a..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_2_Impl$1.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_2_Impl$SpongeNMSWorld.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_2_Impl$SpongeNMSWorld.class deleted file mode 100644 index a684ee39b6..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_2_Impl$SpongeNMSWorld.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_2_Impl$TileEntityBaseBlock.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_2_Impl$TileEntityBaseBlock.class deleted file mode 100644 index 52178975f2..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_2_Impl$TileEntityBaseBlock.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_2_Impl.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_2_Impl.class deleted file mode 100644 index 6ac56f5fb7..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_2_Impl.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_Impl$1.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_Impl$1.class deleted file mode 100644 index d3e8da1147..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_Impl$1.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_Impl$SpongeNMSWorld.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_Impl$SpongeNMSWorld.class deleted file mode 100644 index 69e7875f20..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_Impl$SpongeNMSWorld.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_Impl$TileEntityBaseBlock.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_Impl$TileEntityBaseBlock.class deleted file mode 100644 index 2a5b4e62a6..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_Impl$TileEntityBaseBlock.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_Impl.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_Impl.class deleted file mode 100644 index 45e6a76bf5..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_1_12_Impl.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_Dev_Impl$1.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_Dev_Impl$1.class deleted file mode 100644 index dcd0e9bb1d..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_Dev_Impl$1.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_Dev_Impl$SpongeNMSWorld.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_Dev_Impl$SpongeNMSWorld.class deleted file mode 100644 index 00fad03ee5..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_Dev_Impl$SpongeNMSWorld.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_Dev_Impl$TileEntityBaseBlock.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_Dev_Impl$TileEntityBaseBlock.class deleted file mode 100644 index 8f7f5118a8..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_Dev_Impl$TileEntityBaseBlock.class and /dev/null differ diff --git a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_Dev_Impl.class b/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_Dev_Impl.class deleted file mode 100644 index ad74081357..0000000000 Binary files a/worldedit-sponge/src/main/resources/com/sk89q/worldedit/sponge/adapter/impl/Sponge_Dev_Impl.class and /dev/null differ