mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-12-22 17:27:38 +00:00
Update Upstream
9516002 Register platforms and commands in a more proper way (1766)
This commit is contained in:
parent
f139088b6e
commit
d1af6c38e7
@ -328,7 +328,7 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendAnnouncements() {
|
public void sendAnnouncements() {
|
||||||
if (WorldEditPlugin.getInstance().getBukkitImplAdapter() == null) {
|
if (WorldEditPlugin.getInstance().getLifecycledBukkitImplAdapter() == null) {
|
||||||
print(Caption.of("worldedit.version.bukkit.unsupported-adapter",
|
print(Caption.of("worldedit.version.bukkit.unsupported-adapter",
|
||||||
TextComponent.of("https://intellectualsites.github.io/download/fawe.html", TextColor.AQUA)
|
TextComponent.of("https://intellectualsites.github.io/download/fawe.html", TextColor.AQUA)
|
||||||
.clickEvent(ClickEvent.openUrl("https://intellectualsites.github.io/download/fawe.html"))));
|
.clickEvent(ClickEvent.openUrl("https://intellectualsites.github.io/download/fawe.html"))));
|
||||||
|
@ -27,6 +27,7 @@ import com.sk89q.bukkit.util.CommandInfo;
|
|||||||
import com.sk89q.bukkit.util.CommandRegistration;
|
import com.sk89q.bukkit.util.CommandRegistration;
|
||||||
import com.sk89q.worldedit.LocalConfiguration;
|
import com.sk89q.worldedit.LocalConfiguration;
|
||||||
import com.sk89q.worldedit.WorldEdit;
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
|
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||||
import com.sk89q.worldedit.command.util.PermissionCondition;
|
import com.sk89q.worldedit.command.util.PermissionCondition;
|
||||||
import com.sk89q.worldedit.entity.Player;
|
import com.sk89q.worldedit.entity.Player;
|
||||||
import com.sk89q.worldedit.extension.platform.AbstractPlatform;
|
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.internal.util.LogManagerCompat;
|
||||||
import com.sk89q.worldedit.util.SideEffect;
|
import com.sk89q.worldedit.util.SideEffect;
|
||||||
import com.sk89q.worldedit.util.concurrency.LazyReference;
|
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.DataFixer;
|
||||||
import com.sk89q.worldedit.world.registry.Registries;
|
import com.sk89q.worldedit.world.registry.Registries;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
@ -67,22 +69,17 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
|
|||||||
public final Server server;
|
public final Server server;
|
||||||
public final WorldEditPlugin plugin;
|
public final WorldEditPlugin plugin;
|
||||||
private final CommandRegistration dynamicCommands;
|
private final CommandRegistration dynamicCommands;
|
||||||
private final LazyReference<Watchdog> watchdog;
|
private final Lifecycled<Watchdog> watchdog;
|
||||||
private final RelighterFactory religherFactory;
|
private final RelighterFactory relighterFactory;
|
||||||
private boolean hookingEvents;
|
private boolean hookingEvents;
|
||||||
|
|
||||||
public BukkitServerInterface(WorldEditPlugin plugin, Server server) {
|
public BukkitServerInterface(WorldEditPlugin plugin, Server server) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.dynamicCommands = new CommandRegistration(plugin);
|
this.dynamicCommands = new CommandRegistration(plugin);
|
||||||
this.watchdog = LazyReference.from(() -> {
|
this.watchdog = plugin.getLifecycledBukkitImplAdapter()
|
||||||
if (plugin.getBukkitImplAdapter() != null) {
|
.filter(BukkitImplAdapter::supportsWatchdog)
|
||||||
return plugin.getBukkitImplAdapter().supportsWatchdog()
|
.map(BukkitWatchdog::new);
|
||||||
? new BukkitWatchdog(plugin.getBukkitImplAdapter())
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
RelighterFactory tempFactory;
|
RelighterFactory tempFactory;
|
||||||
try {
|
try {
|
||||||
Class.forName("com.tuinity.tuinity.config.TuinityConfig");
|
Class.forName("com.tuinity.tuinity.config.TuinityConfig");
|
||||||
@ -92,7 +89,7 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
|
|||||||
tempFactory = new NMSRelighterFactory();
|
tempFactory = new NMSRelighterFactory();
|
||||||
LOGGER.info("Using FAWE for relighting");
|
LOGGER.info("Using FAWE for relighting");
|
||||||
}
|
}
|
||||||
this.religherFactory = tempFactory;
|
this.relighterFactory = tempFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandRegistration getDynamicCommands() {
|
CommandRegistration getDynamicCommands() {
|
||||||
@ -111,7 +108,7 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
|
|||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
@Override
|
@Override
|
||||||
public int getDataVersion() {
|
public int getDataVersion() {
|
||||||
if (plugin.getBukkitImplAdapter() != null) {
|
if (plugin.getLifecycledBukkitImplAdapter() != null) {
|
||||||
return Bukkit.getUnsafe().getDataVersion();
|
return Bukkit.getUnsafe().getDataVersion();
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
@ -147,7 +144,7 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Watchdog getWatchdog() {
|
public Watchdog getWatchdog() {
|
||||||
return watchdog.getValue();
|
return watchdog.valueOrThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -208,8 +205,8 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerGameHooks() {
|
public void setGameHooksEnabled(boolean enabled) {
|
||||||
hookingEvents = true;
|
this.hookingEvents = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -265,7 +262,7 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull RelighterFactory getRelighterFactory() {
|
public @NotNull RelighterFactory getRelighterFactory() {
|
||||||
return this.religherFactory;
|
return this.relighterFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unregisterCommands() {
|
public void unregisterCommands() {
|
||||||
|
@ -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.CommandEvent;
|
||||||
import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
|
import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
|
||||||
import com.sk89q.worldedit.event.platform.PlatformReadyEvent;
|
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.Actor;
|
||||||
import com.sk89q.worldedit.extension.platform.Capability;
|
import com.sk89q.worldedit.extension.platform.Capability;
|
||||||
import com.sk89q.worldedit.extension.platform.Platform;
|
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.anvil.ChunkDeleter;
|
||||||
import com.sk89q.worldedit.internal.command.CommandUtil;
|
import com.sk89q.worldedit.internal.command.CommandUtil;
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
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.biome.BiomeType;
|
||||||
import com.sk89q.worldedit.world.block.BlockCategory;
|
import com.sk89q.worldedit.world.block.BlockCategory;
|
||||||
import com.sk89q.worldedit.world.entity.EntityType;
|
import com.sk89q.worldedit.world.entity.EntityType;
|
||||||
@ -69,7 +73,6 @@ import org.bukkit.metadata.FixedMetadataValue;
|
|||||||
import org.bukkit.metadata.MetadataValue;
|
import org.bukkit.metadata.MetadataValue;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.incendo.serverlib.ServerLib;
|
import org.incendo.serverlib.ServerLib;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
@ -94,9 +97,11 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
|
|||||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||||
public static final String CUI_PLUGIN_CHANNEL = "worldedit:cui";
|
public static final String CUI_PLUGIN_CHANNEL = "worldedit:cui";
|
||||||
private static WorldEditPlugin INSTANCE;
|
private static WorldEditPlugin INSTANCE;
|
||||||
|
private static final int BSTATS_ID = 1403;
|
||||||
|
|
||||||
private BukkitImplAdapter bukkitAdapter;
|
private final SimpleLifecycled<BukkitImplAdapter> adapter =
|
||||||
private BukkitServerInterface server;
|
SimpleLifecycled.invalid();
|
||||||
|
private BukkitServerInterface platform;
|
||||||
private BukkitConfiguration config;
|
private BukkitConfiguration config;
|
||||||
private BukkitPermissionAttachmentManager permissionAttachmentManager;
|
private BukkitPermissionAttachmentManager permissionAttachmentManager;
|
||||||
|
|
||||||
@ -110,8 +115,12 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
|
|||||||
WorldEdit worldEdit = WorldEdit.getInstance();
|
WorldEdit worldEdit = WorldEdit.getInstance();
|
||||||
|
|
||||||
// Setup platform
|
// Setup platform
|
||||||
server = new BukkitServerInterface(this, getServer());
|
platform = new BukkitServerInterface(this, getServer());
|
||||||
worldEdit.getPlatformManager().register(server);
|
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);
|
permissionAttachmentManager = new BukkitPermissionAttachmentManager(this);
|
||||||
|
|
||||||
@ -139,6 +148,8 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
|
|||||||
|
|
||||||
new FaweBukkit(this);
|
new FaweBukkit(this);
|
||||||
|
|
||||||
|
WorldEdit.getInstance().getEventBus().post(new PlatformsRegisteredEvent());
|
||||||
|
|
||||||
PermissionsResolverManager.initialize(this); // Setup permission resolver
|
PermissionsResolverManager.initialize(this); // Setup permission resolver
|
||||||
|
|
||||||
// Register CUI
|
// Register CUI
|
||||||
@ -171,7 +182,7 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup metrics
|
// Setup metrics
|
||||||
new Metrics(this, 1403);
|
new Metrics(this, BSTATS_ID);
|
||||||
|
|
||||||
// Check whether the server runs on 11 or greater
|
// Check whether the server runs on 11 or greater
|
||||||
ServerLib.checkJavaLTS();
|
ServerLib.checkJavaLTS();
|
||||||
@ -181,14 +192,15 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
|
|||||||
|
|
||||||
private void setupPreWorldData() {
|
private void setupPreWorldData() {
|
||||||
loadAdapter();
|
loadAdapter();
|
||||||
loadConfig();
|
config.load();
|
||||||
WorldEdit.getInstance().loadMappings();
|
WorldEdit.getInstance().loadMappings();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupWorldData() {
|
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
|
// 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" })
|
@SuppressWarnings({ "deprecation", "unchecked" })
|
||||||
@ -196,11 +208,7 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
|
|||||||
// Biome
|
// Biome
|
||||||
for (Biome biome : Biome.values()) {
|
for (Biome biome : Biome.values()) {
|
||||||
String lowerCaseBiomeName = biome.name().toLowerCase(Locale.ROOT);
|
String lowerCaseBiomeName = biome.name().toLowerCase(Locale.ROOT);
|
||||||
BiomeType biomeType = BiomeType.REGISTRY.register(
|
BiomeType.REGISTRY.register("minecraft:" + lowerCaseBiomeName, new BiomeType("minecraft:" + lowerCaseBiomeName));
|
||||||
"minecraft:" + lowerCaseBiomeName, new BiomeType("minecraft:" + lowerCaseBiomeName));
|
|
||||||
if (bukkitAdapter != null) {
|
|
||||||
biomeType.setLegacyId(bukkitAdapter.getInternalBiomeId(biomeType));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
|
||||||
@ -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() {
|
private void loadAdapter() {
|
||||||
WorldEdit worldEdit = WorldEdit.getInstance();
|
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);
|
LOGGER.warn("Failed to search " + getFile() + " for Bukkit adapters", e);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
bukkitAdapter = adapterLoader.loadAdapter();
|
BukkitImplAdapter bukkitAdapter = adapterLoader.loadAdapter();
|
||||||
LOGGER.info("Using " + bukkitAdapter.getClass().getCanonicalName() + " as the Bukkit adapter");
|
LOGGER.info("Using " + bukkitAdapter.getClass().getCanonicalName() + " as the Bukkit adapter");
|
||||||
|
this.adapter.newValue(bukkitAdapter);
|
||||||
} catch (AdapterLoadException e) {
|
} catch (AdapterLoadException e) {
|
||||||
Platform platform = worldEdit.getPlatformManager().queryCapability(Capability.WORLD_EDITING);
|
Platform platform = worldEdit.getPlatformManager().queryCapability(Capability.WORLD_EDITING);
|
||||||
if (platform instanceof BukkitServerInterface) {
|
if (platform instanceof BukkitServerInterface) {
|
||||||
LOGGER.warn(e.getMessage());
|
LOGGER.warn(e.getMessage());
|
||||||
} else {
|
} else {
|
||||||
LOGGER.info("WorldEdit could not find a Bukkit adapter for this MC version, "
|
LOGGER.info("FastAsyncWorldEdit could not find a Bukkit adapter for this MC version, "
|
||||||
+ "but it seems that you have another implementation of WorldEdit installed (" + platform.getPlatformName() + ") "
|
+ "but it seems that you have another implementation of FastAsyncWorldEdit installed (" + platform.getPlatformName() + ") "
|
||||||
+ "that handles the world editing.");
|
+ "that handles the world editing.");
|
||||||
}
|
}
|
||||||
|
this.adapter.invalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,13 +329,14 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
|
|||||||
Fawe.get().onDisable();
|
Fawe.get().onDisable();
|
||||||
WorldEdit worldEdit = WorldEdit.getInstance();
|
WorldEdit worldEdit = WorldEdit.getInstance();
|
||||||
worldEdit.getSessionManager().unload();
|
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) {
|
if (config != null) {
|
||||||
config.unload();
|
config.unload();
|
||||||
}
|
}
|
||||||
if (server != null) {
|
|
||||||
server.unregisterCommands();
|
|
||||||
}
|
|
||||||
this.getServer().getScheduler().cancelTasks(this);
|
this.getServer().getScheduler().cancelTasks(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -526,7 +526,7 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
|
|||||||
}
|
}
|
||||||
|
|
||||||
public BukkitServerInterface getInternalPlatform() {
|
public BukkitServerInterface getInternalPlatform() {
|
||||||
return server;
|
return platform;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -553,9 +553,12 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
|
|||||||
*
|
*
|
||||||
* @return the adapter
|
* @return the adapter
|
||||||
*/
|
*/
|
||||||
@Nullable
|
Lifecycled<BukkitImplAdapter> getLifecycledBukkitImplAdapter() {
|
||||||
|
return adapter;
|
||||||
|
}
|
||||||
|
|
||||||
public BukkitImplAdapter getBukkitImplAdapter() {
|
public BukkitImplAdapter getBukkitImplAdapter() {
|
||||||
return bukkitAdapter;
|
return adapter.value().orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class WorldInitListener implements Listener {
|
private class WorldInitListener implements Listener {
|
||||||
|
@ -124,7 +124,7 @@ class CLIPlatform extends AbstractPlatform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerGameHooks() {
|
public void setGameHooksEnabled(boolean enabled) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -175,7 +175,7 @@ public class CLIWorldEdit {
|
|||||||
config = new CLIConfiguration(this);
|
config = new CLIConfiguration(this);
|
||||||
config.load();
|
config.load();
|
||||||
|
|
||||||
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent());
|
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent(platform));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onStopped() {
|
public void onStopped() {
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -19,11 +19,13 @@
|
|||||||
|
|
||||||
package com.sk89q.worldedit.event.platform;
|
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
|
* Raised when a platform has finished loading its data.
|
||||||
* register themselves.
|
|
||||||
*/
|
*/
|
||||||
public class PlatformReadyEvent extends Event {
|
public class PlatformReadyEvent extends PlatformEvent {
|
||||||
|
public PlatformReadyEvent(Platform platform) {
|
||||||
|
super(platform);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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 {
|
||||||
|
}
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
package com.sk89q.worldedit.extension.platform;
|
package com.sk89q.worldedit.extension.platform;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A collection of capabilities that a {@link Platform} may support.
|
* A collection of capabilities that a {@link Platform} may support.
|
||||||
*/
|
*/
|
||||||
@ -31,11 +33,12 @@ public enum Capability {
|
|||||||
GAME_HOOKS {
|
GAME_HOOKS {
|
||||||
@Override
|
@Override
|
||||||
void initialize(PlatformManager platformManager, Platform platform) {
|
void initialize(PlatformManager platformManager, Platform platform) {
|
||||||
platform.registerGameHooks();
|
platform.setGameHooksEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void unload(PlatformManager platformManager, Platform platform) {
|
void uninitialize(PlatformManager platformManager, Platform platform) {
|
||||||
|
platform.setGameHooksEnabled(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -54,7 +57,7 @@ public enum Capability {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void unload(PlatformManager platformManager, Platform platform) {
|
void uninitialize(PlatformManager platformManager, Platform platform) {
|
||||||
platformManager.getPlatformCommandManager().removeCommands();
|
platformManager.getPlatformCommandManager().removeCommands();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -76,7 +79,7 @@ public enum Capability {
|
|||||||
WORLD_EDITING {
|
WORLD_EDITING {
|
||||||
/*
|
/*
|
||||||
@Override
|
@Override
|
||||||
void initialize(PlatformManager platformManager, Platform platform) {
|
void ready(PlatformManager platformManager, Platform platform) {
|
||||||
BlockRegistry blockRegistry = platform.getRegistries().getBlockRegistry();
|
BlockRegistry blockRegistry = platform.getRegistries().getBlockRegistry();
|
||||||
for (BlockType type : BlockType.REGISTRY) {
|
for (BlockType type : BlockType.REGISTRY) {
|
||||||
for (BlockState state : type.getAllStates()) {
|
for (BlockState state : type.getAllStates()) {
|
||||||
@ -86,18 +89,35 @@ public enum Capability {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void unload(PlatformManager platformManager, Platform platform) {
|
void unready(PlatformManager platformManager, Platform platform) {
|
||||||
BlockStateIdAccess.clear();
|
BlockStateIdAccess.clear();
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize platform-wide state.
|
||||||
|
*/
|
||||||
void initialize(PlatformManager platformManager, Platform platform) {
|
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) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -138,14 +138,28 @@ public interface Platform extends Keyed {
|
|||||||
/**
|
/**
|
||||||
* Register the commands contained within the given command manager.
|
* Register the commands contained within the given command manager.
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
|
* This method should be ignored if the platform offers a command registration event.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
* @param commandManager the command manager
|
* @param commandManager the command manager
|
||||||
*/
|
*/
|
||||||
void registerCommands(CommandManager commandManager);
|
void registerCommands(CommandManager commandManager);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register game hooks.
|
* 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.
|
* Get the configuration from this platform.
|
||||||
|
@ -40,6 +40,8 @@ import com.sk89q.worldedit.event.platform.ConfigurationLoadEvent;
|
|||||||
import com.sk89q.worldedit.event.platform.Interaction;
|
import com.sk89q.worldedit.event.platform.Interaction;
|
||||||
import com.sk89q.worldedit.event.platform.PlatformInitializeEvent;
|
import com.sk89q.worldedit.event.platform.PlatformInitializeEvent;
|
||||||
import com.sk89q.worldedit.event.platform.PlatformReadyEvent;
|
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.event.platform.PlayerInputEvent;
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||||
import com.sk89q.worldedit.math.Vector3;
|
import com.sk89q.worldedit.math.Vector3;
|
||||||
@ -145,7 +147,7 @@ public class PlatformManager {
|
|||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
Entry<Capability, Platform> entry = it.next();
|
Entry<Capability, Platform> entry = it.next();
|
||||||
if (entry.getValue().equals(platform)) {
|
if (entry.getValue().equals(platform)) {
|
||||||
entry.getKey().unload(this, entry.getValue());
|
entry.getKey().uninitialize(this, entry.getValue());
|
||||||
it.remove();
|
it.remove();
|
||||||
choosePreferred = true; // Have to choose new favorites
|
choosePreferred = true; // Have to choose new favorites
|
||||||
}
|
}
|
||||||
@ -160,8 +162,7 @@ public class PlatformManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the preferred platform for handling a certain capability. Returns
|
* Get the preferred platform for handling a certain capability. Throws if none are available.
|
||||||
* null if none is available.
|
|
||||||
*
|
*
|
||||||
* @param capability the capability
|
* @param capability the capability
|
||||||
* @return the platform
|
* @return the platform
|
||||||
@ -173,12 +174,11 @@ public class PlatformManager {
|
|||||||
return platform;
|
return platform;
|
||||||
} else {
|
} else {
|
||||||
if (preferences.isEmpty()) {
|
if (preferences.isEmpty()) {
|
||||||
// Use the first available if preferences have not been decided yet.
|
// Not all platforms registered, this is being called too early!
|
||||||
if (platforms.isEmpty()) {
|
throw new NoCapablePlatformException(
|
||||||
// No platforms registered, this is being called too early!
|
"Not all platforms have been registered yet!"
|
||||||
throw new NoCapablePlatformException("No platforms have been registered yet! Please wait until WorldEdit is initialized.");
|
+ " Please wait until FastAsyncWorldEdit is initialized."
|
||||||
}
|
);
|
||||||
return platforms.get(0);
|
|
||||||
}
|
}
|
||||||
throw new NoCapablePlatformException("No platform was found supporting " + capability.name());
|
throw new NoCapablePlatformException("No platform was found supporting " + capability.name());
|
||||||
}
|
}
|
||||||
@ -191,8 +191,15 @@ public class PlatformManager {
|
|||||||
for (Capability capability : Capability.values()) {
|
for (Capability capability : Capability.values()) {
|
||||||
Platform preferred = findMostPreferred(capability);
|
Platform preferred = findMostPreferred(capability);
|
||||||
if (preferred != null) {
|
if (preferred != null) {
|
||||||
preferences.put(capability, preferred);
|
Platform oldPreferred = preferences.put(capability, preferred);
|
||||||
capability.initialize(this, 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();
|
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
|
@Subscribe
|
||||||
public void handlePlatformReady(PlatformReadyEvent event) {
|
public void handlePlatformsRegistered(PlatformsRegisteredEvent event) {
|
||||||
choosePreferred();
|
choosePreferred();
|
||||||
if (initialized.compareAndSet(false, true)) {
|
if (initialized.compareAndSet(false, true)) {
|
||||||
worldEdit.getEventBus().post(new PlatformInitializeEvent());
|
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 extends Tool> T reset(T tool) {
|
private <T extends Tool> T reset(T tool) {
|
||||||
new PatternTraverser(tool).reset(null);
|
new PatternTraverser(tool).reset(null);
|
||||||
return tool;
|
return tool;
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<T> implements Lifecycled<T> {
|
||||||
|
private final T value;
|
||||||
|
|
||||||
|
public ConstantLifecycled(T value) {
|
||||||
|
this.value = Objects.requireNonNull(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<T> value() {
|
||||||
|
return Optional.of(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Events<T> events() {
|
||||||
|
// Simple implementation, we just need to call onNewValue
|
||||||
|
return new Events<T>() {
|
||||||
|
@Override
|
||||||
|
public <O> void onNewValue(O owner, BiConsumer<O, ? super Lifecycled<T>> callback) {
|
||||||
|
callback.accept(owner, ConstantLifecycled.this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <O> void onInvalidated(O owner, BiConsumer<O, ? super Lifecycled<T>> callback) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.util.lifecycle;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
class FlatMapLifecycled<T, U> implements Lifecycled<U> {
|
||||||
|
private final LifecycledCallbackHandler<U> events = new LifecycledCallbackHandler<>(this);
|
||||||
|
private Lifecycled<U> mapped;
|
||||||
|
private Token<FlatMapLifecycled<T, U>> mappedToken;
|
||||||
|
@Nullable
|
||||||
|
private U value;
|
||||||
|
|
||||||
|
FlatMapLifecycled(Lifecycled<T> upstream, Function<T, Lifecycled<U>> 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<U> value() {
|
||||||
|
return Optional.ofNullable(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid() {
|
||||||
|
return value != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Events<U> events() {
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 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".
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Unless specified, {@link Lifecycled} objects are <em>not</em> thread-safe. However, the
|
||||||
|
* {@link Events} objects are, and callbacks may be added from any thread.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param <T> the value type
|
||||||
|
*/
|
||||||
|
public interface Lifecycled<T> {
|
||||||
|
|
||||||
|
interface Events<T> {
|
||||||
|
/**
|
||||||
|
* Add a callback for when this lifecycled is given a new value. Will be called immediately
|
||||||
|
* if this lifecycled is currently valid.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param owner when the owner is GC'd, the callback is removed
|
||||||
|
* @param callback the callback, will be passed the lifecycled object
|
||||||
|
*/
|
||||||
|
<O> void onNewValue(O owner, BiConsumer<O, ? super Lifecycled<T>> callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a callback for when this lifecycled is invalidated. Will be called immediately if
|
||||||
|
* this lifecycled is currently invalid.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param owner when the owner is GC'd, the callback is removed
|
||||||
|
* @param callback the callback, will be passed the lifecycled object
|
||||||
|
*/
|
||||||
|
<O> void onInvalidated(O owner, BiConsumer<O, ? super Lifecycled<T>> callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value or {@link Optional#empty()}.
|
||||||
|
*
|
||||||
|
* @return the value
|
||||||
|
*/
|
||||||
|
Optional<T> 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<T> events();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map the value.
|
||||||
|
*
|
||||||
|
* @param mapper the mapper function
|
||||||
|
* @param <U> the new type
|
||||||
|
* @return the downstream lifecycled
|
||||||
|
*/
|
||||||
|
default <U> Lifecycled<U> map(Function<T, U> 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<T> filter(Predicate<T> filterer) {
|
||||||
|
SimpleLifecycled<T> 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 <U> Lifecycled<U> flatMap(Function<T, Lifecycled<U>> mapper) {
|
||||||
|
return new FlatMapLifecycled<>(this, mapper);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<T> implements Lifecycled.Events<T> {
|
||||||
|
private final Lifecycled<T> lifecycled;
|
||||||
|
private final Lock lock = new ReentrantLock();
|
||||||
|
private final Map<Object, BiConsumer<?, ? super Lifecycled<T>>> onInvalidatedCallbacks =
|
||||||
|
new WeakHashMap<>();
|
||||||
|
private final Map<Object, BiConsumer<?, ? super Lifecycled<T>>> onNewValueCallbacks =
|
||||||
|
new WeakHashMap<>();
|
||||||
|
|
||||||
|
public LifecycledCallbackHandler(Lifecycled<T> lifecycled) {
|
||||||
|
this.lifecycled = lifecycled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <O> void onInvalidated(O owner, BiConsumer<O, ? super Lifecycled<T>> callback) {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
onInvalidatedCallbacks.put(owner, callback);
|
||||||
|
if (!lifecycled.isValid()) {
|
||||||
|
callback.accept(owner, lifecycled);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <O> void onNewValue(O owner, BiConsumer<O, ? super Lifecycled<T>> 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<Object, BiConsumer<?, ? super Lifecycled<T>>> callback : onInvalidatedCallbacks.entrySet()) {
|
||||||
|
Object owner = callback.getKey();
|
||||||
|
if (owner == null) {
|
||||||
|
// GC'd, continue
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
BiConsumer<Object, ? super Lifecycled<T>> cast =
|
||||||
|
(BiConsumer<Object, ? super Lifecycled<T>>) 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<Object, BiConsumer<?, ? super Lifecycled<T>>> callback : onNewValueCallbacks.entrySet()) {
|
||||||
|
Object owner = callback.getKey();
|
||||||
|
if (owner == null) {
|
||||||
|
// GC'd, continue
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
BiConsumer<Object, ? super Lifecycled<T>> cast =
|
||||||
|
(BiConsumer<Object, ? super Lifecycled<T>>) callback.getValue();
|
||||||
|
cast.accept(owner, lifecycled);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<T, U> implements Lifecycled<U> {
|
||||||
|
private final LifecycledCallbackHandler<U> events = new LifecycledCallbackHandler<>(this);
|
||||||
|
private final Lifecycled<T> upstream;
|
||||||
|
private final Function<T, U> mapper;
|
||||||
|
@Nullable
|
||||||
|
private U cache;
|
||||||
|
private boolean computable;
|
||||||
|
|
||||||
|
MapLifecycled(Lifecycled<T> upstream, Function<T, U> 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<U> value() {
|
||||||
|
if (!computable) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
if (cache == null) {
|
||||||
|
compute();
|
||||||
|
}
|
||||||
|
return Optional.of(cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid() {
|
||||||
|
return computable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Events<U> events() {
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<T> implements Lifecycled<T> {
|
||||||
|
public static <T> SimpleLifecycled<T> valid(T value) {
|
||||||
|
return new SimpleLifecycled<>(Objects.requireNonNull(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> SimpleLifecycled<T> invalid() {
|
||||||
|
return new SimpleLifecycled<>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final LifecycledCallbackHandler<T> 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<T> value() {
|
||||||
|
return Optional.ofNullable(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Events<T> events() {
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.util.lifecycle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to create a new strong reference to an object that can be separately dropped.
|
||||||
|
*
|
||||||
|
* @param <T> the inner object
|
||||||
|
*/
|
||||||
|
class Token<T> {
|
||||||
|
final T inner;
|
||||||
|
|
||||||
|
Token(T inner) {
|
||||||
|
this.inner = inner;
|
||||||
|
}
|
||||||
|
}
|
@ -21,10 +21,17 @@ package com.sk89q.worldedit.internal.expression;
|
|||||||
|
|
||||||
import com.sk89q.worldedit.LocalConfiguration;
|
import com.sk89q.worldedit.LocalConfiguration;
|
||||||
import com.sk89q.worldedit.WorldEdit;
|
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.Platform;
|
||||||
|
import com.sk89q.worldedit.extension.platform.Preference;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
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.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
@ -42,12 +49,17 @@ class BaseExpressionTest {
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setup() {
|
void setup() {
|
||||||
|
when(mockPlat.getCapabilities()).thenReturn(
|
||||||
|
Stream.of(Capability.values())
|
||||||
|
.collect(Collectors.toMap(Function.identity(), __ -> Preference.NORMAL))
|
||||||
|
);
|
||||||
when(mockPlat.getConfiguration()).thenReturn(new LocalConfiguration() {
|
when(mockPlat.getConfiguration()).thenReturn(new LocalConfiguration() {
|
||||||
@Override
|
@Override
|
||||||
public void load() {
|
public void load() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
WorldEdit.getInstance().getPlatformManager().register(mockPlat);
|
WorldEdit.getInstance().getPlatformManager().register(mockPlat);
|
||||||
|
WorldEdit.getInstance().getEventBus().post(new PlatformsRegisteredEvent());
|
||||||
WorldEdit.getInstance().getConfiguration().calculationTimeout = 1_000;
|
WorldEdit.getInstance().getConfiguration().calculationTimeout = 1_000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,12 +30,13 @@ class BlockMapTest {
|
|||||||
static void setupFakePlatform() {
|
static void setupFakePlatform() {
|
||||||
when(MOCKED_PLATFORM.getRegistries()).thenReturn(new BundledRegistries() {
|
when(MOCKED_PLATFORM.getRegistries()).thenReturn(new BundledRegistries() {
|
||||||
});
|
});
|
||||||
when(MOCKED_PLATFORM.getCapabilities()).thenReturn(ImmutableMap.of(
|
when(MOCKED_PLATFORM.getCapabilities()).thenReturn(
|
||||||
Capability.WORLD_EDITING, Preference.PREFERRED,
|
Stream.of(Capability.values())
|
||||||
Capability.GAME_HOOKS, Preference.PREFERRED
|
.collect(Collectors.toMap(Function.identity(), __ -> Preference.NORMAL))
|
||||||
));
|
);
|
||||||
PlatformManager platformManager = WorldEdit.getInstance().getPlatformManager();
|
PlatformManager platformManager = WorldEdit.getInstance().getPlatformManager();
|
||||||
platformManager.register(MOCKED_PLATFORM);
|
platformManager.register(MOCKED_PLATFORM);
|
||||||
|
WorldEdit.getInstance().getEventBus().post(new PlatformsRegisteredEvent());
|
||||||
|
|
||||||
registerBlock("minecraft:air");
|
registerBlock("minecraft:air");
|
||||||
registerBlock("minecraft:oak_wood");
|
registerBlock("minecraft:oak_wood");
|
||||||
|
Loading…
Reference in New Issue
Block a user