From d1af6c38e75e703c808f93c7a55b29429d1f4c4e Mon Sep 17 00:00:00 2001 From: NotMyFault Date: Sat, 5 Jun 2021 10:27:38 +0200 Subject: [PATCH] Update Upstream 9516002 Register platforms and commands in a more proper way (1766) --- .../sk89q/worldedit/bukkit/BukkitPlayer.java | 2 +- .../bukkit/BukkitServerInterface.java | 29 ++-- .../worldedit/bukkit/WorldEditPlugin.java | 73 +++++---- .../com/sk89q/worldedit/cli/CLIPlatform.java | 2 +- .../com/sk89q/worldedit/cli/CLIWorldEdit.java | 2 +- .../event/platform/PlatformEvent.java | 40 +++++ .../event/platform/PlatformReadyEvent.java | 10 +- .../event/platform/PlatformUnreadyEvent.java | 31 ++++ .../platform/PlatformsRegisteredEvent.java | 28 ++++ .../extension/platform/Capability.java | 32 +++- .../extension/platform/Platform.java | 16 +- .../extension/platform/PlatformManager.java | 59 +++++-- .../util/lifecycle/ConstantLifecycled.java | 55 +++++++ .../util/lifecycle/FlatMapLifecycled.java | 80 ++++++++++ .../worldedit/util/lifecycle/Lifecycled.java | 151 ++++++++++++++++++ .../lifecycle/LifecycledCallbackHandler.java | 114 +++++++++++++ .../util/lifecycle/MapLifecycled.java | 82 ++++++++++ .../util/lifecycle/SimpleLifecycled.java | 79 +++++++++ .../sk89q/worldedit/util/lifecycle/Token.java | 33 ++++ .../expression/BaseExpressionTest.java | 12 ++ .../util/collection/BlockMapTest.java | 9 +- 21 files changed, 858 insertions(+), 81 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/PlatformEvent.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/PlatformUnreadyEvent.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/PlatformsRegisteredEvent.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/ConstantLifecycled.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/FlatMapLifecycled.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/Lifecycled.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/LifecycledCallbackHandler.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/MapLifecycled.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/SimpleLifecycled.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/Token.java diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java index 40843a677..e57d3602f 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -328,7 +328,7 @@ public class BukkitPlayer extends AbstractPlayerActor { @Override public void sendAnnouncements() { - if (WorldEditPlugin.getInstance().getBukkitImplAdapter() == null) { + if (WorldEditPlugin.getInstance().getLifecycledBukkitImplAdapter() == null) { print(Caption.of("worldedit.version.bukkit.unsupported-adapter", TextComponent.of("https://intellectualsites.github.io/download/fawe.html", TextColor.AQUA) .clickEvent(ClickEvent.openUrl("https://intellectualsites.github.io/download/fawe.html")))); diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java index 40acebd3e..0704fa221 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java @@ -27,6 +27,7 @@ import com.sk89q.bukkit.util.CommandInfo; import com.sk89q.bukkit.util.CommandRegistration; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.command.util.PermissionCondition; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.AbstractPlatform; @@ -38,6 +39,7 @@ import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.util.lifecycle.Lifecycled; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.registry.Registries; import org.apache.logging.log4j.Logger; @@ -67,22 +69,17 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser public final Server server; public final WorldEditPlugin plugin; private final CommandRegistration dynamicCommands; - private final LazyReference watchdog; - private final RelighterFactory religherFactory; + private final Lifecycled watchdog; + private final RelighterFactory relighterFactory; private boolean hookingEvents; public BukkitServerInterface(WorldEditPlugin plugin, Server server) { this.plugin = plugin; this.server = server; this.dynamicCommands = new CommandRegistration(plugin); - this.watchdog = LazyReference.from(() -> { - if (plugin.getBukkitImplAdapter() != null) { - return plugin.getBukkitImplAdapter().supportsWatchdog() - ? new BukkitWatchdog(plugin.getBukkitImplAdapter()) - : null; - } - return null; - }); + this.watchdog = plugin.getLifecycledBukkitImplAdapter() + .filter(BukkitImplAdapter::supportsWatchdog) + .map(BukkitWatchdog::new); RelighterFactory tempFactory; try { Class.forName("com.tuinity.tuinity.config.TuinityConfig"); @@ -92,7 +89,7 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser tempFactory = new NMSRelighterFactory(); LOGGER.info("Using FAWE for relighting"); } - this.religherFactory = tempFactory; + this.relighterFactory = tempFactory; } CommandRegistration getDynamicCommands() { @@ -111,7 +108,7 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser @SuppressWarnings("deprecation") @Override public int getDataVersion() { - if (plugin.getBukkitImplAdapter() != null) { + if (plugin.getLifecycledBukkitImplAdapter() != null) { return Bukkit.getUnsafe().getDataVersion(); } return -1; @@ -147,7 +144,7 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser @Override public Watchdog getWatchdog() { - return watchdog.getValue(); + return watchdog.valueOrThrow(); } @Override @@ -208,8 +205,8 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser } @Override - public void registerGameHooks() { - hookingEvents = true; + public void setGameHooksEnabled(boolean enabled) { + this.hookingEvents = enabled; } @Override @@ -265,7 +262,7 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser @Override public @NotNull RelighterFactory getRelighterFactory() { - return this.religherFactory; + return this.relighterFactory; } public void unregisterCommands() { diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java index 475989740..d6f9a549d 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java @@ -37,6 +37,8 @@ import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R3; 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.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Platform; @@ -44,6 +46,8 @@ import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.internal.anvil.ChunkDeleter; import com.sk89q.worldedit.internal.command.CommandUtil; import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.util.lifecycle.Lifecycled; +import com.sk89q.worldedit.util.lifecycle.SimpleLifecycled; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockCategory; import com.sk89q.worldedit.world.entity.EntityType; @@ -69,7 +73,6 @@ import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.metadata.MetadataValue; import org.bukkit.plugin.java.JavaPlugin; import org.incendo.serverlib.ServerLib; -import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.FileNotFoundException; @@ -94,9 +97,11 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter private static final Logger LOGGER = LogManagerCompat.getLogger(); public static final String CUI_PLUGIN_CHANNEL = "worldedit:cui"; private static WorldEditPlugin INSTANCE; + private static final int BSTATS_ID = 1403; - private BukkitImplAdapter bukkitAdapter; - private BukkitServerInterface server; + private final SimpleLifecycled adapter = + SimpleLifecycled.invalid(); + private BukkitServerInterface platform; private BukkitConfiguration config; private BukkitPermissionAttachmentManager permissionAttachmentManager; @@ -110,8 +115,12 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter WorldEdit worldEdit = WorldEdit.getInstance(); // Setup platform - server = new BukkitServerInterface(this, getServer()); - worldEdit.getPlatformManager().register(server); + platform = new BukkitServerInterface(this, getServer()); + worldEdit.getPlatformManager().register(platform); + + createDefaultConfiguration("config-legacy.yml"); // Create the default configuration file for WorldEdit, for it's config-legacy.yml + + config = new BukkitConfiguration(new YAMLProcessor(new File(getDataFolder(), "config-legacy.yml"), true), this); permissionAttachmentManager = new BukkitPermissionAttachmentManager(this); @@ -139,6 +148,8 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter new FaweBukkit(this); + WorldEdit.getInstance().getEventBus().post(new PlatformsRegisteredEvent()); + PermissionsResolverManager.initialize(this); // Setup permission resolver // Register CUI @@ -171,7 +182,7 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter } // Setup metrics - new Metrics(this, 1403); + new Metrics(this, BSTATS_ID); // Check whether the server runs on 11 or greater ServerLib.checkJavaLTS(); @@ -181,14 +192,15 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter private void setupPreWorldData() { loadAdapter(); - loadConfig(); + config.load(); WorldEdit.getInstance().loadMappings(); } private void setupWorldData() { - setupTags(); // datapacks aren't loaded until just before the world is, and bukkit has no event for this + // datapacks aren't loaded until just before the world is, and bukkit has no event for this // so the earliest we can do this is in WorldInit - WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); + setupTags(); + WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent(platform)); } @SuppressWarnings({ "deprecation", "unchecked" }) @@ -196,11 +208,7 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter // Biome for (Biome biome : Biome.values()) { String lowerCaseBiomeName = biome.name().toLowerCase(Locale.ROOT); - BiomeType biomeType = BiomeType.REGISTRY.register( - "minecraft:" + lowerCaseBiomeName, new BiomeType("minecraft:" + lowerCaseBiomeName)); - if (bukkitAdapter != null) { - biomeType.setLegacyId(bukkitAdapter.getInternalBiomeId(biomeType)); - } + BiomeType.REGISTRY.register("minecraft:" + lowerCaseBiomeName, new BiomeType("minecraft:" + lowerCaseBiomeName)); } /* @@ -271,17 +279,6 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter } } - private void loadConfig() { - createDefaultConfiguration("config-legacy.yml"); // Create the default configuration file - - config = new BukkitConfiguration(new YAMLProcessor(new File(getDataFolder(), "config-legacy.yml"), true), this); - config.load(); - // Create schematics folder - WorldEdit worldEdit = WorldEdit.getInstance(); - File dir = worldEdit.getWorkingDirectoryPath(worldEdit.getConfiguration().saveDir).toFile(); - dir.mkdirs(); - } - private void loadAdapter() { WorldEdit worldEdit = WorldEdit.getInstance(); @@ -308,17 +305,19 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter LOGGER.warn("Failed to search " + getFile() + " for Bukkit adapters", e); } try { - bukkitAdapter = adapterLoader.loadAdapter(); + BukkitImplAdapter bukkitAdapter = adapterLoader.loadAdapter(); LOGGER.info("Using " + bukkitAdapter.getClass().getCanonicalName() + " as the Bukkit adapter"); + this.adapter.newValue(bukkitAdapter); } catch (AdapterLoadException e) { Platform platform = worldEdit.getPlatformManager().queryCapability(Capability.WORLD_EDITING); if (platform instanceof BukkitServerInterface) { LOGGER.warn(e.getMessage()); } else { - LOGGER.info("WorldEdit could not find a Bukkit adapter for this MC version, " - + "but it seems that you have another implementation of WorldEdit installed (" + platform.getPlatformName() + ") " + LOGGER.info("FastAsyncWorldEdit could not find a Bukkit adapter for this MC version, " + + "but it seems that you have another implementation of FastAsyncWorldEdit installed (" + platform.getPlatformName() + ") " + "that handles the world editing."); } + this.adapter.invalidate(); } } @@ -330,13 +329,14 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter Fawe.get().onDisable(); WorldEdit worldEdit = WorldEdit.getInstance(); worldEdit.getSessionManager().unload(); - worldEdit.getPlatformManager().unregister(server); + if (platform != null) { + worldEdit.getEventBus().post(new PlatformUnreadyEvent(platform)); + worldEdit.getPlatformManager().unregister(platform); + platform.unregisterCommands(); + } if (config != null) { config.unload(); } - if (server != null) { - server.unregisterCommands(); - } this.getServer().getScheduler().cancelTasks(this); } @@ -526,7 +526,7 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter } public BukkitServerInterface getInternalPlatform() { - return server; + return platform; } /** @@ -553,9 +553,12 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter * * @return the adapter */ - @Nullable + Lifecycled getLifecycledBukkitImplAdapter() { + return adapter; + } + public BukkitImplAdapter getBukkitImplAdapter() { - return bukkitAdapter; + return adapter.value().orElse(null); } private class WorldInitListener implements Listener { diff --git a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIPlatform.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIPlatform.java index e762d6b4d..530e58dbd 100644 --- a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIPlatform.java +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIPlatform.java @@ -124,7 +124,7 @@ class CLIPlatform extends AbstractPlatform { } @Override - public void registerGameHooks() { + public void setGameHooksEnabled(boolean enabled) { } @Override diff --git a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIWorldEdit.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIWorldEdit.java index 1413553dd..2b1117058 100644 --- a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIWorldEdit.java +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIWorldEdit.java @@ -175,7 +175,7 @@ public class CLIWorldEdit { config = new CLIConfiguration(this); config.load(); - WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); + WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent(platform)); } public void onStopped() { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/PlatformEvent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/PlatformEvent.java new file mode 100644 index 000000000..261b78ae0 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/PlatformEvent.java @@ -0,0 +1,40 @@ +/* + * 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.event.platform; + +import com.sk89q.worldedit.event.Event; +import com.sk89q.worldedit.extension.platform.Platform; + +public abstract class PlatformEvent extends Event { + private final Platform platform; + + protected PlatformEvent(Platform platform) { + this.platform = platform; + } + + /** + * Get the platform for this event. + * + * @return the platform + */ + public Platform getPlatform() { + return platform; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/PlatformReadyEvent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/PlatformReadyEvent.java index 0e3042dcc..7ae072ae5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/PlatformReadyEvent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/PlatformReadyEvent.java @@ -19,11 +19,13 @@ package com.sk89q.worldedit.event.platform; -import com.sk89q.worldedit.event.Event; +import com.sk89q.worldedit.extension.platform.Platform; /** - * Raised when a platform thinks that all the platforms have had a chance to - * register themselves. + * Raised when a platform has finished loading its data. */ -public class PlatformReadyEvent extends Event { +public class PlatformReadyEvent extends PlatformEvent { + public PlatformReadyEvent(Platform platform) { + super(platform); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/PlatformUnreadyEvent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/PlatformUnreadyEvent.java new file mode 100644 index 000000000..25930e6b7 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/PlatformUnreadyEvent.java @@ -0,0 +1,31 @@ +/* + * 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.event.platform; + +import com.sk89q.worldedit.extension.platform.Platform; + +/** + * Raised when a platform needs to retract all registered data, e.g. due to a reload. + */ +public class PlatformUnreadyEvent extends PlatformEvent { + public PlatformUnreadyEvent(Platform platform) { + super(platform); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/PlatformsRegisteredEvent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/PlatformsRegisteredEvent.java new file mode 100644 index 000000000..8eac2569f --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/PlatformsRegisteredEvent.java @@ -0,0 +1,28 @@ +/* + * 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.event.platform; + +import com.sk89q.worldedit.event.Event; + +/** + * Fired by a platform when it believes all available platforms should be registered. + */ +public class PlatformsRegisteredEvent extends Event { +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java index be0305d2e..f74018324 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.extension.platform; +import com.sk89q.worldedit.WorldEdit; + /** * A collection of capabilities that a {@link Platform} may support. */ @@ -31,11 +33,12 @@ public enum Capability { GAME_HOOKS { @Override void initialize(PlatformManager platformManager, Platform platform) { - platform.registerGameHooks(); + platform.setGameHooksEnabled(true); } @Override - void unload(PlatformManager platformManager, Platform platform) { + void uninitialize(PlatformManager platformManager, Platform platform) { + platform.setGameHooksEnabled(false); } }, @@ -54,7 +57,7 @@ public enum Capability { } @Override - void unload(PlatformManager platformManager, Platform platform) { + void uninitialize(PlatformManager platformManager, Platform platform) { platformManager.getPlatformCommandManager().removeCommands(); } }, @@ -76,7 +79,7 @@ public enum Capability { WORLD_EDITING { /* @Override - void initialize(PlatformManager platformManager, Platform platform) { + void ready(PlatformManager platformManager, Platform platform) { BlockRegistry blockRegistry = platform.getRegistries().getBlockRegistry(); for (BlockType type : BlockType.REGISTRY) { for (BlockState state : type.getAllStates()) { @@ -86,18 +89,35 @@ public enum Capability { } @Override - void unload(PlatformManager platformManager, Platform platform) { + void unready(PlatformManager platformManager, Platform platform) { BlockStateIdAccess.clear(); } */ }; + /** + * Initialize platform-wide state. + */ void initialize(PlatformManager platformManager, Platform platform) { } - void unload(PlatformManager platformManager, Platform platform) { + /** + * Un-initialize platform-wide state. + */ + void uninitialize(PlatformManager platformManager, Platform platform) { + } + /** + * Initialize per-level state. + */ + void ready(PlatformManager platformManager, Platform platform) { + } + + /** + * Un-initialize per-level state. + */ + void unready(PlatformManager platformManager, Platform platform) { } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java index d3051e17b..1a93237fb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java @@ -138,14 +138,28 @@ public interface Platform extends Keyed { /** * Register the commands contained within the given command manager. * + *

+ * This method should be ignored if the platform offers a command registration event. + *

+ * * @param commandManager the command manager */ void registerCommands(CommandManager commandManager); /** * Register game hooks. + * + * @deprecated Call {@link #setGameHooksEnabled(boolean)} with {@code true} instead */ - void registerGameHooks(); + @Deprecated + default void registerGameHooks() { + setGameHooksEnabled(true); + } + + /** + * Set if the game hooks are enabled for this platform. + */ + void setGameHooksEnabled(boolean enabled); /** * Get the configuration from this platform. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java index 5cf46afb7..a45bd567f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java @@ -40,6 +40,8 @@ import com.sk89q.worldedit.event.platform.ConfigurationLoadEvent; import com.sk89q.worldedit.event.platform.Interaction; import com.sk89q.worldedit.event.platform.PlatformInitializeEvent; 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.PlayerInputEvent; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.Vector3; @@ -145,7 +147,7 @@ public class PlatformManager { while (it.hasNext()) { Entry entry = it.next(); if (entry.getValue().equals(platform)) { - entry.getKey().unload(this, entry.getValue()); + entry.getKey().uninitialize(this, entry.getValue()); it.remove(); choosePreferred = true; // Have to choose new favorites } @@ -160,8 +162,7 @@ public class PlatformManager { } /** - * Get the preferred platform for handling a certain capability. Returns - * null if none is available. + * Get the preferred platform for handling a certain capability. Throws if none are available. * * @param capability the capability * @return the platform @@ -173,12 +174,11 @@ public class PlatformManager { return platform; } else { if (preferences.isEmpty()) { - // Use the first available if preferences have not been decided yet. - if (platforms.isEmpty()) { - // No platforms registered, this is being called too early! - throw new NoCapablePlatformException("No platforms have been registered yet! Please wait until WorldEdit is initialized."); - } - return platforms.get(0); + // Not all platforms registered, this is being called too early! + throw new NoCapablePlatformException( + "Not all platforms have been registered yet!" + + " Please wait until FastAsyncWorldEdit is initialized." + ); } throw new NoCapablePlatformException("No platform was found supporting " + capability.name()); } @@ -191,8 +191,15 @@ public class PlatformManager { for (Capability capability : Capability.values()) { Platform preferred = findMostPreferred(capability); if (preferred != null) { - preferences.put(capability, preferred); - capability.initialize(this, preferred); + Platform oldPreferred = preferences.put(capability, preferred); + // only (re)initialize if it changed + if (preferred != oldPreferred) { + // uninitialize if needed + if (oldPreferred != null) { + capability.uninitialize(this, oldPreferred); + } + capability.initialize(this, preferred); + } } } @@ -311,14 +318,42 @@ public class PlatformManager { return queryCapability(Capability.WORLD_EDITING).getSupportedSideEffects(); } + /** + * You shouldn't have been calling this anyways, but this is now deprecated. Either don't + * fire this event at all, or fire the new event via the event bus if you're a platform. + */ + @Deprecated + public void handlePlatformReady(@SuppressWarnings("unused") PlatformReadyEvent event) { + handlePlatformsRegistered(new PlatformsRegisteredEvent()); + } + + /** + * Internal, do not call. + */ @Subscribe - public void handlePlatformReady(PlatformReadyEvent event) { + public void handlePlatformsRegistered(PlatformsRegisteredEvent event) { choosePreferred(); if (initialized.compareAndSet(false, true)) { worldEdit.getEventBus().post(new PlatformInitializeEvent()); } } + /** + * Internal, do not call. + */ + @Subscribe + public void handleNewPlatformReady(PlatformReadyEvent event) { + preferences.forEach((cap, platform) -> cap.ready(this, platform)); + } + + /** + * Internal, do not call. + */ + @Subscribe + public void handleNewPlatformUnready(PlatformUnreadyEvent event) { + preferences.forEach((cap, platform) -> cap.unready(this, platform)); + } + private T reset(T tool) { new PatternTraverser(tool).reset(null); return tool; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/ConstantLifecycled.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/ConstantLifecycled.java new file mode 100644 index 000000000..41cb21022 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/ConstantLifecycled.java @@ -0,0 +1,55 @@ +/* + * 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.util.lifecycle; + +import java.util.Objects; +import java.util.Optional; +import java.util.function.BiConsumer; + +/** + * A {@link Lifecycled} that never invalidates. + */ +public final class ConstantLifecycled implements Lifecycled { + private final T value; + + public ConstantLifecycled(T value) { + this.value = Objects.requireNonNull(value); + } + + @Override + public Optional value() { + return Optional.of(value); + } + + @Override + public Events events() { + // Simple implementation, we just need to call onNewValue + return new Events() { + @Override + public void onNewValue(O owner, BiConsumer> callback) { + callback.accept(owner, ConstantLifecycled.this); + } + + @Override + public void onInvalidated(O owner, BiConsumer> callback) { + } + }; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/FlatMapLifecycled.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/FlatMapLifecycled.java new file mode 100644 index 000000000..9c0fd63d8 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/FlatMapLifecycled.java @@ -0,0 +1,80 @@ +/* + * 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.util.lifecycle; + +import java.util.Optional; +import java.util.function.Function; +import javax.annotation.Nullable; + +class FlatMapLifecycled implements Lifecycled { + private final LifecycledCallbackHandler events = new LifecycledCallbackHandler<>(this); + private Lifecycled mapped; + private Token> mappedToken; + @Nullable + private U value; + + FlatMapLifecycled(Lifecycled upstream, Function> mapper) { + upstream.events().onInvalidated(this, (this$, up) -> { + boolean fire = this$.value != null; + this$.value = null; + // drop `mapped` hooks if needed + this$.mappedToken = null; + this$.mapped = null; + if (fire) { + this$.events.fireInvalidated(); + } + }); + upstream.events().onNewValue(this, (this$, up) -> { + this$.mapped = mapper.apply(up.valueOrThrow()); + this$.mappedToken = new Token<>(this$); + mapped.events().onInvalidated(this$.mappedToken, (token, mapped$) -> { + boolean fire = token.inner.value != null; + token.inner.value = null; + // note we do not drop the token here, onNewValue may be called again + if (fire) { + this$.events.fireInvalidated(); + } + }); + mapped.events().onNewValue(this$.mappedToken, (token, mapped$) -> { + U newValue = mapped$.valueOrThrow(); + boolean fire = token.inner.value != newValue; + token.inner.value = newValue; + if (fire) { + this$.events.fireOnNewValue(); + } + }); + }); + } + + @Override + public Optional value() { + return Optional.ofNullable(value); + } + + @Override + public boolean isValid() { + return value != null; + } + + @Override + public Events events() { + return events; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/Lifecycled.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/Lifecycled.java new file mode 100644 index 000000000..d9d2c7f49 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/Lifecycled.java @@ -0,0 +1,151 @@ +/* + * 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.util.lifecycle; + +import java.util.Optional; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * Represents an object with a simple valid/invalid lifecycle. + * + *

+ * A lifecycled object will start with no value, then trigger + * {@link Events#onNewValue(Object, BiConsumer)} callbacks when it gets one, and + * {@link Events#onInvalidated(Object, BiConsumer)} callbacks when it loses it. A full + * invalidated->new value cycle is called a "reload". + *

+ * + *

+ * Downstream lifecycled objects can be derived using functional methods, and share some + * common rules. They will apply the operation sometime before the result is needed, either + * eagerly or lazily. They will re-do the operation after the upstream {@link Lifecycled} is + * reloaded. + *

+ * + *

+ * Unless specified, {@link Lifecycled} objects are not thread-safe. However, the + * {@link Events} objects are, and callbacks may be added from any thread. + *

+ * + * @param the value type + */ +public interface Lifecycled { + + interface Events { + /** + * Add a callback for when this lifecycled is given a new value. Will be called immediately + * if this lifecycled is currently valid. + * + *

+ * The callback should not reference the owner, it must only access it via the parameter. + * This ensures that the owner will be GC-able, otherwise it may be stuck in a reference + * loop. + *

+ * + * @param owner when the owner is GC'd, the callback is removed + * @param callback the callback, will be passed the lifecycled object + */ + void onNewValue(O owner, BiConsumer> callback); + + /** + * Add a callback for when this lifecycled is invalidated. Will be called immediately if + * this lifecycled is currently invalid. + * + *

+ * The callback should not reference the owner, it must only access it via the parameter. + * This ensures that the owner will be GC-able, otherwise it may be stuck in a reference + * loop. + *

+ * + * @param owner when the owner is GC'd, the callback is removed + * @param callback the callback, will be passed the lifecycled object + */ + void onInvalidated(O owner, BiConsumer> callback); + } + + /** + * Get the value or {@link Optional#empty()}. + * + * @return the value + */ + Optional value(); + + /** + * Get the value or throw. + * + * @return the value + * @throws IllegalStateException if there is no value + */ + default T valueOrThrow() throws IllegalStateException { + return value().orElseThrow(() -> new IllegalStateException("Currently invalid")); + } + + /** + * Check for validity, usually without triggering computation. + * + * @return if this lifecycled's {@link #value()} is valid + */ + default boolean isValid() { + return value().isPresent(); + } + + /** + * Get the event manager for this lifecycled object. + * + * @return the event manager + */ + Events events(); + + /** + * Map the value. + * + * @param mapper the mapper function + * @param the new type + * @return the downstream lifecycled + */ + default Lifecycled map(Function mapper) { + return new MapLifecycled<>(this, mapper); + } + + /** + * Filter the value. In other words, create a new lifecycled object where validity is ANDed + * with the result of calling the filter function. + * + * @param filterer the filter function + * @return the downstream lifecycled + */ + default Lifecycled filter(Predicate filterer) { + SimpleLifecycled downstream = SimpleLifecycled.invalid(); + events().onInvalidated(downstream, (d, lifecycled) -> d.invalidate()); + events().onNewValue(downstream, (d, lifecycled) -> { + T value = lifecycled.valueOrThrow(); + if (filterer.test(value)) { + d.newValue(value); + } + }); + return downstream; + } + + default Lifecycled flatMap(Function> mapper) { + return new FlatMapLifecycled<>(this, mapper); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/LifecycledCallbackHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/LifecycledCallbackHandler.java new file mode 100644 index 000000000..f4181de80 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/LifecycledCallbackHandler.java @@ -0,0 +1,114 @@ +/* + * 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.util.lifecycle; + +import java.util.Map; +import java.util.WeakHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.BiConsumer; + +/** + * Convenience class for implementing the callbacks of {@link Lifecycled}. + */ +public class LifecycledCallbackHandler implements Lifecycled.Events { + private final Lifecycled lifecycled; + private final Lock lock = new ReentrantLock(); + private final Map>> onInvalidatedCallbacks = + new WeakHashMap<>(); + private final Map>> onNewValueCallbacks = + new WeakHashMap<>(); + + public LifecycledCallbackHandler(Lifecycled lifecycled) { + this.lifecycled = lifecycled; + } + + @Override + public void onInvalidated(O owner, BiConsumer> callback) { + lock.lock(); + try { + onInvalidatedCallbacks.put(owner, callback); + if (!lifecycled.isValid()) { + callback.accept(owner, lifecycled); + } + } finally { + lock.unlock(); + } + } + + @Override + public void onNewValue(O owner, BiConsumer> callback) { + lock.lock(); + try { + onNewValueCallbacks.put(owner, callback); + if (lifecycled.isValid()) { + callback.accept(owner, lifecycled); + } + } finally { + lock.unlock(); + } + } + + + /** + * Fire {@link #onInvalidated(Object, BiConsumer)} callbacks. + */ + public void fireInvalidated() { + lock.lock(); + try { + for (Map.Entry>> callback : onInvalidatedCallbacks.entrySet()) { + Object owner = callback.getKey(); + if (owner == null) { + // GC'd, continue + continue; + } + @SuppressWarnings("unchecked") + BiConsumer> cast = + (BiConsumer>) callback.getValue(); + cast.accept(owner, lifecycled); + } + } finally { + lock.unlock(); + } + } + + /** + * Fire {@link #onNewValue(Object, BiConsumer)} callbacks, the {@link Lifecycled#value()} must + * be available. + */ + public void fireOnNewValue() { + lock.lock(); + try { + for (Map.Entry>> callback : onNewValueCallbacks.entrySet()) { + Object owner = callback.getKey(); + if (owner == null) { + // GC'd, continue + continue; + } + @SuppressWarnings("unchecked") + BiConsumer> cast = + (BiConsumer>) callback.getValue(); + cast.accept(owner, lifecycled); + } + } finally { + lock.unlock(); + } + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/MapLifecycled.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/MapLifecycled.java new file mode 100644 index 000000000..a7ed07bb8 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/MapLifecycled.java @@ -0,0 +1,82 @@ +/* + * 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.util.lifecycle; + +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; +import javax.annotation.Nullable; + +class MapLifecycled implements Lifecycled { + private final LifecycledCallbackHandler events = new LifecycledCallbackHandler<>(this); + private final Lifecycled upstream; + private final Function mapper; + @Nullable + private U cache; + private boolean computable; + + MapLifecycled(Lifecycled upstream, Function mapper) { + this.upstream = upstream; + this.mapper = mapper; + upstream.events().onInvalidated(this, (this$, __) -> { + boolean fire = this$.computable; + this$.cache = null; + this$.computable = false; + if (fire) { + this$.events.fireInvalidated(); + } + }); + upstream.events().onNewValue(this, (this$, __) -> { + boolean fire = !this$.computable; + this$.computable = true; + if (fire) { + this$.events.fireOnNewValue(); + } + }); + } + + private void compute() { + T value = upstream.value().orElseThrow(() -> + new AssertionError("Upstream lost value without calling onInvalidated event") + ); + this.cache = Objects.requireNonNull(mapper.apply(value), "Mapper cannot produce null"); + } + + @Override + public Optional value() { + if (!computable) { + return Optional.empty(); + } + if (cache == null) { + compute(); + } + return Optional.of(cache); + } + + @Override + public boolean isValid() { + return computable; + } + + @Override + public Events events() { + return events; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/SimpleLifecycled.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/SimpleLifecycled.java new file mode 100644 index 000000000..2c97d4850 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/SimpleLifecycled.java @@ -0,0 +1,79 @@ +/* + * 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.util.lifecycle; + +import java.util.Objects; +import java.util.Optional; +import javax.annotation.Nullable; + +/** + * A {@link Lifecycled} that can be directly called to {@linkplain #invalidate() invalidate} it or + * set a {@linkplain #newValue(Object) new value}. + */ +public final class SimpleLifecycled implements Lifecycled { + public static SimpleLifecycled valid(T value) { + return new SimpleLifecycled<>(Objects.requireNonNull(value)); + } + + public static SimpleLifecycled invalid() { + return new SimpleLifecycled<>(null); + } + + private final LifecycledCallbackHandler events = new LifecycledCallbackHandler<>(this); + @Nullable + private T value; + + private SimpleLifecycled(@Nullable T value) { + this.value = value; + } + + /** + * Set the value of this lifecycled and fire the new value event. + * + * @param value the value + */ + public void newValue(T value) { + // Ensure lifecycle constraints are upheld. + invalidate(); + this.value = Objects.requireNonNull(value); + events.fireOnNewValue(); + } + + /** + * Remove the value of this lifecycled and fire the invalidated event. + */ + public void invalidate() { + boolean fire = this.value != null; + this.value = null; + if (fire) { + events.fireInvalidated(); + } + } + + @Override + public Optional value() { + return Optional.ofNullable(value); + } + + @Override + public Events events() { + return events; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/Token.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/Token.java new file mode 100644 index 000000000..b721ec87c --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/lifecycle/Token.java @@ -0,0 +1,33 @@ +/* + * 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.util.lifecycle; + +/** + * Used to create a new strong reference to an object that can be separately dropped. + * + * @param the inner object + */ +class Token { + final T inner; + + Token(T inner) { + this.inner = inner; + } +} diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/BaseExpressionTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/BaseExpressionTest.java index ca398001b..5e22fbf00 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/BaseExpressionTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/BaseExpressionTest.java @@ -21,10 +21,17 @@ package com.sk89q.worldedit.internal.expression; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.event.platform.PlatformsRegisteredEvent; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extension.platform.Preference; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -42,12 +49,17 @@ class BaseExpressionTest { @BeforeEach void setup() { + when(mockPlat.getCapabilities()).thenReturn( + Stream.of(Capability.values()) + .collect(Collectors.toMap(Function.identity(), __ -> Preference.NORMAL)) + ); when(mockPlat.getConfiguration()).thenReturn(new LocalConfiguration() { @Override public void load() { } }); WorldEdit.getInstance().getPlatformManager().register(mockPlat); + WorldEdit.getInstance().getEventBus().post(new PlatformsRegisteredEvent()); WorldEdit.getInstance().getConfiguration().calculationTimeout = 1_000; } diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/util/collection/BlockMapTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/util/collection/BlockMapTest.java index a9bc368e2..ac2a8048e 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/util/collection/BlockMapTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/util/collection/BlockMapTest.java @@ -30,12 +30,13 @@ class BlockMapTest { static void setupFakePlatform() { when(MOCKED_PLATFORM.getRegistries()).thenReturn(new BundledRegistries() { }); - when(MOCKED_PLATFORM.getCapabilities()).thenReturn(ImmutableMap.of( - Capability.WORLD_EDITING, Preference.PREFERRED, - Capability.GAME_HOOKS, Preference.PREFERRED - )); + when(MOCKED_PLATFORM.getCapabilities()).thenReturn( + Stream.of(Capability.values()) + .collect(Collectors.toMap(Function.identity(), __ -> Preference.NORMAL)) + ); PlatformManager platformManager = WorldEdit.getInstance().getPlatformManager(); platformManager.register(MOCKED_PLATFORM); + WorldEdit.getInstance().getEventBus().post(new PlatformsRegisteredEvent()); registerBlock("minecraft:air"); registerBlock("minecraft:oak_wood");