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.plot.world;
020
021import com.plotsquared.core.PlotSquared;
022import com.plotsquared.core.configuration.ConfigurationNode;
023import com.plotsquared.core.configuration.ConfigurationSection;
024import com.plotsquared.core.configuration.ConfigurationUtil;
025import com.plotsquared.core.configuration.caption.TranslatableCaption;
026import com.plotsquared.core.configuration.file.YamlConfiguration;
027import com.plotsquared.core.generator.GridPlotWorld;
028import com.plotsquared.core.generator.SingleWorldGenerator;
029import com.plotsquared.core.inject.annotations.WorldConfig;
030import com.plotsquared.core.listener.PlotListener;
031import com.plotsquared.core.location.BlockLoc;
032import com.plotsquared.core.location.Location;
033import com.plotsquared.core.plot.Plot;
034import com.plotsquared.core.plot.PlotAreaType;
035import com.plotsquared.core.plot.PlotId;
036import com.plotsquared.core.plot.PlotManager;
037import com.plotsquared.core.plot.PlotSettings;
038import com.plotsquared.core.plot.flag.FlagContainer;
039import com.plotsquared.core.queue.GlobalBlockQueue;
040import com.plotsquared.core.setup.PlotAreaBuilder;
041import com.plotsquared.core.setup.SettingsNodesWrapper;
042import com.plotsquared.core.util.EventDispatcher;
043import com.plotsquared.core.util.task.TaskManager;
044import org.checkerframework.checker.nullness.qual.NonNull;
045import org.checkerframework.checker.nullness.qual.Nullable;
046
047import java.io.File;
048import java.io.IOException;
049import java.nio.file.Files;
050
051public class SinglePlotArea extends GridPlotWorld {
052
053    @SuppressWarnings({"unused", "FieldCanBeLocal"})
054    private final EventDispatcher eventDispatcher;
055    @SuppressWarnings({"unused", "FieldCanBeLocal"})
056    private final PlotListener plotListener;
057    public boolean VOID = false;
058
059    public SinglePlotArea(
060            final @NonNull PlotAreaManager plotAreaManager,
061            final @NonNull EventDispatcher eventDispatcher,
062            final @NonNull PlotListener plotListener,
063            @WorldConfig final @NonNull YamlConfiguration worldConfiguration,
064            final @NonNull GlobalBlockQueue globalBlockQueue
065    ) {
066        super("*", null, new SingleWorldGenerator(plotAreaManager), null, null,
067                worldConfiguration, globalBlockQueue
068        );
069        this.eventDispatcher = eventDispatcher;
070        this.plotListener = plotListener;
071        this.setAllowSigns(false);
072        this.setDefaultHome(new BlockLoc(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE));
073    }
074
075    /**
076     * Returns true if the given string matches the naming system used to identify single plot worlds
077     * e.g. -1_5 represents plot id *;-1;5. "*" being the plot area name given to single plot world
078     * {@link com.plotsquared.core.plot.PlotArea}.
079     * @since 6.1.4
080     */
081    public static boolean isSinglePlotWorld(String worldName) {
082        int len = worldName.length();
083        int separator = 0;
084        for (int i = 0; i < len; i++) {
085            switch (worldName.charAt(i)) {
086                case '_':
087                    separator++;
088                    break;
089                case '-':
090                case '0':
091                case '1':
092                case '2':
093                case '3':
094                case '4':
095                case '5':
096                case '6':
097                case '7':
098                case '8':
099                case '9':
100                    break;
101                default:
102                    return false;
103            }
104        }
105        return separator == 1;
106    }
107
108    @NonNull
109    @Override
110    protected PlotManager createManager() {
111        return new SinglePlotManager(this);
112    }
113
114    @Override
115    public void loadConfiguration(ConfigurationSection config) {
116        VOID = config.getBoolean("void", false);
117    }
118
119    @Override
120    public void saveConfiguration(ConfigurationSection config) {
121        super.saveConfiguration(config);
122    }
123
124    public void loadWorld(final PlotId id) {
125        String worldName = id.toUnderscoreSeparatedString();
126        if (PlotSquared.platform().worldUtil().isWorld(worldName)) {
127            return;
128        }
129        PlotAreaBuilder builder = PlotAreaBuilder.newBuilder()
130                .plotManager("PlotSquared:single")
131                .generatorName("PlotSquared:single")
132                .plotAreaType(getType())
133                .terrainType(getTerrain())
134                .settingsNodesWrapper(new SettingsNodesWrapper(new ConfigurationNode[0], null))
135                .worldName(worldName);
136
137        File container = PlotSquared.platform().worldContainer();
138        File destination = new File(container, worldName);
139
140        {// convert old
141            File oldFile = new File(container, id.toCommaSeparatedString());
142            if (oldFile.exists()) {
143                oldFile.renameTo(destination);
144            } else {
145                oldFile = new File(container, id.toSeparatedString("."));
146                if (oldFile.exists()) {
147                    oldFile.renameTo(destination);
148                }
149            }
150        }
151        // Duplicate 0;0
152        if (builder.plotAreaType() != PlotAreaType.NORMAL) {
153            if (!destination.exists()) {
154                File src = new File(container, "0_0");
155                if (src.exists()) {
156                    if (!destination.exists()) {
157                        destination.mkdirs();
158                    }
159                    File levelDat = new File(src, "level.dat");
160                    if (levelDat.exists()) {
161                        try {
162                            Files.copy(
163                                    levelDat.toPath(),
164                                    new File(destination, levelDat.getName()).toPath()
165                            );
166                            File data = new File(src, "data");
167                            if (data.exists()) {
168                                File dataDest = new File(destination, "data");
169                                dataDest.mkdirs();
170                                for (File file : data.listFiles()) {
171                                    Files.copy(
172                                            file.toPath(),
173                                            new File(dataDest, file.getName()).toPath()
174                                    );
175                                }
176                            }
177                        } catch (IOException exception) {
178                            exception.printStackTrace();
179                        }
180                    }
181                }
182            }
183        }
184
185        try {
186            TaskManager.getPlatformImplementation().sync(() -> {
187                final String name = id.toUnderscoreSeparatedString();
188                if (!PlotSquared.platform().worldUtil().isWorld(name)) {
189                    PlotSquared.platform().setupUtils().setupWorld(builder);
190                }
191                return null;
192            });
193        } catch (final Exception e) {
194            e.printStackTrace();
195        }
196
197        //        String worldName = plot.getWorldName();
198        //        World world = Bukkit.getWorld(worldName);
199        //        if (world != null) {
200        //            return world;
201        //        }
202        //        WorldCreator wc = new WorldCreator(worldName);
203        //        wc.generator("PlotSquared:single");
204        //        wc.environment(World.Environment.NORMAL);
205        //        wc.type(WorldType.FLAT);
206        //        return AsyncWorld.create(wc);
207    }
208
209
210    @Override
211    public ConfigurationNode[] getSettingNodes() {
212        return new ConfigurationNode[]{
213                new ConfigurationNode(
214                        "void",
215                        this.VOID,
216                        TranslatableCaption.of("setup.singleplotarea_void_world"),
217                        ConfigurationUtil.BOOLEAN
218                )};
219    }
220
221    @Nullable
222    @Override
223    public Plot getOwnedPlot(final @NonNull Location location) {
224        PlotId pid = PlotId.fromStringOrNull(location.getWorldName());
225        Plot plot = pid == null ? null : this.plots.get(pid);
226        return plot == null ? null : plot.getBasePlot(false);
227    }
228
229    @Nullable
230    @Override
231    public Plot getOwnedPlotAbs(@NonNull Location location) {
232        PlotId pid = PlotId.fromStringOrNull(location.getWorldName());
233        return pid == null ? null : plots.get(pid);
234    }
235
236    @Nullable
237    @Override
238    public Plot getPlot(final @NonNull Location location) {
239        PlotId pid = PlotId.fromStringOrNull(location.getWorldName());
240        return pid == null ? null : getPlot(pid);
241    }
242
243    @Nullable
244    @Override
245    public Plot getPlotAbs(final @NonNull Location location) {
246        final PlotId pid = PlotId.fromStringOrNull(location.getWorldName());
247        return pid == null ? null : getPlotAbs(pid);
248    }
249
250    public boolean addPlot(@NonNull Plot plot) {
251        plot = adapt(plot);
252        return super.addPlot(plot);
253    }
254
255    @Override
256    public boolean addPlotAbs(@NonNull Plot plot) {
257        plot = adapt(plot);
258        return super.addPlotAbs(plot);
259    }
260
261    @Override
262    public boolean addPlotIfAbsent(@NonNull Plot plot) {
263        plot = adapt(plot);
264        return super.addPlotIfAbsent(plot);
265    }
266
267    @Override
268    public boolean allowSigns() {
269        return false; // do not create signs for single plots
270    }
271
272    @SuppressWarnings("deprecation")
273    protected Plot adapt(Plot p) {
274        if (p instanceof SinglePlot) {
275            return p;
276        }
277        PlotSettings s = p.getSettings();
278
279        final FlagContainer oldContainer = p.getFlagContainer();
280        p = new SinglePlot(p.getId(), p.getOwnerAbs(), p.getTrusted(), p.getMembers(),
281                p.getDenied(), s.getAlias(), s.getPosition(), null, this, s.getMerged(),
282                p.getTimestamp(), p.temp
283        );
284        p.getFlagContainer().addAll(oldContainer);
285
286        return p;
287    }
288
289    public @Nullable Plot getPlotAbs(final @NonNull PlotId id) {
290        Plot plot = getOwnedPlotAbs(id);
291        if (plot == null) {
292            return new SinglePlot(this, id);
293        }
294        return plot;
295    }
296
297    public @Nullable Plot getPlot(@NonNull PlotId id) {
298        // TODO
299        Plot plot = getOwnedPlotAbs(id);
300        if (plot == null) {
301            return new SinglePlot(this, id);
302        }
303        return plot.getBasePlot(false);
304    }
305
306}