mirror of
https://github.com/EngineHub/WorldEdit.git
synced 2025-01-18 12:34:20 +08:00
Register platforms and commands in a more proper way (#1766)
* Register platforms and commands in a more proper way Platforms are now register "on load"/initialize/etc., and preferreds are chosen just prior to command registration events. This allows us to properly hook in to reload. Additionally, we now have the capability to reload data with /minecraft:reload, though this is not yet implemented. * Correct javadocs on queryCapability * Flatten BukkitImplAdapter Lifecycled
This commit is contained in:
parent
8cfbf7e478
commit
95160027d9
@ -23,6 +23,7 @@
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
@ -443,7 +444,8 @@ public static ItemType asItemType(Material material) {
|
||||
public static BlockState adapt(BlockData blockData) {
|
||||
checkNotNull(blockData);
|
||||
|
||||
if (WorldEditPlugin.getInstance().getBukkitImplAdapter() == null) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
if (adapter == null) {
|
||||
return blockStateStringCache.computeIfAbsent(blockData.getAsString(), input -> {
|
||||
try {
|
||||
return WorldEdit.getInstance().getBlockFactory().parseFromInput(input, TO_BLOCK_CONTEXT).toImmutableState();
|
||||
@ -454,7 +456,7 @@ public static BlockState adapt(BlockData blockData) {
|
||||
});
|
||||
} else {
|
||||
return blockStateCache.computeIfAbsent(
|
||||
WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBlockStateId(blockData).orElseGet(
|
||||
adapter.getInternalBlockStateId(blockData).orElseGet(
|
||||
() -> blockData.getAsString().hashCode()
|
||||
),
|
||||
input -> {
|
||||
@ -509,8 +511,9 @@ public static BlockState asBlockState(ItemStack itemStack) throws WorldEditExcep
|
||||
*/
|
||||
public static BaseItemStack adapt(ItemStack itemStack) {
|
||||
checkNotNull(itemStack);
|
||||
if (WorldEditPlugin.getInstance().getBukkitImplAdapter() != null) {
|
||||
return WorldEditPlugin.getInstance().getBukkitImplAdapter().adapt(itemStack);
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
if (adapter != null) {
|
||||
return adapter.adapt(itemStack);
|
||||
}
|
||||
return new BaseItemStack(ItemTypes.get(itemStack.getType().getKey().toString()), itemStack.getAmount());
|
||||
}
|
||||
@ -523,8 +526,9 @@ public static BaseItemStack adapt(ItemStack itemStack) {
|
||||
*/
|
||||
public static ItemStack adapt(BaseItemStack item) {
|
||||
checkNotNull(item);
|
||||
if (WorldEditPlugin.getInstance().getBukkitImplAdapter() != null) {
|
||||
return WorldEditPlugin.getInstance().getBukkitImplAdapter().adapt(item);
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
if (adapter != null) {
|
||||
return adapter.adapt(item);
|
||||
}
|
||||
return new ItemStack(adapt(item.getType()), item.getAmount());
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ public Locale getLocale() {
|
||||
|
||||
@Override
|
||||
public void sendAnnouncements() {
|
||||
if (WorldEditPlugin.getInstance().getBukkitImplAdapter() == null) {
|
||||
if (WorldEditPlugin.getInstance().getLifecycledBukkitImplAdapter() == null) {
|
||||
printError(TranslatableComponent.of("worldedit.version.bukkit.unsupported-adapter",
|
||||
TextComponent.of("https://enginehub.org/worldedit/#downloads", TextColor.AQUA)
|
||||
.clickEvent(ClickEvent.openUrl("https://enginehub.org/worldedit/#downloads"))));
|
||||
|
@ -24,6 +24,7 @@
|
||||
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;
|
||||
@ -33,7 +34,7 @@
|
||||
import com.sk89q.worldedit.extension.platform.Preference;
|
||||
import com.sk89q.worldedit.extension.platform.Watchdog;
|
||||
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.bukkit.Bukkit;
|
||||
@ -59,21 +60,16 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
|
||||
public final Server server;
|
||||
public final WorldEditPlugin plugin;
|
||||
private final CommandRegistration dynamicCommands;
|
||||
private final LazyReference<Watchdog> watchdog;
|
||||
private final Lifecycled<Watchdog> watchdog;
|
||||
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);
|
||||
}
|
||||
|
||||
CommandRegistration getDynamicCommands() {
|
||||
@ -92,7 +88,7 @@ public Registries getRegistries() {
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public int getDataVersion() {
|
||||
if (plugin.getBukkitImplAdapter() != null) {
|
||||
if (plugin.getLifecycledBukkitImplAdapter() != null) {
|
||||
return Bukkit.getUnsafe().getDataVersion();
|
||||
}
|
||||
return -1;
|
||||
@ -129,7 +125,7 @@ public int schedule(long delay, long period, Runnable task) {
|
||||
|
||||
@Override
|
||||
public Watchdog getWatchdog() {
|
||||
return watchdog.getValue();
|
||||
return watchdog.valueOrThrow();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -190,8 +186,8 @@ public void registerCommands(CommandManager dispatcher) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerGameHooks() {
|
||||
hookingEvents = true;
|
||||
public void setGameHooksEnabled(boolean enabled) {
|
||||
this.hookingEvents = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -33,6 +33,8 @@
|
||||
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.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
@ -43,6 +45,8 @@
|
||||
import com.sk89q.worldedit.internal.command.CommandUtil;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.util.lifecycle.Lifecycled;
|
||||
import com.sk89q.worldedit.util.lifecycle.SimpleLifecycled;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockCategory;
|
||||
@ -87,7 +91,6 @@
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.logging.Level;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME;
|
||||
@ -115,8 +118,9 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
|
||||
private static WorldEditPlugin INSTANCE;
|
||||
private static final int BSTATS_PLUGIN_ID = 3328;
|
||||
|
||||
private BukkitImplAdapter bukkitAdapter;
|
||||
private BukkitServerInterface server;
|
||||
private final SimpleLifecycled<BukkitImplAdapter> adapter =
|
||||
SimpleLifecycled.invalid();
|
||||
private BukkitServerInterface platform;
|
||||
private BukkitConfiguration config;
|
||||
|
||||
@Override
|
||||
@ -129,8 +133,12 @@ public void onLoad() {
|
||||
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.yml"); // Create the default configuration file
|
||||
|
||||
config = new BukkitConfiguration(new YAMLProcessor(new File(getDataFolder(), "config.yml"), true), this);
|
||||
|
||||
Path delChunks = Paths.get(getDataFolder().getPath(), DELCHUNKS_FILE_NAME);
|
||||
if (Files.exists(delChunks)) {
|
||||
@ -149,6 +157,8 @@ public void onEnable() {
|
||||
ClassSourceValidator verifier = new ClassSourceValidator(this);
|
||||
verifier.reportMismatches(ImmutableList.of(World.class, CommandManager.class, EditSession.class, Actor.class));
|
||||
|
||||
WorldEdit.getInstance().getEventBus().post(new PlatformsRegisteredEvent());
|
||||
|
||||
PermissionsResolverManager.initialize(this); // Setup permission resolver
|
||||
|
||||
// Register CUI
|
||||
@ -184,14 +194,16 @@ public void onEnable() {
|
||||
|
||||
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" })
|
||||
@ -257,13 +269,6 @@ private void setupTags() {
|
||||
}
|
||||
}
|
||||
|
||||
private void loadConfig() {
|
||||
createDefaultConfiguration("config.yml"); // Create the default configuration file
|
||||
|
||||
config = new BukkitConfiguration(new YAMLProcessor(new File(getDataFolder(), "config.yml"), true), this);
|
||||
config.load();
|
||||
}
|
||||
|
||||
private void loadAdapter() {
|
||||
WorldEdit worldEdit = WorldEdit.getInstance();
|
||||
|
||||
@ -282,8 +287,9 @@ private void loadAdapter() {
|
||||
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) {
|
||||
@ -293,6 +299,7 @@ private void loadAdapter() {
|
||||
+ "but it seems that you have another implementation of WorldEdit installed (" + platform.getPlatformName() + ") "
|
||||
+ "that handles the world editing.");
|
||||
}
|
||||
this.adapter.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -303,13 +310,14 @@ private void loadAdapter() {
|
||||
public void 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);
|
||||
}
|
||||
|
||||
@ -471,7 +479,7 @@ public Actor wrapCommandSender(CommandSender sender) {
|
||||
}
|
||||
|
||||
BukkitServerInterface getInternalPlatform() {
|
||||
return server;
|
||||
return platform;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -498,9 +506,12 @@ static WorldEditPlugin getInstance() {
|
||||
*
|
||||
* @return the adapter
|
||||
*/
|
||||
@Nullable
|
||||
Lifecycled<BukkitImplAdapter> getLifecycledBukkitImplAdapter() {
|
||||
return adapter;
|
||||
}
|
||||
|
||||
BukkitImplAdapter getBukkitImplAdapter() {
|
||||
return bukkitAdapter;
|
||||
return adapter.value().orElse(null);
|
||||
}
|
||||
|
||||
private class WorldInitListener implements Listener {
|
||||
@ -533,7 +544,7 @@ public void onAsyncTabComplete(com.destroystokyo.paper.event.server.AsyncTabComp
|
||||
return;
|
||||
}
|
||||
String label = buffer.substring(1, firstSpace);
|
||||
Plugin owner = server.getDynamicCommands().getCommandOwner(label);
|
||||
Plugin owner = platform.getDynamicCommands().getCommandOwner(label);
|
||||
if (owner != WorldEditPlugin.this) {
|
||||
return;
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ public void registerCommands(CommandManager manager) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerGameHooks() {
|
||||
public void setGameHooksEnabled(boolean enabled) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -45,7 +45,6 @@
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.DefaultParser;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
@ -176,7 +175,7 @@ public void onStarted() {
|
||||
config = new CLIConfiguration(this);
|
||||
config.load();
|
||||
|
||||
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent());
|
||||
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent(platform));
|
||||
}
|
||||
|
||||
public void onStopped() {
|
||||
|
@ -55,7 +55,7 @@ override fun matchWorld(world: World?) = error("Documentation does not provide t
|
||||
|
||||
override fun registerCommands(commandManager: CommandManager?) = error("Documentation does not provide this")
|
||||
|
||||
override fun registerGameHooks() = error("Documentation does not provide this")
|
||||
override fun setGameHooksEnabled(enabled: Boolean) = error("Documentation does not provide this")
|
||||
|
||||
override fun getCapabilities() = error("Documentation does not provide this")
|
||||
|
||||
|
@ -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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
}
|
@ -37,11 +37,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);
|
||||
}
|
||||
},
|
||||
|
||||
@ -53,6 +54,11 @@ void unload(PlatformManager platformManager, Platform platform) {
|
||||
void initialize(PlatformManager platformManager, Platform platform) {
|
||||
WorldEdit.getInstance().getAssetLoaders().init();
|
||||
}
|
||||
|
||||
@Override
|
||||
void uninitialize(PlatformManager platformManager, Platform platform) {
|
||||
WorldEdit.getInstance().getAssetLoaders().uninit();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -65,7 +71,7 @@ void initialize(PlatformManager platformManager, Platform platform) {
|
||||
}
|
||||
|
||||
@Override
|
||||
void unload(PlatformManager platformManager, Platform platform) {
|
||||
void uninitialize(PlatformManager platformManager, Platform platform) {
|
||||
platformManager.getPlatformCommandManager().removeCommands();
|
||||
}
|
||||
},
|
||||
@ -86,7 +92,7 @@ void unload(PlatformManager platformManager, Platform platform) {
|
||||
*/
|
||||
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()) {
|
||||
@ -98,17 +104,33 @@ void initialize(PlatformManager platformManager, Platform platform) {
|
||||
}
|
||||
|
||||
@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) {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -135,14 +135,28 @@ public interface Platform {
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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.
|
||||
|
@ -33,6 +33,8 @@
|
||||
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.session.request.Request;
|
||||
@ -137,7 +139,7 @@ public synchronized boolean unregister(Platform platform) {
|
||||
while (it.hasNext()) {
|
||||
Entry<Capability, Platform> 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
|
||||
}
|
||||
@ -152,8 +154,7 @@ public synchronized boolean unregister(Platform platform) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -165,12 +166,11 @@ public synchronized Platform queryCapability(Capability capability) throws NoCap
|
||||
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 WorldEdit is initialized."
|
||||
);
|
||||
}
|
||||
throw new NoCapablePlatformException("No platform was found supporting " + capability.name());
|
||||
}
|
||||
@ -183,8 +183,15 @@ private synchronized void choosePreferred() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -295,14 +302,42 @@ public Collection<SideEffect> 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
|
||||
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));
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void handleBlockInteract(BlockInteractEvent event) {
|
||||
// Create a proxy actor with a potentially different world for
|
||||
|
@ -75,6 +75,11 @@ public void init() {
|
||||
registerAssetLoader(new ImageHeightmapLoader(worldEdit, this.assetsDir), ImageHeightmap.class);
|
||||
}
|
||||
|
||||
public void uninit() {
|
||||
this.assetsDir = null;
|
||||
assetLoaderRegistration.clear();
|
||||
}
|
||||
|
||||
public <T> void registerAssetLoader(AssetLoader<T> loader, Class<T> assetClass) {
|
||||
assetLoaders.add(loader);
|
||||
for (String extension : loader.getAllowedExtensions()) {
|
||||
|
@ -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 @@
|
||||
|
||||
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 @@ static double readSlot(Expression expr, String name) {
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
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.PlatformManager;
|
||||
@ -50,7 +51,9 @@
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
@ -74,12 +77,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");
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
package com.sk89q.worldedit.fabric;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
@ -28,10 +27,6 @@
|
||||
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.Vector3;
|
||||
import com.sk89q.worldedit.registry.state.BooleanProperty;
|
||||
import com.sk89q.worldedit.registry.state.DirectionalProperty;
|
||||
import com.sk89q.worldedit.registry.state.EnumProperty;
|
||||
import com.sk89q.worldedit.registry.state.IntegerProperty;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.util.Direction;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
@ -45,7 +40,6 @@
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.state.property.DirectionProperty;
|
||||
import net.minecraft.util.Identifier;
|
||||
@ -59,23 +53,12 @@
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public final class FabricAdapter {
|
||||
|
||||
private static @Nullable MinecraftServer server;
|
||||
|
||||
private static MinecraftServer requireServer() {
|
||||
return Objects.requireNonNull(server, "No server injected");
|
||||
}
|
||||
|
||||
static void setServer(@Nullable MinecraftServer server) {
|
||||
FabricAdapter.server = server;
|
||||
}
|
||||
|
||||
private FabricAdapter() {
|
||||
}
|
||||
|
||||
@ -84,14 +67,15 @@ public static World adapt(net.minecraft.world.World world) {
|
||||
}
|
||||
|
||||
public static Biome adapt(BiomeType biomeType) {
|
||||
return requireServer()
|
||||
return FabricWorldEdit.LIFECYCLED_SERVER.valueOrThrow()
|
||||
.getRegistryManager()
|
||||
.get(Registry.BIOME_KEY)
|
||||
.get(new Identifier(biomeType.getId()));
|
||||
}
|
||||
|
||||
public static BiomeType adapt(Biome biome) {
|
||||
Identifier id = requireServer().getRegistryManager().get(Registry.BIOME_KEY).getId(biome);
|
||||
Identifier id = FabricWorldEdit.LIFECYCLED_SERVER.valueOrThrow().getRegistryManager()
|
||||
.get(Registry.BIOME_KEY).getId(biome);
|
||||
Objects.requireNonNull(id, "biome is not registered");
|
||||
return BiomeTypes.get(id.toString());
|
||||
}
|
||||
|
@ -21,7 +21,6 @@
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.sk89q.worldedit.command.util.PermissionCondition;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.platform.AbstractPlatform;
|
||||
@ -32,13 +31,15 @@
|
||||
import com.sk89q.worldedit.extension.platform.Watchdog;
|
||||
import com.sk89q.worldedit.fabric.internal.ExtendedChunk;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.lifecycle.Lifecycled;
|
||||
import com.sk89q.worldedit.util.lifecycle.SimpleLifecycled;
|
||||
import com.sk89q.worldedit.world.DataFixer;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.registry.Registries;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.PlayerManager;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.dedicated.MinecraftDedicatedServer;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
@ -55,7 +56,9 @@
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
@ -63,19 +66,19 @@
|
||||
class FabricPlatform extends AbstractPlatform implements MultiUserPlatform {
|
||||
|
||||
private final FabricWorldEdit mod;
|
||||
private final MinecraftServer server;
|
||||
private final FabricDataFixer dataFixer;
|
||||
private final @Nullable Watchdog watchdog;
|
||||
private final Lifecycled<Optional<Watchdog>> watchdog;
|
||||
private boolean hookingEvents = false;
|
||||
private CommandDispatcher<ServerCommandSource> nativeDispatcher;
|
||||
|
||||
FabricPlatform(FabricWorldEdit mod, MinecraftServer server) {
|
||||
FabricPlatform(FabricWorldEdit mod) {
|
||||
this.mod = mod;
|
||||
this.server = server;
|
||||
this.nativeDispatcher = server.getCommandManager().getDispatcher();
|
||||
this.dataFixer = new FabricDataFixer(getDataVersion());
|
||||
this.watchdog = server instanceof MinecraftDedicatedServer
|
||||
? (Watchdog) server : null;
|
||||
|
||||
this.watchdog = FabricWorldEdit.LIFECYCLED_SERVER.map(
|
||||
server -> server instanceof MinecraftDedicatedServer
|
||||
? Optional.of((Watchdog) server)
|
||||
: Optional.empty()
|
||||
);
|
||||
}
|
||||
|
||||
boolean isHookingEvents() {
|
||||
@ -116,12 +119,12 @@ public int schedule(long delay, long period, Runnable task) {
|
||||
@Override
|
||||
@Nullable
|
||||
public Watchdog getWatchdog() {
|
||||
return watchdog;
|
||||
return watchdog.value().flatMap(Function.identity()).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends World> getWorlds() {
|
||||
Iterable<ServerWorld> worlds = server.getWorlds();
|
||||
Iterable<ServerWorld> worlds = FabricWorldEdit.LIFECYCLED_SERVER.valueOrThrow().getWorlds();
|
||||
List<World> ret = new ArrayList<>();
|
||||
for (ServerWorld world : worlds) {
|
||||
ret.add(new FabricWorld(world));
|
||||
@ -135,7 +138,8 @@ public Player matchPlayer(Player player) {
|
||||
if (player instanceof FabricPlayer) {
|
||||
return player;
|
||||
} else {
|
||||
ServerPlayerEntity entity = server.getPlayerManager().getPlayer(player.getName());
|
||||
ServerPlayerEntity entity = FabricWorldEdit.LIFECYCLED_SERVER.valueOrThrow()
|
||||
.getPlayerManager().getPlayer(player.getName());
|
||||
return entity != null ? new FabricPlayer(entity) : null;
|
||||
}
|
||||
}
|
||||
@ -146,7 +150,7 @@ public World matchWorld(World world) {
|
||||
if (world instanceof FabricWorld) {
|
||||
return world;
|
||||
} else {
|
||||
for (ServerWorld ws : server.getWorlds()) {
|
||||
for (ServerWorld ws : FabricWorldEdit.LIFECYCLED_SERVER.valueOrThrow().getWorlds()) {
|
||||
if (((ServerWorldProperties) ws.getLevelProperties()).getLevelName().equals(world.getName())) {
|
||||
return new FabricWorld(ws);
|
||||
}
|
||||
@ -156,31 +160,14 @@ public World matchWorld(World world) {
|
||||
}
|
||||
}
|
||||
|
||||
public void setNativeDispatcher(CommandDispatcher<ServerCommandSource> nativeDispatcher) {
|
||||
this.nativeDispatcher = nativeDispatcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommands(CommandManager manager) {
|
||||
if (server == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Command command : manager.getAllCommands().collect(toList())) {
|
||||
CommandWrapper.register(nativeDispatcher, command);
|
||||
Set<String> perms = command.getCondition().as(PermissionCondition.class)
|
||||
.map(PermissionCondition::getPermissions)
|
||||
.orElseGet(Collections::emptySet);
|
||||
if (!perms.isEmpty()) {
|
||||
perms.forEach(FabricWorldEdit.inst.getPermissionsProvider()::registerPermission);
|
||||
}
|
||||
}
|
||||
// No-op, we register using Fabric's event
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerGameHooks() {
|
||||
// We registered the events already anyway, so we just 'turn them on'
|
||||
hookingEvents = true;
|
||||
public void setGameHooksEnabled(boolean enabled) {
|
||||
this.hookingEvents = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -236,7 +223,7 @@ public Set<SideEffect> getSupportedSideEffects() {
|
||||
@Override
|
||||
public Collection<Actor> getConnectedUsers() {
|
||||
List<Actor> users = new ArrayList<>();
|
||||
PlayerManager scm = server.getPlayerManager();
|
||||
PlayerManager scm = FabricWorldEdit.LIFECYCLED_SERVER.valueOrThrow().getPlayerManager();
|
||||
for (ServerPlayerEntity entity : scm.getPlayerList()) {
|
||||
if (entity != null) {
|
||||
users.add(new FabricPlayer(entity));
|
||||
|
@ -22,7 +22,10 @@
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.command.util.PermissionCondition;
|
||||
import com.sk89q.worldedit.event.platform.PlatformReadyEvent;
|
||||
import com.sk89q.worldedit.event.platform.PlatformUnreadyEvent;
|
||||
import com.sk89q.worldedit.event.platform.PlatformsRegisteredEvent;
|
||||
import com.sk89q.worldedit.event.platform.SessionIdleEvent;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.extension.platform.Platform;
|
||||
@ -31,6 +34,8 @@
|
||||
import com.sk89q.worldedit.internal.anvil.ChunkDeleter;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
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.block.BlockType;
|
||||
@ -65,15 +70,20 @@
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.world.World;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.enginehub.piston.Command;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.sk89q.worldedit.fabric.FabricAdapter.adaptPlayer;
|
||||
import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
/**
|
||||
* The Fabric implementation of WorldEdit.
|
||||
@ -84,6 +94,15 @@ public class FabricWorldEdit implements ModInitializer {
|
||||
public static final String MOD_ID = "worldedit";
|
||||
public static final String CUI_PLUGIN_CHANNEL = "cui";
|
||||
|
||||
public static final Lifecycled<MinecraftServer> LIFECYCLED_SERVER;
|
||||
|
||||
static {
|
||||
SimpleLifecycled<MinecraftServer> lifecycledServer = SimpleLifecycled.invalid();
|
||||
ServerLifecycleEvents.SERVER_STARTED.register(lifecycledServer::newValue);
|
||||
ServerLifecycleEvents.SERVER_STOPPING.register(__ -> lifecycledServer.invalidate());
|
||||
LIFECYCLED_SERVER = lifecycledServer;
|
||||
}
|
||||
|
||||
private FabricPermissionsProvider provider;
|
||||
|
||||
public static FabricWorldEdit inst;
|
||||
@ -113,6 +132,12 @@ public void onInitialize() {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
this.platform = new FabricPlatform(this);
|
||||
|
||||
WorldEdit.getInstance().getPlatformManager().register(platform);
|
||||
|
||||
config = new FabricConfiguration(this);
|
||||
this.provider = getInitialPermissionsProvider();
|
||||
|
||||
WECUIPacketHandler.init();
|
||||
|
||||
@ -129,29 +154,25 @@ public void onInitialize() {
|
||||
}
|
||||
|
||||
private void registerCommands(CommandDispatcher<ServerCommandSource> dispatcher, boolean dedicated) {
|
||||
WorldEdit.getInstance().getEventBus().post(new PlatformsRegisteredEvent());
|
||||
PlatformManager manager = WorldEdit.getInstance().getPlatformManager();
|
||||
if (manager.getPlatforms().isEmpty()) {
|
||||
// We'll register as part of our platform initialization later.
|
||||
return;
|
||||
}
|
||||
|
||||
// This is a re-register (due to /reload), we must add our commands now
|
||||
|
||||
Platform commandsPlatform = manager.queryCapability(Capability.USER_COMMANDS);
|
||||
if (commandsPlatform != platform || !platform.isHookingEvents()) {
|
||||
// We're not in control of commands/events -- do not re-register.
|
||||
// We're not in control of commands/events -- do not register.
|
||||
return;
|
||||
}
|
||||
platform.setNativeDispatcher(dispatcher);
|
||||
platform.registerCommands(manager.getPlatformCommandManager().getCommandManager());
|
||||
}
|
||||
|
||||
private void setupPlatform(MinecraftServer server) {
|
||||
this.platform = new FabricPlatform(this, server);
|
||||
|
||||
WorldEdit.getInstance().getPlatformManager().register(platform);
|
||||
|
||||
this.provider = getInitialPermissionsProvider();
|
||||
List<Command> commands = manager.getPlatformCommandManager().getCommandManager()
|
||||
.getAllCommands().collect(toList());
|
||||
for (Command command : commands) {
|
||||
CommandWrapper.register(dispatcher, command);
|
||||
Set<String> perms = command.getCondition().as(PermissionCondition.class)
|
||||
.map(PermissionCondition::getPermissions)
|
||||
.orElseGet(Collections::emptySet);
|
||||
if (!perms.isEmpty()) {
|
||||
perms.forEach(getPermissionsProvider()::registerPermission);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private FabricPermissionsProvider getInitialPermissionsProvider() {
|
||||
@ -211,22 +232,16 @@ private void onStartingServer(MinecraftServer minecraftServer) {
|
||||
}
|
||||
|
||||
private void onStartServer(MinecraftServer minecraftServer) {
|
||||
FabricAdapter.setServer(minecraftServer);
|
||||
setupPlatform(minecraftServer);
|
||||
setupRegistries(minecraftServer);
|
||||
|
||||
config = new FabricConfiguration(this);
|
||||
config.load();
|
||||
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent());
|
||||
minecraftServer.reloadResources(
|
||||
minecraftServer.getDataPackManager().getEnabledNames()
|
||||
);
|
||||
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent(platform));
|
||||
}
|
||||
|
||||
private void onStopServer(MinecraftServer minecraftServer) {
|
||||
WorldEdit worldEdit = WorldEdit.getInstance();
|
||||
worldEdit.getSessionManager().unload();
|
||||
worldEdit.getPlatformManager().unregister(platform);
|
||||
WorldEdit.getInstance().getEventBus().post(new PlatformUnreadyEvent(platform));
|
||||
}
|
||||
|
||||
private boolean shouldSkip() {
|
||||
|
@ -176,9 +176,8 @@ public void registerCommands(CommandManager manager) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerGameHooks() {
|
||||
// We registered the events already anyway, so we just 'turn them on'
|
||||
hookingEvents = true;
|
||||
public void setGameHooksEnabled(boolean enabled) {
|
||||
this.hookingEvents = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -23,9 +23,14 @@
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.command.util.PermissionCondition;
|
||||
import com.sk89q.worldedit.event.platform.PlatformReadyEvent;
|
||||
import com.sk89q.worldedit.event.platform.PlatformUnreadyEvent;
|
||||
import com.sk89q.worldedit.event.platform.PlatformsRegisteredEvent;
|
||||
import com.sk89q.worldedit.event.platform.SessionIdleEvent;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.extension.platform.Platform;
|
||||
import com.sk89q.worldedit.extension.platform.PlatformManager;
|
||||
import com.sk89q.worldedit.forge.net.handler.InternalPacketHandler;
|
||||
import com.sk89q.worldedit.forge.net.handler.WECUIPacketHandler;
|
||||
import com.sk89q.worldedit.forge.net.packet.LeftClickAirEventMessage;
|
||||
@ -50,6 +55,7 @@
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.CommandEvent;
|
||||
import net.minecraftforge.event.RegisterCommandsEvent;
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
||||
import net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickEmpty;
|
||||
@ -70,15 +76,20 @@
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.enginehub.piston.Command;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.sk89q.worldedit.forge.ForgeAdapter.adaptPlayer;
|
||||
import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
/**
|
||||
* The Forge implementation of WorldEdit.
|
||||
@ -132,6 +143,8 @@ private void init(FMLCommonSetupEvent event) {
|
||||
}
|
||||
}
|
||||
|
||||
setupPlatform();
|
||||
|
||||
WECUIPacketHandler.init();
|
||||
InternalPacketHandler.init();
|
||||
|
||||
@ -143,6 +156,8 @@ private void setupPlatform() {
|
||||
|
||||
WorldEdit.getInstance().getPlatformManager().register(platform);
|
||||
|
||||
config = new ForgeConfiguration(this);
|
||||
|
||||
// TODO if (ModList.get().isLoaded("sponge")) {
|
||||
// this.provider = new ForgePermissionsProvider.SpongePermissionsProvider();
|
||||
// } else {
|
||||
@ -189,6 +204,30 @@ private void setupRegistries(MinecraftServer server) {
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void registerCommands(RegisterCommandsEvent event) {
|
||||
WorldEdit.getInstance().getEventBus().post(new PlatformsRegisteredEvent());
|
||||
|
||||
PlatformManager manager = WorldEdit.getInstance().getPlatformManager();
|
||||
Platform commandsPlatform = manager.queryCapability(Capability.USER_COMMANDS);
|
||||
if (commandsPlatform != platform || !platform.isHookingEvents()) {
|
||||
// We're not in control of commands/events -- do not register.
|
||||
return;
|
||||
}
|
||||
|
||||
List<Command> commands = manager.getPlatformCommandManager().getCommandManager()
|
||||
.getAllCommands().collect(toList());
|
||||
for (Command command : commands) {
|
||||
CommandWrapper.register(event.getDispatcher(), command);
|
||||
Set<String> perms = command.getCondition().as(PermissionCondition.class)
|
||||
.map(PermissionCondition::getPermissions)
|
||||
.orElseGet(Collections::emptySet);
|
||||
if (!perms.isEmpty()) {
|
||||
perms.forEach(getPermissionsProvider()::registerPermission);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void serverAboutToStart(FMLServerAboutToStartEvent event) {
|
||||
final Path delChunks = workingDir.resolve(DELCHUNKS_FILE_NAME);
|
||||
@ -201,17 +240,15 @@ public void serverAboutToStart(FMLServerAboutToStartEvent event) {
|
||||
public void serverStopping(FMLServerStoppingEvent event) {
|
||||
WorldEdit worldEdit = WorldEdit.getInstance();
|
||||
worldEdit.getSessionManager().unload();
|
||||
worldEdit.getPlatformManager().unregister(platform);
|
||||
WorldEdit.getInstance().getEventBus().post(new PlatformUnreadyEvent(platform));
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void serverStarted(FMLServerStartedEvent event) {
|
||||
setupPlatform();
|
||||
setupRegistries(event.getServer());
|
||||
|
||||
config = new ForgeConfiguration(this);
|
||||
config.load();
|
||||
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent());
|
||||
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent(platform));
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
@ -159,9 +159,8 @@ public List<String> getSuggestions(CommandSource source, String arguments, @Null
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerGameHooks() {
|
||||
// We registered the events already anyway, so we just 'turn them on'
|
||||
hookingEvents = true;
|
||||
public void setGameHooksEnabled(boolean enabled) {
|
||||
this.hookingEvents = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -179,7 +179,7 @@ public void serverStopping(GameStoppingServerEvent event) {
|
||||
|
||||
@Listener
|
||||
public void serverStarted(GameStartedServerEvent event) {
|
||||
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent());
|
||||
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent(platform));
|
||||
|
||||
loadAdapter();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user