Plex-FAWE/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java

383 lines
13 KiB
Java

/*
* 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.sponge;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME;
import com.google.inject.Inject;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.event.platform.PlatformReadyEvent;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.internal.anvil.ChunkDeleter;
import com.sk89q.worldedit.sponge.adapter.AdapterLoadException;
import com.sk89q.worldedit.sponge.adapter.SpongeImplAdapter;
import com.sk89q.worldedit.sponge.adapter.SpongeImplLoader;
import com.sk89q.worldedit.sponge.config.SpongeConfiguration;
import org.bstats.sponge.Metrics2;
import org.slf4j.Logger;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.block.BlockSnapshot;
import org.spongepowered.api.block.BlockType;
import org.spongepowered.api.block.BlockTypes;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.config.ConfigDir;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.block.InteractBlockEvent;
import org.spongepowered.api.event.filter.cause.Root;
import org.spongepowered.api.event.game.state.GameAboutToStartServerEvent;
import org.spongepowered.api.event.game.state.GameInitializationEvent;
import org.spongepowered.api.event.game.state.GamePostInitializationEvent;
import org.spongepowered.api.event.game.state.GamePreInitializationEvent;
import org.spongepowered.api.event.game.state.GameStartedServerEvent;
import org.spongepowered.api.event.game.state.GameStoppingServerEvent;
import org.spongepowered.api.event.item.inventory.InteractItemEvent;
import org.spongepowered.api.item.ItemType;
import org.spongepowered.api.item.inventory.ItemStack;
import org.spongepowered.api.plugin.Plugin;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.scheduler.Task;
import org.spongepowered.api.world.Location;
import org.spongepowered.api.world.World;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
/**
* The Sponge implementation of WorldEdit.
*/
@Plugin(id = SpongeWorldEdit.MOD_ID, name = "WorldEdit",
description = "WorldEdit is an easy-to-use in-game world editor for Minecraft",
url = "https://enginehub.org/worldedit/")
public class SpongeWorldEdit {
@Inject
private Logger logger;
private Metrics2 metrics;
public static final String MOD_ID = "worldedit";
private static final int BSTATS_PLUGIN_ID = 3329;
private SpongePermissionsProvider provider;
@Inject
private PluginContainer container;
private static SpongeWorldEdit inst;
public static PluginContainer container() {
return inst.container;
}
public static SpongeWorldEdit inst() {
return inst;
}
private SpongePlatform platform;
private SpongeImplAdapter spongeAdapter;
@Inject
private SpongeConfiguration config;
@Inject @ConfigDir(sharedRoot = false)
private File workingDir;
@Inject
public SpongeWorldEdit(Metrics2.Factory metricsFactory) {
inst = this;
metrics = metricsFactory.make(BSTATS_PLUGIN_ID);
}
@Listener
public void preInit(GamePreInitializationEvent event) {
// Load configuration
config.load();
Task.builder().interval(30, TimeUnit.SECONDS).execute(ThreadSafeCache.getInstance()).submit(this);
}
@Listener
public void init(GameInitializationEvent event) {
CUIChannelHandler.init();
}
@Listener
public void postInit(GamePostInitializationEvent event) {
logger.info("WorldEdit for Sponge (version " + getInternalVersion() + ") is loaded");
}
@Listener
public void serverAboutToStart(GameAboutToStartServerEvent event) {
if (this.platform != null) {
logger.warn("GameAboutToStartServerEvent occurred when GameStoppingServerEvent hasn't");
WorldEdit.getInstance().getPlatformManager().unregister(platform);
}
final Path delChunks = workingDir.toPath().resolve(DELCHUNKS_FILE_NAME);
if (Files.exists(delChunks)) {
ChunkDeleter.runFromFile(delChunks, true);
}
this.platform = new SpongePlatform(this);
this.provider = new SpongePermissionsProvider();
for (BlockType blockType : Sponge.getRegistry().getAllOf(BlockType.class)) {
// TODO Handle blockstate stuff
String id = blockType.getId();
if (!com.sk89q.worldedit.world.block.BlockType.REGISTRY.keySet().contains(id)) {
com.sk89q.worldedit.world.block.BlockType.REGISTRY.register(id, new com.sk89q.worldedit.world.block.BlockType(id));
}
}
for (ItemType itemType : Sponge.getRegistry().getAllOf(ItemType.class)) {
String id = itemType.getId();
if (!com.sk89q.worldedit.world.item.ItemType.REGISTRY.keySet().contains(id)) {
com.sk89q.worldedit.world.item.ItemType.REGISTRY.register(id, new com.sk89q.worldedit.world.item.ItemType(id));
}
}
WorldEdit.getInstance().getPlatformManager().register(platform);
}
@Listener
public void serverStopping(GameStoppingServerEvent event) {
WorldEdit worldEdit = WorldEdit.getInstance();
worldEdit.getSessionManager().unload();
worldEdit.getPlatformManager().unregister(platform);
}
@Listener
public void serverStarted(GameStartedServerEvent event) {
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent());
loadAdapter();
}
private void loadAdapter() {
WorldEdit worldEdit = WorldEdit.getInstance();
// Attempt to load a Sponge adapter
SpongeImplLoader adapterLoader = new SpongeImplLoader();
try {
adapterLoader.addFromPath(getClass().getClassLoader());
} catch (IOException e) {
logger.warn("Failed to search path for Sponge adapters");
}
try {
adapterLoader.addFromJar(container.getSource().get().toFile());
} catch (IOException e) {
logger.warn("Failed to search " + container.getSource().get().toFile() + " for Sponge adapters", e);
}
try {
spongeAdapter = adapterLoader.loadAdapter();
logger.info("Using " + spongeAdapter.getClass().getCanonicalName() + " as the Sponge adapter");
} catch (AdapterLoadException e) {
Platform platform = worldEdit.getPlatformManager().queryCapability(Capability.WORLD_EDITING);
if (platform instanceof SpongePlatform) {
logger.warn(e.getMessage());
} else {
logger.info("WorldEdit could not find a Sponge adapter for this MC version, " +
"but it seems that you have another implementation of WorldEdit installed (" + platform.getPlatformName() + ") " +
"that handles the world editing.");
}
}
}
public SpongeImplAdapter getAdapter() {
return this.spongeAdapter;
}
@Listener
public void onPlayerItemInteract(InteractItemEvent.Secondary event, @Root Player spongePlayer) {
if (platform == null) {
return;
}
if (!platform.isHookingEvents()) return; // We have to be told to catch these events
WorldEdit we = WorldEdit.getInstance();
SpongePlayer player = wrapPlayer(spongePlayer);
if (we.handleRightClick(player)) {
event.setCancelled(true);
}
}
@Listener
public void onPlayerInteract(InteractBlockEvent event, @Root Player spongePlayer) {
if (platform == null) {
return;
}
if (!platform.isHookingEvents()) return; // We have to be told to catch these events
WorldEdit we = WorldEdit.getInstance();
SpongePlayer player = wrapPlayer(spongePlayer);
com.sk89q.worldedit.world.World world = player.getWorld();
BlockSnapshot targetBlock = event.getTargetBlock();
Optional<Location<World>> optLoc = targetBlock.getLocation();
BlockType interactedType = targetBlock.getState().getType();
if (event instanceof InteractBlockEvent.Primary) {
if (interactedType != BlockTypes.AIR) {
if (!optLoc.isPresent()) {
return;
}
Location<World> loc = optLoc.get();
com.sk89q.worldedit.util.Location pos = new com.sk89q.worldedit.util.Location(
world, loc.getX(), loc.getY(), loc.getZ());
if (we.handleBlockLeftClick(player, pos)) {
event.setCancelled(true);
}
if (we.handleArmSwing(player)) {
event.setCancelled(true);
}
} else {
if (we.handleArmSwing(player)) {
event.setCancelled(true);
}
}
} else if (event instanceof InteractBlockEvent.Secondary) {
if (!optLoc.isPresent()) {
return;
}
Location<World> loc = optLoc.get();
com.sk89q.worldedit.util.Location pos = new com.sk89q.worldedit.util.Location(
world, loc.getX(), loc.getY(), loc.getZ());
if (we.handleBlockRightClick(player, pos)) {
event.setCancelled(true);
}
if (we.handleRightClick(player)) {
event.setCancelled(true);
}
}
}
public static ItemStack toSpongeItemStack(BaseItemStack item) {
return inst().getAdapter().makeSpongeStack(item);
}
/**
* Get the configuration.
*
* @return the Sponge configuration
*/
SpongeConfiguration getConfig() {
return this.config;
}
/**
* Get the WorldEdit proxy for the given player.
*
* @param player the player
* @return the WorldEdit player
*/
public SpongePlayer wrapPlayer(Player player) {
checkNotNull(player);
return new SpongePlayer(platform, player);
}
public Actor wrapCommandSource(CommandSource sender) {
if (sender instanceof Player) {
return wrapPlayer((Player) sender);
}
return new SpongeCommandSender(this, sender);
}
/**
* Get the session for a player.
*
* @param player the player
* @return the session
*/
public LocalSession getSession(Player player) {
checkNotNull(player);
return WorldEdit.getInstance().getSessionManager().get(wrapPlayer(player));
}
/**
* Get the WorldEdit proxy for the given world.
*
* @param world the world
* @return the WorldEdit world
*/
public SpongeWorld getWorld(World world) {
checkNotNull(world);
return getAdapter().getWorld(world);
}
/**
* Get the WorldEdit proxy for the platform.
*
* @return the WorldEdit platform
*/
public Platform getPlatform() {
return this.platform;
}
/**
* Get the working directory where WorldEdit's files are stored.
*
* @return the working directory
*/
public File getWorkingDir() {
return this.workingDir;
}
/**
* Get the version of the WorldEdit Sponge implementation.
*
* @return a version string
*/
String getInternalVersion() {
return container.getVersion().orElse("Unknown");
}
public void setPermissionsProvider(SpongePermissionsProvider provider) {
this.provider = provider;
}
public SpongePermissionsProvider getPermissionsProvider() {
return provider;
}
}