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.URI;
045import java.net.URL;
046import java.util.Collections;
047import java.util.List;
048
049@CommandDeclaration(command = "load",
050        aliases = "restore",
051        category = CommandCategory.SCHEMATIC,
052        requiredType = RequiredType.NONE,
053        permission = "plots.load",
054        usage = "/plot load")
055public class Load extends SubCommand {
056
057    private final PlotAreaManager plotAreaManager;
058    private final SchematicHandler schematicHandler;
059
060    @Inject
061    public Load(
062            final @NonNull PlotAreaManager plotAreaManager,
063            final @NonNull SchematicHandler schematicHandler
064    ) {
065        this.plotAreaManager = plotAreaManager;
066        this.schematicHandler = schematicHandler;
067    }
068
069    @Override
070    public boolean onCommand(final PlotPlayer<?> player, final String[] args) {
071        final String world = player.getLocation().getWorldName();
072        if (!this.plotAreaManager.hasPlotArea(world)) {
073            player.sendMessage(TranslatableCaption.of("errors.not_in_plot_world"));
074            return false;
075        }
076        final Plot plot = player.getCurrentPlot();
077        if (plot == null) {
078            player.sendMessage(TranslatableCaption.of("errors.not_in_plot"));
079            return false;
080        }
081        if (!plot.hasOwner()) {
082            player.sendMessage(TranslatableCaption.of("info.plot_unowned"));
083            return false;
084        }
085        if (!plot.isOwner(player.getUUID()) && !player.hasPermission(Permission.PERMISSION_ADMIN_COMMAND_LOAD)) {
086            player.sendMessage(TranslatableCaption.of("permission.no_plot_perms"));
087            return false;
088        }
089        if (plot.getRunning() > 0) {
090            player.sendMessage(TranslatableCaption.of("errors.wait_for_timer"));
091            return false;
092        }
093
094        try (final MetaDataAccess<List<String>> metaDataAccess =
095                     player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_SCHEMATICS)) {
096            if (args.length != 0) {
097                if (args.length == 1) {
098                    List<String> schematics = metaDataAccess.get().orElse(null);
099                    if (schematics == null) {
100                        // No schematics found:
101                        player.sendMessage(
102                                TranslatableCaption.of("web.load_null"),
103                                TagResolver.resolver("command", Tag.inserting(Component.text("/plot load")))
104                        );
105                        return false;
106                    }
107                    String schematic;
108                    try {
109                        schematic = schematics.get(Integer.parseInt(args[0]) - 1);
110                    } catch (Exception ignored) {
111                        // use /plot load <index>
112                        player.sendMessage(
113                                TranslatableCaption.of("invalid.not_valid_number"),
114                                TagResolver.resolver("value", Tag.inserting(Component.text("(1, " + schematics.size() + ')')))
115                        );
116                        return false;
117                    }
118                    final URL url;
119                    try {
120                        url = URI.create(Settings.Web.URL + "saves/" + player.getUUID() + '/' + schematic).toURL();
121                    } catch (MalformedURLException e) {
122                        e.printStackTrace();
123                        player.sendMessage(TranslatableCaption.of("web.load_failed"));
124                        return false;
125                    }
126                    plot.addRunning();
127                    player.sendMessage(TranslatableCaption.of("working.generating_component"));
128                    TaskManager.runTaskAsync(() -> {
129                        Schematic taskSchematic = this.schematicHandler.getSchematic(url);
130                        if (taskSchematic == null) {
131                            plot.removeRunning();
132                            player.sendMessage(
133                                    TranslatableCaption.of("schematics.schematic_invalid"),
134                                    TagResolver.resolver(
135                                            "reason",
136                                            Tag.inserting(Component.text("non-existent or not in gzip format"))
137                                    )
138                            );
139                            return;
140                        }
141                        PlotArea area = plot.getArea();
142                        this.schematicHandler.paste(
143                                taskSchematic,
144                                plot,
145                                0,
146                                area.getMinBuildHeight(),
147                                0,
148                                false,
149                                player,
150                                new RunnableVal<>() {
151                                    @Override
152                                    public void run(Boolean value) {
153                                        plot.removeRunning();
154                                        if (value) {
155                                            player.sendMessage(TranslatableCaption.of("schematics.schematic_paste_success"));
156                                        } else {
157                                            player.sendMessage(TranslatableCaption.of("schematics.schematic_paste_failed"));
158                                        }
159                                    }
160                                }
161                        );
162                    });
163                    return true;
164                }
165                plot.removeRunning();
166                player.sendMessage(
167                        TranslatableCaption.of("commandconfig.command_syntax"),
168                        TagResolver.resolver("value", Tag.inserting(Component.text("/plot load <index>")))
169                );
170                return false;
171            }
172
173            // list schematics
174
175            List<String> schematics = metaDataAccess.get().orElse(null);
176            if (schematics == null) {
177                plot.addRunning();
178                TaskManager.runTaskAsync(() -> {
179                    List<String> schematics1 = this.schematicHandler.getSaves(player.getUUID());
180                    plot.removeRunning();
181                    if ((schematics1 == null) || schematics1.isEmpty()) {
182                        player.sendMessage(TranslatableCaption.of("web.load_failed"));
183                        return;
184                    }
185                    metaDataAccess.set(schematics1);
186                    displaySaves(player);
187                });
188            } else {
189                displaySaves(player);
190            }
191        }
192        return true;
193    }
194
195    public void displaySaves(PlotPlayer<?> player) {
196        try (final MetaDataAccess<List<String>> metaDataAccess =
197                     player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_SCHEMATICS)) {
198            List<String> schematics = metaDataAccess.get().orElse(Collections.emptyList());
199            for (int i = 0; i < Math.min(schematics.size(), 32); i++) {
200                try {
201                    String schematic = schematics.get(i).split("\\.")[0];
202                    String[] split = schematic.split("_");
203                    if (split.length < 5) {
204                        continue;
205                    }
206                    String time = TimeUtil.secToTime((System.currentTimeMillis() / 1000) - Long.parseLong(split[0]));
207                    String world = split[1];
208                    PlotId id = PlotId.fromString(split[2] + ';' + split[3]);
209                    String size = split[4];
210                    String color = "<dark_aqua>";
211                    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
212                            + "<dark_gray> | </dark_gray>" + color + size + 'x' + size));
213                } catch (Exception e) {
214                    e.printStackTrace();
215                }
216            }
217            player.sendMessage(
218                    TranslatableCaption.of("web.load_list"),
219                    TagResolver.resolver("command", Tag.inserting(Component.text("/plot load #")))
220            );
221        }
222    }
223
224}