Added support for platforms to declare capabilities.

Platforms can declare certain capabilities and a suggested preference
for the platform for each capability. WorldEdit can then choose
the best platform for a given capability.

Examples of capabilities include providing configuration, registering
game hooks/events, performing changes to the world, or checking
permissions/authorization.
This commit is contained in:
sk89q 2014-06-27 01:11:35 -07:00
parent d9cea950b0
commit e52ca6661f
13 changed files with 416 additions and 131 deletions

View File

@ -25,6 +25,8 @@ import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.CommandsManager; import com.sk89q.minecraft.util.commands.CommandsManager;
import com.sk89q.worldedit.*; import com.sk89q.worldedit.*;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Preference;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Server; import org.bukkit.Server;
@ -32,16 +34,14 @@ import org.bukkit.World;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class BukkitServerInterface extends ServerInterface { public class BukkitServerInterface extends ServerInterface {
public Server server; public Server server;
public WorldEditPlugin plugin; public WorldEditPlugin plugin;
private CommandRegistration dynamicCommands; private CommandRegistration dynamicCommands;
private BukkitBiomeTypes biomes; private BukkitBiomeTypes biomes;
private boolean hookingEvents;
public BukkitServerInterface(WorldEditPlugin plugin, Server server) { public BukkitServerInterface(WorldEditPlugin plugin, Server server) {
this.plugin = plugin; this.plugin = plugin;
@ -50,6 +50,10 @@ public class BukkitServerInterface extends ServerInterface {
dynamicCommands = new CommandRegistration(plugin); dynamicCommands = new CommandRegistration(plugin);
} }
boolean isHookingEvents() {
return hookingEvents;
}
@Override @Override
public int resolveItem(String name) { public int resolveItem(String name) {
Material mat = Material.matchMaterial(name); Material mat = Material.matchMaterial(name);
@ -114,6 +118,11 @@ public class BukkitServerInterface extends ServerInterface {
dynamicCommands.register(toRegister); dynamicCommands.register(toRegister);
} }
@Override
public void registerGameHooks() {
hookingEvents = true;
}
@Override @Override
public LocalConfiguration getConfiguration() { public LocalConfiguration getConfiguration() {
return plugin.getLocalConfiguration(); return plugin.getLocalConfiguration();
@ -134,6 +143,17 @@ public class BukkitServerInterface extends ServerInterface {
return plugin.getDescription().getVersion(); return plugin.getDescription().getVersion();
} }
@Override
public Map<Capability, Preference> getCapabilities() {
Map<Capability, Preference> capabilities = new EnumMap<Capability, Preference>(Capability.class);
capabilities.put(Capability.CONFIGURATION, Preference.NORMAL);
capabilities.put(Capability.GAME_HOOKS, Preference.PREFERRED);
capabilities.put(Capability.PERMISSIONS, Preference.PREFERRED);
capabilities.put(Capability.USER_COMMANDS, Preference.PREFERRED);
capabilities.put(Capability.WORLD_EDITING, Preference.PREFER_OTHERS);
return capabilities;
}
public void unregisterCommands() { public void unregisterCommands() {
dynamicCommands.unregisterCommands(); dynamicCommands.unregisterCommands();
} }

View File

@ -69,11 +69,19 @@ public class WorldEditListener implements Listener {
*/ */
@EventHandler @EventHandler
public void onPlayerQuit(PlayerQuitEvent event) { public void onPlayerQuit(PlayerQuitEvent event) {
if (!plugin.getInternalPlatform().isHookingEvents()) {
return;
}
plugin.getWorldEdit().markExpire(plugin.wrapPlayer(event.getPlayer())); plugin.getWorldEdit().markExpire(plugin.wrapPlayer(event.getPlayer()));
} }
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onGamemode(PlayerGameModeChangeEvent event) { public void onGamemode(PlayerGameModeChangeEvent event) {
if (!plugin.getInternalPlatform().isHookingEvents()) {
return;
}
// this will automatically refresh their sesssion, we don't have to do anything // this will automatically refresh their sesssion, we don't have to do anything
WorldEdit.getInstance().getSession(plugin.wrapPlayer(event.getPlayer())); WorldEdit.getInstance().getSession(plugin.wrapPlayer(event.getPlayer()));
} }
@ -114,6 +122,10 @@ public class WorldEditListener implements Listener {
*/ */
@EventHandler @EventHandler
public void onPlayerInteract(PlayerInteractEvent event) { public void onPlayerInteract(PlayerInteractEvent event) {
if (!plugin.getInternalPlatform().isHookingEvents()) {
return;
}
if (event.useItemInHand() == Result.DENY) { if (event.useItemInHand() == Result.DENY) {
return; return;
} }

View File

@ -26,13 +26,9 @@ import com.sk89q.worldedit.bukkit.selections.CuboidSelection;
import com.sk89q.worldedit.bukkit.selections.CylinderSelection; import com.sk89q.worldedit.bukkit.selections.CylinderSelection;
import com.sk89q.worldedit.bukkit.selections.Polygonal2DSelection; import com.sk89q.worldedit.bukkit.selections.Polygonal2DSelection;
import com.sk89q.worldedit.bukkit.selections.Selection; import com.sk89q.worldedit.bukkit.selections.Selection;
import com.sk89q.worldedit.extension.platform.PlatformRejectionException; import com.sk89q.worldedit.event.platform.PlatformReadyEvent;
import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.*;
import com.sk89q.worldedit.regions.CylinderRegion;
import com.sk89q.worldedit.regions.Polygonal2DRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionSelector;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -106,21 +102,19 @@ public class WorldEditPlugin extends JavaPlugin {
// Setup interfaces // Setup interfaces
server = new BukkitServerInterface(this, getServer()); server = new BukkitServerInterface(this, getServer());
controller = WorldEdit.getInstance(); controller = WorldEdit.getInstance();
try { controller.getPlatformManager().register(server);
controller.getPlatformManager().register(server); api = new WorldEditAPI(this);
api = new WorldEditAPI(this); getServer().getMessenger().registerIncomingPluginChannel(this, CUI_PLUGIN_CHANNEL, new CUIChannelListener(this));
getServer().getMessenger().registerIncomingPluginChannel(this, CUI_PLUGIN_CHANNEL, new CUIChannelListener(this)); getServer().getMessenger().registerOutgoingPluginChannel(this, CUI_PLUGIN_CHANNEL);
getServer().getMessenger().registerOutgoingPluginChannel(this, CUI_PLUGIN_CHANNEL); // Now we can register events!
// Now we can register events! getServer().getPluginManager().registerEvents(new WorldEditListener(this), this);
getServer().getPluginManager().registerEvents(new WorldEditListener(this), this);
getServer().getScheduler().runTaskTimerAsynchronously(this, getServer().getScheduler().runTaskTimerAsynchronously(this, new SessionTimer(controller, getServer()), 120, 120);
new SessionTimer(controller, getServer()), 120, 120);
} catch (PlatformRejectionException e) { // If we are on MCPC+/Cauldron, then Forge will have already loaded
throw new RuntimeException( // Forge WorldEdit and there's (probably) not going to be any other
"WorldEdit rejected the Bukkit implementation of WorldEdit! This is strange and should " + // platforms to be worried about... at the current time of writing
"not have happened. Please report this error.", e); WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent());
}
} }
private void copyNmsBlockClasses(File target) { private void copyNmsBlockClasses(File target) {
@ -357,6 +351,10 @@ public class WorldEditPlugin extends JavaPlugin {
return server; return server;
} }
BukkitServerInterface getInternalPlatform() {
return server;
}
/** /**
* Get WorldEdit. * Get WorldEdit.
* *

View File

@ -23,6 +23,8 @@ import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.worldedit.BiomeTypes; import com.sk89q.worldedit.BiomeTypes;
import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.ServerInterface; import com.sk89q.worldedit.ServerInterface;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Preference;
import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.FMLCommonHandler;
import net.minecraft.command.CommandBase; import net.minecraft.command.CommandBase;
import net.minecraft.command.ICommand; import net.minecraft.command.ICommand;
@ -34,21 +36,26 @@ import net.minecraft.server.MinecraftServer;
import net.minecraft.world.WorldServer; import net.minecraft.world.WorldServer;
import net.minecraftforge.common.DimensionManager; import net.minecraftforge.common.DimensionManager;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.List;
class ForgePlatform extends ServerInterface { class ForgePlatform extends ServerInterface {
private final ForgeWorldEdit mod; private final ForgeWorldEdit mod;
private final MinecraftServer server; private final MinecraftServer server;
private final ForgeBiomeTypes biomes; private final ForgeBiomeTypes biomes;
private boolean hookingEvents = false;
public ForgePlatform(ForgeWorldEdit mod) { ForgePlatform(ForgeWorldEdit mod) {
this.mod = mod; this.mod = mod;
this.server = FMLCommonHandler.instance().getMinecraftServerInstance(); this.server = FMLCommonHandler.instance().getMinecraftServerInstance();
this.biomes = new ForgeBiomeTypes(); this.biomes = new ForgeBiomeTypes();
} }
boolean isHookingEvents() {
return hookingEvents;
}
@Override
public int resolveItem(String name) { public int resolveItem(String name) {
if (name == null) return 0; if (name == null) return 0;
for (Item item : Item.itemsList) { for (Item item : Item.itemsList) {
@ -65,21 +72,26 @@ class ForgePlatform extends ServerInterface {
return 0; return 0;
} }
@Override
public boolean isValidMobType(String type) { public boolean isValidMobType(String type) {
return EntityList.stringToClassMapping.containsKey(type); return EntityList.stringToClassMapping.containsKey(type);
} }
@Override
public void reload() { public void reload() {
} }
@Override
public BiomeTypes getBiomes() { public BiomeTypes getBiomes() {
return this.biomes; return this.biomes;
} }
@Override
public int schedule(long delay, long period, Runnable task) { public int schedule(long delay, long period, Runnable task) {
return -1; return -1;
} }
@Override
public List<? extends com.sk89q.worldedit.world.World> getWorlds() { public List<? extends com.sk89q.worldedit.world.World> getWorlds() {
List<WorldServer> worlds = Arrays.asList(DimensionManager.getWorlds()); List<WorldServer> worlds = Arrays.asList(DimensionManager.getWorlds());
List<com.sk89q.worldedit.world.World> ret = new ArrayList<com.sk89q.worldedit.world.World>(worlds.size()); List<com.sk89q.worldedit.world.World> ret = new ArrayList<com.sk89q.worldedit.world.World>(worlds.size());
@ -125,6 +137,12 @@ class ForgePlatform extends ServerInterface {
} }
} }
@Override
public void registerGameHooks() {
// We registered the events already anyway, so we just 'turn them on'
hookingEvents = true;
}
@Override @Override
public LocalConfiguration getConfiguration() { public LocalConfiguration getConfiguration() {
return mod.getConfig(); return mod.getConfig();
@ -144,4 +162,16 @@ class ForgePlatform extends ServerInterface {
public String getPlatformVersion() { public String getPlatformVersion() {
return mod.getInternalVersion(); return mod.getInternalVersion();
} }
@Override
public Map<Capability, Preference> getCapabilities() {
Map<Capability, Preference> capabilities = new EnumMap<Capability, Preference>(Capability.class);
capabilities.put(Capability.CONFIGURATION, Preference.PREFER_OTHERS);
capabilities.put(Capability.GAME_HOOKS, Preference.NORMAL);
capabilities.put(Capability.PERMISSIONS, Preference.PREFER_OTHERS);
capabilities.put(Capability.USER_COMMANDS, Preference.NORMAL);
capabilities.put(Capability.WORLD_EDITING, Preference.PREFERRED);
return capabilities;
}
} }

View File

@ -24,8 +24,8 @@ import com.google.common.io.Closer;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldVector; import com.sk89q.worldedit.WorldVector;
import com.sk89q.worldedit.event.platform.PlatformReadyEvent;
import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extension.platform.PlatformRejectionException;
import com.sk89q.worldedit.internal.LocalWorldAdapter; import com.sk89q.worldedit.internal.LocalWorldAdapter;
import cpw.mods.fml.common.FMLLog; import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.Mod;
@ -103,11 +103,8 @@ public class ForgeWorldEdit {
} }
this.platform = new ForgePlatform(this); this.platform = new ForgePlatform(this);
try {
WorldEdit.getInstance().getPlatformManager().register(platform); WorldEdit.getInstance().getPlatformManager().register(platform);
} catch (PlatformRejectionException e) {
throw new RuntimeException("Failed to register with WorldEdit", e);
}
} }
@EventHandler @EventHandler
@ -115,6 +112,11 @@ public class ForgeWorldEdit {
WorldEdit.getInstance().getPlatformManager().unregister(platform); WorldEdit.getInstance().getPlatformManager().unregister(platform);
} }
@EventHandler
public void serverStarted(FMLServerStartedEvent event) {
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent());
}
@ForgeSubscribe @ForgeSubscribe
public void onCommandEvent(CommandEvent event) { public void onCommandEvent(CommandEvent event) {
if ((event.sender instanceof EntityPlayerMP)) { if ((event.sender instanceof EntityPlayerMP)) {
@ -128,6 +130,8 @@ public class ForgeWorldEdit {
@ForgeSubscribe @ForgeSubscribe
public void onPlayerInteract(PlayerInteractEvent event) { public void onPlayerInteract(PlayerInteractEvent event) {
if (!platform.isHookingEvents()) return; // We have to be told to catch these events
if (event.useItem == Result.DENY || event.entity.worldObj.isRemote) return; if (event.useItem == Result.DENY || event.entity.worldObj.isRemote) return;
WorldEdit we = WorldEdit.getInstance(); WorldEdit we = WorldEdit.getInstance();

View File

@ -56,19 +56,11 @@ public class WorldEditCommands {
player.print("https://github.com/sk89q/worldedit/"); player.print("https://github.com/sk89q/worldedit/");
PlatformManager pm = we.getPlatformManager(); PlatformManager pm = we.getPlatformManager();
Platform primary = pm.getPrimaryPlatform();
player.printDebug(""); player.printDebug("");
player.printDebug("Platforms:"); player.printDebug("Platforms:");
for (Platform platform : pm.getPlatforms()) { for (Platform platform : pm.getPlatforms()) {
String prefix = ""; player.printDebug(String.format("- %s v%s (WE v%s)", platform.getPlatformName(), platform.getPlatformVersion(), platform.getVersion()));
if (primary != null && primary.equals(platform)) {
prefix = "[PRIMARY] ";
}
player.printDebug(String.format("- %s%s v%s (WE v%s)",
prefix, platform.getPlatformName(), platform.getPlatformVersion(), platform.getVersion()));
} }
} }

View File

@ -0,0 +1,29 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.event.platform;
import com.sk89q.worldedit.event.Event;
/**
* Raised when a platform thinks that all the platforms have had a chance to
* register themselves.
*/
public class PlatformReadyEvent extends Event {
}

View File

@ -0,0 +1,81 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.extension.platform;
/**
* A collection of capabilities that a {@link Platform} may support.
*/
public enum Capability {
/**
* The capability of registering game hooks to catch events such as
* a player clicking a block.
*/
GAME_HOOKS {
@Override
void initialize(PlatformManager platformManager, Platform platform) {
platform.registerGameHooks();
}
@Override
void unload(PlatformManager platformManager, Platform platform) {
}
},
/**
* The capability of providing configuration.
*/
CONFIGURATION,
/**
* The capability of handling user commands entered in chat or console.
*/
USER_COMMANDS {
@Override
void initialize(PlatformManager platformManager, Platform platform) {
platformManager.getCommandManager().register(platform);
}
@Override
void unload(PlatformManager platformManager, Platform platform) {
platformManager.getCommandManager().unregister();
}
},
/**
* The capability of a platform to assess whether a given
* {@link Actor} has sufficient authorization to perform a task.
*/
PERMISSIONS,
/**
* The capability of a platform to perform modifications to a world.
*/
WORLD_EDITING;
void initialize(PlatformManager platformManager, Platform platform) {
}
void unload(PlatformManager platformManager, Platform platform) {
}
}

View File

@ -19,31 +19,24 @@
package com.sk89q.worldedit.extension.platform; package com.sk89q.worldedit.extension.platform;
import com.sk89q.worldedit.WorldEditException;
/** /**
* Thrown when a platform registration request is rejected, which may * Thrown when no capable platform is found.
* be because another platform is already registered.
*/ */
public class PlatformRejectionException extends WorldEditException { public class NoCapablePlatformException extends RuntimeException {
/** public NoCapablePlatformException() {
* Create with a message. }
*
* @param message the message public NoCapablePlatformException(String message) {
*/
public PlatformRejectionException(String message) {
super(message); super(message);
} }
/** public NoCapablePlatformException(String message, Throwable cause) {
* Create with a message and a cause.
*
* @param message the message
* @param cause the cause
*/
public PlatformRejectionException(String message, Throwable cause) {
super(message, cause); super(message, cause);
} }
public NoCapablePlatformException(Throwable cause) {
super(cause);
}
} }

View File

@ -27,6 +27,7 @@ import com.sk89q.worldedit.LocalPlayer;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* Represents a platform that WorldEdit has been implemented for. * Represents a platform that WorldEdit has been implemented for.
@ -82,6 +83,11 @@ public interface Platform {
void onCommandRegistration(List<Command> commands, CommandsManager<LocalPlayer> manager); void onCommandRegistration(List<Command> commands, CommandsManager<LocalPlayer> manager);
/**
* Register game hooks.
*/
void registerGameHooks();
/** /**
* Get the configuration from this platform. * Get the configuration from this platform.
* *
@ -116,4 +122,13 @@ public interface Platform {
*/ */
String getPlatformVersion(); String getPlatformVersion();
/**
* Get a map of advertised capabilities of this platform, where each key
* in the given map is a supported capability and the respective value
* indicates the preference for this platform for that given capability.
*
* @return a map of capabilities
*/
Map<Capability, Preference> getCapabilities();
} }

View File

@ -20,10 +20,12 @@
package com.sk89q.worldedit.extension.platform; package com.sk89q.worldedit.extension.platform;
import com.sk89q.worldedit.*; import com.sk89q.worldedit.*;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.command.tool.*; import com.sk89q.worldedit.command.tool.*;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.platform.BlockInteractEvent; import com.sk89q.worldedit.event.platform.BlockInteractEvent;
import com.sk89q.worldedit.event.platform.Interaction; import com.sk89q.worldedit.event.platform.Interaction;
import com.sk89q.worldedit.event.platform.PlatformReadyEvent;
import com.sk89q.worldedit.event.platform.PlayerInputEvent; import com.sk89q.worldedit.event.platform.PlayerInputEvent;
import com.sk89q.worldedit.internal.ServerInterfaceAdapter; import com.sk89q.worldedit.internal.ServerInterfaceAdapter;
import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.regions.RegionSelector;
@ -31,8 +33,8 @@ import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.eventbus.Subscribe; import com.sk89q.worldedit.util.eventbus.Subscribe;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.*;
import java.util.List; import java.util.Map.Entry;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -48,11 +50,11 @@ public class PlatformManager {
private static final Logger logger = Logger.getLogger(PlatformManager.class.getCanonicalName()); private static final Logger logger = Logger.getLogger(PlatformManager.class.getCanonicalName());
private final LocalConfiguration defaultConfig = new DefaultConfiguration();
private final List<Platform> platforms = new ArrayList<Platform>();
private final WorldEdit worldEdit; private final WorldEdit worldEdit;
private final CommandManager commandManager; private final CommandManager commandManager;
private @Nullable Platform primary = null; private final List<Platform> platforms = new ArrayList<Platform>();
private final Map<Capability, Platform> preferences = new EnumMap<Capability, Platform>(Capability.class);
private @Nullable String firstSeenVersion;
/** /**
* Create a new platform manager. * Create a new platform manager.
@ -72,56 +74,128 @@ public class PlatformManager {
* Register a platform with WorldEdit. * Register a platform with WorldEdit.
* *
* @param platform the platform * @param platform the platform
* @throws PlatformRejectionException thrown if the registration is rejected
*/ */
public synchronized void register(Platform platform) throws PlatformRejectionException { public synchronized void register(Platform platform) {
checkNotNull(platform); checkNotNull(platform);
logger.log(Level.FINE, "Got request to register " + platform.getClass() + " with WorldEdit [" + super.toString() + "]"); logger.log(Level.FINE, "Got request to register " + platform.getClass() + " with WorldEdit [" + super.toString() + "]");
// Just add the platform to the list of platforms: we'll pick favorites
// once all the platforms have been loaded
platforms.add(platform); platforms.add(platform);
// Register primary platform // Make sure that versions are in sync
if (this.primary == null) { if (firstSeenVersion != null) {
commandManager.register(platform); if (!firstSeenVersion.equals(platform.getVersion())) {
this.primary = platform;
} else {
// Make sure that versions are in sync
if (!primary.getVersion().equals(platform.getVersion())) {
logger.log(Level.WARNING, logger.log(Level.WARNING,
"\n**********************************************\n" + "\n**********************************************\n" +
"** There is a mismatch in available WorldEdit platforms!\n" + "** You have WorldEdit installed for multiple platforms in the same \n" +
"** game/program. This is OK except that you have different WorldEdit versions\n" +
"** installed (i.e. {0} and {1}).\n" +
"**\n" + "**\n" +
"** {0} v{1} is trying to register WE version v{2}\n" + "** WorldEdit has seen both versions {0} and {1}.\n" +
"** but the primary platform, {3} v{4}, uses WE version v{5}\n" +
"**\n" + "**\n" +
"** Things may break! Please make sure that your WE versions are in sync.\n" + "** Things may break! Please make sure that your WE versions are in sync.\n" +
"**********************************************\n", "**********************************************\n",
new Object[]{ new Object[]{
platform.getClass(), platform.getPlatformVersion(), platform.getVersion(), firstSeenVersion, platform.getVersion()
primary.getClass(), primary.getPlatformVersion(), primary.getVersion()
}); });
} }
} else {
firstSeenVersion = platform.getVersion();
} }
} }
/** /**
* Unregister a platform from WorldEdit. * Unregister a platform from WorldEdit.
* </p>
* If the platform has been chosen for any capabilities, then a new
* platform will be found.
* *
* @param platform the platform * @param platform the platform
*/ */
public synchronized boolean unregister(Platform platform) { public synchronized boolean unregister(Platform platform) {
checkNotNull(platform); checkNotNull(platform);
boolean removed = platforms.remove(platform); boolean removed = platforms.remove(platform);
if (removed) { if (removed) {
logger.log(Level.FINE, "Unregistering " + platform.getClass().getCanonicalName() + " from WorldEdit"); logger.log(Level.FINE, "Unregistering " + platform.getClass().getCanonicalName() + " from WorldEdit");
if (platform == primary) { boolean choosePreferred = false;
primary = null;
commandManager.unregister(); // Check whether this platform was chosen to be the preferred one
// for any capability and be sure to remove it
Iterator<Entry<Capability, Platform>> it = preferences.entrySet().iterator();
while (it.hasNext()) {
Entry<Capability, Platform> entry = it.next();
if (entry.getValue().equals(platform)) {
entry.getKey().unload(this, entry.getValue());
it.remove();
choosePreferred = true; // Have to choose new favorites
}
}
if (choosePreferred) {
choosePreferred();
} }
} }
return removed; return removed;
} }
/**
* Get the preferred platform for handling a certain capability. Returns
* null if none is available.
*
* @param capability the capability
* @return the platform
* @throws NoCapablePlatformException thrown if no platform is capable
*/
public synchronized Platform queryCapability(Capability capability) throws NoCapablePlatformException {
Platform platform = preferences.get(checkNotNull(capability));
if (platform != null) {
return platform;
} else {
throw new NoCapablePlatformException("No platform was found supporting " + capability.name());
}
}
/**
* Choose preferred platforms and perform necessary initialization.
*/
private synchronized void choosePreferred() {
for (Capability capability : Capability.values()) {
Platform preferred = findMostPreferred(capability);
if (preferred != null) {
preferences.put(capability, preferred);
capability.initialize(this, preferred);
}
}
}
/**
* Find the most preferred platform for a given capability from the list of
* platforms. This does not use the map of preferred platforms.
*
* @param capability the capability
* @return the most preferred platform, or null if no platform was found
*/
private synchronized @Nullable Platform findMostPreferred(Capability capability) {
Platform preferred = null;
Preference highest = null;
for (Platform platform : platforms) {
Preference preference = platform.getCapabilities().get(capability);
if (preference != null && (highest == null || preference.isPreferredOver(highest))) {
preferred = platform;
highest = preference;
}
}
return preferred;
}
/** /**
* Get a list of loaded platforms. * Get a list of loaded platforms.
* </p> * </p>
@ -133,15 +207,6 @@ public class PlatformManager {
return new ArrayList<Platform>(platforms); return new ArrayList<Platform>(platforms);
} }
/**
* Get the primary platform.
*
* @return the primary platform (may be null)
*/
public @Nullable Platform getPrimaryPlatform() {
return primary;
}
/** /**
* Get the command manager. * Get the command manager.
* *
@ -160,26 +225,7 @@ public class PlatformManager {
* @return the configuration * @return the configuration
*/ */
public LocalConfiguration getConfiguration() { public LocalConfiguration getConfiguration() {
Platform platform = primary; return queryCapability(Capability.CONFIGURATION).getConfiguration();
if (platform != null) {
return platform.getConfiguration();
} else {
return defaultConfig;
}
}
/**
* Return a {@link Platform}.
*
* @return a {@link Platform}
* @throws IllegalStateException if no platform has been registered
*/
public Platform getPlatform() throws IllegalStateException {
Platform platform = primary;
if (platform != null) {
return platform;
} else {
throw new IllegalStateException("No platform has been registered");
}
} }
/** /**
@ -188,19 +234,17 @@ public class PlatformManager {
* @return a {@link ServerInterface} * @return a {@link ServerInterface}
* @throws IllegalStateException if no platform has been registered * @throws IllegalStateException if no platform has been registered
*/ */
@SuppressWarnings("deprecation")
public ServerInterface getServerInterface() throws IllegalStateException { public ServerInterface getServerInterface() throws IllegalStateException {
Platform platform = primary; return ServerInterfaceAdapter.adapt(queryCapability(Capability.USER_COMMANDS));
if (platform != null) {
if (platform instanceof ServerInterface) {
return (ServerInterface) platform;
} else {
return ServerInterfaceAdapter.adapt(platform);
}
} else {
throw new IllegalStateException("No platform has been registered");
}
} }
@Subscribe
public void handlePlatformReady(PlatformReadyEvent event) {
choosePreferred();
}
@SuppressWarnings("deprecation")
@Subscribe @Subscribe
public void handleBlockInteract(BlockInteractEvent event) { public void handleBlockInteract(BlockInteractEvent event) {
Actor actor = event.getCause(); Actor actor = event.getCause();
@ -288,6 +332,7 @@ public class PlatformManager {
} }
} }
@SuppressWarnings("deprecation")
@Subscribe @Subscribe
public void handlePlayerInput(PlayerInputEvent event) { public void handlePlayerInput(PlayerInputEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
@ -370,13 +415,5 @@ public class PlatformManager {
} }
} }
/**
* A default configuration for when none is set.
*/
private static class DefaultConfiguration extends LocalConfiguration {
@Override
public void load() {
}
}
} }

View File

@ -0,0 +1,59 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.extension.platform;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Indicates the preference of a platform for a particular
* {@link Capability}.
*/
public enum Preference {
/**
* Indicates that the platform should be preferred for a given capability.
*/
PREFERRED,
/**
* Indicates that preference for a platform is neutral for a given
* capability.
*/
NORMAL,
/**
* Indicates that there should not be a preference for the platform for
* a given capability.
*/
PREFER_OTHERS;
/**
* Returns whether this given preference is preferred over the given
* other preference.
*
* @param other the other preference
* @return true if this preference is greater
*/
public boolean isPreferredOver(Preference other) {
checkNotNull(other);
return ordinal() < other.ordinal();
}
}

View File

@ -21,11 +21,17 @@ package com.sk89q.worldedit.internal;
import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandsManager; import com.sk89q.minecraft.util.commands.CommandsManager;
import com.sk89q.worldedit.*; import com.sk89q.worldedit.BiomeTypes;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalPlayer;
import com.sk89q.worldedit.ServerInterface;
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 com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import java.util.List; import java.util.List;
import java.util.Map;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
@ -87,6 +93,10 @@ public class ServerInterfaceAdapter extends ServerInterface {
platform.onCommandRegistration(commands, manager); platform.onCommandRegistration(commands, manager);
} }
@Override
public void registerGameHooks() {
}
@Override @Override
public LocalConfiguration getConfiguration() { public LocalConfiguration getConfiguration() {
return platform.getConfiguration(); return platform.getConfiguration();
@ -107,6 +117,11 @@ public class ServerInterfaceAdapter extends ServerInterface {
return platform.getPlatformVersion(); return platform.getPlatformVersion();
} }
@Override
public Map<Capability, Preference> getCapabilities() {
return platform.getCapabilities();
}
/** /**
* Adapt an {@link Platform} instance into a {@link ServerInterface}. * Adapt an {@link Platform} instance into a {@link ServerInterface}.
* *