PlotSquared/Core/src/main/java/com/plotsquared/core/command/Template.java

308 lines
14 KiB
Java

/*
* PlotSquared, a land and world management plugin for Minecraft.
* Copyright (C) IntellectualSites <https://intellectualsites.com>
* Copyright (C) IntellectualSites 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.plotsquared.core.command;
import com.google.inject.Inject;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.configuration.ConfigurationNode;
import com.plotsquared.core.configuration.ConfigurationSection;
import com.plotsquared.core.configuration.ConfigurationUtil;
import com.plotsquared.core.configuration.InvalidConfigurationException;
import com.plotsquared.core.configuration.Settings;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.configuration.file.YamlConfiguration;
import com.plotsquared.core.events.TeleportCause;
import com.plotsquared.core.inject.annotations.WorldConfig;
import com.plotsquared.core.inject.annotations.WorldFile;
import com.plotsquared.core.permissions.Permission;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.PlotArea;
import com.plotsquared.core.plot.PlotManager;
import com.plotsquared.core.plot.world.PlotAreaManager;
import com.plotsquared.core.setup.PlotAreaBuilder;
import com.plotsquared.core.setup.SettingsNodesWrapper;
import com.plotsquared.core.util.FileBytes;
import com.plotsquared.core.util.FileUtils;
import com.plotsquared.core.util.SetupUtils;
import com.plotsquared.core.util.TabCompletions;
import com.plotsquared.core.util.WorldUtil;
import com.plotsquared.core.util.task.TaskManager;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
@CommandDeclaration(command = "template",
permission = "plots.admin",
usage = "/plot template [import | export] <world> <template>",
category = CommandCategory.ADMINISTRATION)
public class Template extends SubCommand {
private final PlotAreaManager plotAreaManager;
private final YamlConfiguration worldConfiguration;
private final File worldFile;
private final SetupUtils setupUtils;
private final WorldUtil worldUtil;
@Inject
public Template(
final @NonNull PlotAreaManager plotAreaManager,
@WorldConfig final @NonNull YamlConfiguration worldConfiguration,
@WorldFile final @NonNull File worldFile,
final @NonNull SetupUtils setupUtils,
final @NonNull WorldUtil worldUtil
) {
this.plotAreaManager = plotAreaManager;
this.worldConfiguration = worldConfiguration;
this.worldFile = worldFile;
this.setupUtils = setupUtils;
this.worldUtil = worldUtil;
}
public static boolean extractAllFiles(String world, String template) {
try {
File folder =
FileUtils.getFile(PlotSquared.platform().getDirectory(), Settings.Paths.TEMPLATES);
if (!folder.exists()) {
return false;
}
File output = PlotSquared.platform().getDirectory();
if (!output.exists()) {
output.mkdirs();
}
File input = new File(folder + File.separator + template + ".template");
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(input))) {
ZipEntry ze = zis.getNextEntry();
byte[] buffer = new byte[2048];
while (ze != null) {
if (!ze.isDirectory()) {
String name = ze.getName().replace('\\', File.separatorChar)
.replace('/', File.separatorChar);
File newFile = new File(
(output + File.separator + name).replaceAll("__TEMP_DIR__", world));
File parent = newFile.getParentFile();
if (parent != null) {
parent.mkdirs();
}
try (FileOutputStream fos = new FileOutputStream(newFile)) {
int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
}
}
ze = zis.getNextEntry();
}
zis.closeEntry();
}
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
public static byte[] getBytes(PlotArea plotArea) {
ConfigurationSection section = PlotSquared
.get()
.getWorldConfiguration()
.getConfigurationSection("worlds." + plotArea.getWorldName());
YamlConfiguration config = new YamlConfiguration();
String generator = PlotSquared.platform().setupUtils().getGenerator(plotArea);
if (generator != null) {
config.set("generator.plugin", generator);
}
for (String key : section.getKeys(true)) {
config.set(key, section.get(key));
}
return config.saveToString().getBytes();
}
public static void zipAll(String world, Set<FileBytes> files) throws IOException {
File output = FileUtils.getFile(PlotSquared.platform().getDirectory(), Settings.Paths.TEMPLATES);
output.mkdirs();
try (FileOutputStream fos = new FileOutputStream(
output + File.separator + world + ".template");
ZipOutputStream zos = new ZipOutputStream(fos)) {
for (FileBytes file : files) {
ZipEntry ze = new ZipEntry(file.path);
zos.putNextEntry(ze);
zos.write(file.data);
}
zos.closeEntry();
}
}
@Override
public boolean onCommand(final PlotPlayer<?> player, String[] args) {
if (args.length != 2 && args.length != 3) {
if (args.length == 1) {
if (args[0].equalsIgnoreCase("export")) {
player.sendMessage(
TranslatableCaption.of("commandconfig.command_syntax"),
net.kyori.adventure.text.minimessage.Template.of("value", "/plot template export <world>")
);
return true;
} else if (args[0].equalsIgnoreCase("import")) {
player.sendMessage(
TranslatableCaption.of("commandconfig.command_syntax"),
net.kyori.adventure.text.minimessage.Template.of("value", "/plot template import <world> <template>")
);
return true;
}
}
sendUsage(player);
return true;
}
final String world = args[1];
switch (args[0].toLowerCase()) {
case "import" -> {
if (args.length != 3) {
player.sendMessage(
TranslatableCaption.of("commandconfig.command_syntax"),
net.kyori.adventure.text.minimessage.Template.of("value", "/plot template import <world> <template>")
);
return false;
}
if (this.plotAreaManager.hasPlotArea(world)) {
player.sendMessage(
TranslatableCaption.of("setup.setup_world_taken"),
net.kyori.adventure.text.minimessage.Template.of("value", world)
);
return false;
}
boolean result = extractAllFiles(world, args[2]);
if (!result) {
player.sendMessage(
TranslatableCaption.of("template.invalid_template"),
net.kyori.adventure.text.minimessage.Template.of("value", args[2])
);
return false;
}
File worldFile = FileUtils.getFile(
PlotSquared.platform().getDirectory(),
Settings.Paths.TEMPLATES + File.separator + "tmp-data.yml"
);
YamlConfiguration worldConfig = YamlConfiguration.loadConfiguration(worldFile);
this.worldConfiguration.set("worlds." + world, worldConfig.get(""));
try {
this.worldConfiguration.save(this.worldFile);
this.worldConfiguration.load(this.worldFile);
} catch (InvalidConfigurationException | IOException e) {
e.printStackTrace();
}
String manager =
worldConfig.getString("generator.plugin", PlotSquared.platform().pluginName());
String generator = worldConfig.getString("generator.init", manager);
PlotAreaBuilder builder = PlotAreaBuilder.newBuilder()
.plotAreaType(ConfigurationUtil.getType(worldConfig))
.terrainType(ConfigurationUtil.getTerrain(worldConfig))
.plotManager(manager)
.generatorName(generator)
.settingsNodesWrapper(new SettingsNodesWrapper(new ConfigurationNode[0], null))
.worldName(world);
this.setupUtils.setupWorld(builder);
TaskManager.runTask(() -> {
player.teleport(this.worldUtil.getSpawn(world), TeleportCause.COMMAND_TEMPLATE);
player.sendMessage(TranslatableCaption.of("setup.setup_finished"));
});
return true;
}
case "export" -> {
if (args.length != 2) {
player.sendMessage(
TranslatableCaption.of("commandconfig.command_syntax"),
net.kyori.adventure.text.minimessage.Template.of("value", "/plot template export <world>")
);
return false;
}
final PlotArea area = this.plotAreaManager.getPlotAreaByString(world);
if (area == null) {
player.sendMessage(
TranslatableCaption.of("errors.not_valid_plot_world"),
net.kyori.adventure.text.minimessage.Template.of("value", args[1])
);
return false;
}
final PlotManager manager = area.getPlotManager();
TaskManager.runTaskAsync(() -> {
try {
manager.exportTemplate();
} catch (Exception e) { // Must recover from any exception thrown a third party template manager
e.printStackTrace();
player.sendMessage(
TranslatableCaption.of("template.template_failed"),
net.kyori.adventure.text.minimessage.Template.of("value", e.getMessage())
);
return;
}
player.sendMessage(TranslatableCaption.of("setup.setup_finished"));
});
return true;
}
default -> sendUsage(player);
}
return false;
}
@Override
public Collection<Command> tab(final PlotPlayer<?> player, final String[] args, final boolean space) {
if (args.length == 1) {
final List<String> completions = new LinkedList<>();
if (player.hasPermission(Permission.PERMISSION_TEMPLATE_EXPORT)) {
completions.add("export");
}
if (player.hasPermission(Permission.PERMISSION_TEMPLATE_IMPORT)) {
completions.add("import");
}
final List<Command> commands = completions.stream().filter(completion -> completion
.toLowerCase()
.startsWith(args[0].toLowerCase()))
.map(completion -> new Command(
null,
true,
completion,
"",
RequiredType.NONE,
CommandCategory.ADMINISTRATION
) {
}).collect(Collectors.toCollection(LinkedList::new));
if (player.hasPermission(Permission.PERMISSION_TEMPLATE) && args[0].length() > 0) {
commands.addAll(TabCompletions.completePlayers(player, args[0], Collections.emptyList()));
}
return commands;
}
return TabCompletions.completePlayers(player, String.join(",", args).trim(), Collections.emptyList());
}
}