001/*
002 * PlotSquared, a land and world management plugin for Minecraft.
003 * Copyright (C) IntellectualSites <https://intellectualsites.com>
004 * Copyright (C) IntellectualSites team and contributors
005 *
006 * This program is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * This program is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License
017 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
018 */
019package com.plotsquared.core.command;
020
021import com.google.inject.Inject;
022import com.plotsquared.core.configuration.Settings;
023import com.plotsquared.core.configuration.caption.StaticCaption;
024import com.plotsquared.core.configuration.caption.TranslatableCaption;
025import com.plotsquared.core.permissions.Permission;
026import com.plotsquared.core.player.MetaDataAccess;
027import com.plotsquared.core.player.PlayerMetaDataKeys;
028import com.plotsquared.core.player.PlotPlayer;
029import com.plotsquared.core.plot.Plot;
030import com.plotsquared.core.plot.PlotArea;
031import com.plotsquared.core.plot.PlotId;
032import com.plotsquared.core.plot.schematic.Schematic;
033import com.plotsquared.core.plot.world.PlotAreaManager;
034import com.plotsquared.core.util.SchematicHandler;
035import com.plotsquared.core.util.TimeUtil;
036import com.plotsquared.core.util.task.RunnableVal;
037import com.plotsquared.core.util.task.TaskManager;
038import net.kyori.adventure.text.Component;
039import net.kyori.adventure.text.minimessage.tag.Tag;
040import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
041import org.checkerframework.checker.nullness.qual.NonNull;
042
043import java.net.MalformedURLException;
044import java.net.URL;
045import java.util.Collections;
046import java.util.List;
047
048@CommandDeclaration(command = "load",
049        aliases = "restore",
050        category = CommandCategory.SCHEMATIC,
051        requiredType = RequiredType.NONE,
052        permission = "plots.load",
053        usage = "/plot load")
054public class Load extends SubCommand {
055
056    private final PlotAreaManager plotAreaManager;
057    private final SchematicHandler schematicHandler;
058
059    @Inject
060    public Load(
061            final @NonNull PlotAreaManager plotAreaManager,
062            final @NonNull SchematicHandler schematicHandler
063    ) {
064        this.plotAreaManager = plotAreaManager;
065        this.schematicHandler = schematicHandler;
066    }
067
068    @Override
069    public boolean onCommand(final PlotPlayer<?> player, final String[] args) {
070        final String world = player.getLocation().getWorldName();
071        if (!this.plotAreaManager.hasPlotArea(world)) {
072            player.sendMessage(TranslatableCaption.of("errors.not_in_plot_world"));
073            return false;
074        }
075        final Plot plot = player.getCurrentPlot();
076        if (plot == null) {
077            player.sendMessage(TranslatableCaption.of("errors.not_in_plot"));
078            return false;
079        }
080        if (!plot.hasOwner()) {
081            player.sendMessage(TranslatableCaption.of("info.plot_unowned"));
082            return false;
083        }
084        if (!plot.isOwner(player.getUUID()) && !player.hasPermission(Permission.PERMISSION_ADMIN_COMMAND_LOAD)) {
085            player.sendMessage(TranslatableCaption.of("permission.no_plot_perms"));
086            return false;
087        }
088        if (plot.getRunning() > 0) {
089            player.sendMessage(TranslatableCaption.of("errors.wait_for_timer"));
090            return false;
091        }
092
093        try (final MetaDataAccess<List<String>> metaDataAccess =
094                     player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_SCHEMATICS)) {
095            if (args.length != 0) {
096                if (args.length == 1) {
097                    List<String> schematics = metaDataAccess.get().orElse(null);
098                    if (schematics == null) {
099                        // No schematics found:
100                        player.sendMessage(
101                                TranslatableCaption.of("web.load_null"),
102                                TagResolver.resolver("command", Tag.inserting(Component.text("/plot load")))
103                        );
104                        return false;
105                    }
106                    String schematic;
107                    try {
108                        schematic = schematics.get(Integer.parseInt(args[0]) - 1);
109                    } catch (Exception ignored) {
110                        // use /plot load <index>
111                        player.sendMessage(
112                                TranslatableCaption.of("invalid.not_valid_number"),
113                                TagResolver.resolver("value", Tag.inserting(Component.text("(1, " + schematics.size() + ')')))
114                        );
115                        return false;
116                    }
117                    final URL url;
118                    try {
119                        url = new URL(Settings.Web.URL + "saves/" + player.getUUID() + '/' + schematic);
120                    } catch (MalformedURLException e) {
121                        e.printStackTrace();
122                        player.sendMessage(TranslatableCaption.of("web.load_failed"));
123                        return false;
124                    }
125                    plot.addRunning();
126                    player.sendMessage(TranslatableCaption.of("working.generating_component"));
127                    TaskManager.runTaskAsync(() -> {
128                        Schematic taskSchematic = this.schematicHandler.getSchematic(url);
129                        if (taskSchematic == null) {
130                            plot.removeRunning();
131                            player.sendMessage(
132                                    TranslatableCaption.of("schematics.schematic_invalid"),
133                                    TagResolver.resolver(
134                                            "reason",
135                                            Tag.inserting(Component.text("non-existent or not in gzip format"))
136                                    )
137                            );
138                            return;
139                        }
140                        PlotArea area = plot.getArea();
141                        this.schematicHandler.paste(
142                                taskSchematic,
143                                plot,
144                                0,
145                                area.getMinBuildHeight(),
146                                0,
147                                false,
148                                player,
149                                new RunnableVal<>() {
150                                    @Override
151                                    public void run(Boolean value) {
152                                        plot.removeRunning();
153                                        if (value) {
154                                            player.sendMessage(TranslatableCaption.of("schematics.schematic_paste_success"));
155                                        } else {
156                                            player.sendMessage(TranslatableCaption.of("schematics.schematic_paste_failed"));
157                                        }
158                                    }
159                                }
160                        );
161                    });
162                    return true;
163                }
164                plot.removeRunning();
165                player.sendMessage(
166                        TranslatableCaption.of("commandconfig.command_syntax"),
167                        TagResolver.resolver("value", Tag.inserting(Component.text("/plot load <index>")))
168                );
169                return false;
170            }
171
172            // list schematics
173
174            List<String> schematics = metaDataAccess.get().orElse(null);
175            if (schematics == null) {
176                plot.addRunning();
177                TaskManager.runTaskAsync(() -> {
178                    List<String> schematics1 = this.schematicHandler.getSaves(player.getUUID());
179                    plot.removeRunning();
180                    if ((schematics1 == null) || schematics1.isEmpty()) {
181                        player.sendMessage(TranslatableCaption.of("web.load_failed"));
182                        return;
183                    }
184                    metaDataAccess.set(schematics1);
185                    displaySaves(player);
186                });
187            } else {
188                displaySaves(player);
189            }
190        }
191        return true;
192    }
193
194    public void displaySaves(PlotPlayer<?> player) {
195        try (final MetaDataAccess<List<String>> metaDataAccess =
196                     player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_SCHEMATICS)) {
197            List<String> schematics = metaDataAccess.get().orElse(Collections.emptyList());
198            for (int i = 0; i < Math.min(schematics.size(), 32); i++) {
199                try {
200                    String schematic = schematics.get(i).split("\\.")[0];
201                    String[] split = schematic.split("_");
202                    if (split.length < 5) {
203                        continue;
204                    }
205                    String time = TimeUtil.secToTime((System.currentTimeMillis() / 1000) - Long.parseLong(split[0]));
206                    String world = split[1];
207                    PlotId id = PlotId.fromString(split[2] + ';' + split[3]);
208                    String size = split[4];
209                    String color = "<dark_aqua>";
210                    player.sendMessage(StaticCaption.of("<dark_gray>[</dark_gray><gray>" + (i + 1) + "</gray><dark_aqua>] </dark_aqua>" + color + time + "<dark_gray> | </dark_gray>" + color + world + ';' + id
211                            + "<dark_gray> | </dark_gray>" + color + size + 'x' + size));
212                } catch (Exception e) {
213                    e.printStackTrace();
214                }
215            }
216            player.sendMessage(
217                    TranslatableCaption.of("web.load_list"),
218                    TagResolver.resolver("command", Tag.inserting(Component.text("/plot load #")))
219            );
220        }
221    }
222
223}