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     *
080     * @since 6.1.4
081     */
082    public static boolean isSinglePlotWorld(String worldName) {
083        int len = worldName.length();
084        int separator = 0;
085        for (int i = 0; i < len; i++) {
086            switch (worldName.charAt(i)) {
087                case '_':
088                    separator++;
089                    break;
090                case '-':
091                case '0':
092                case '1':
093                case '2':
094                case '3':
095                case '4':
096                case '5':
097                case '6':
098                case '7':
099                case '8':
100                case '9':
101                    break;
102                default:
103                    return false;
104            }
105        }
106        return separator == 1;
107    }
108
109    @NonNull
110    @Override
111    protected PlotManager createManager() {
112        return new SinglePlotManager(this);
113    }
114
115    @Override
116    public void loadConfiguration(ConfigurationSection config) {
117        VOID = config.getBoolean("void", false);
118    }
119
120    @Override
121    public void saveConfiguration(ConfigurationSection config) {
122        super.saveConfiguration(config);
123    }
124
125    public void loadWorld(final PlotId id) {
126        String worldName = id.toUnderscoreSeparatedString();
127        if (PlotSquared.platform().worldUtil().isWorld(worldName)) {
128            return;
129        }
130        PlotAreaBuilder builder = PlotAreaBuilder.newBuilder()
131                .plotManager("PlotSquared:single")
132                .generatorName("PlotSquared:single")
133                .plotAreaType(getType())
134                .terrainType(getTerrain())
135                .settingsNodesWrapper(new SettingsNodesWrapper(new ConfigurationNode[0], null))
136                .worldName(worldName);
137
138        File container = PlotSquared.platform().worldContainer();
139        File destination = new File(container, worldName);
140
141        {// convert old
142            File oldFile = new File(container, id.toCommaSeparatedString());
143            if (oldFile.exists()) {
144                oldFile.renameTo(destination);
145            } else {
146                oldFile = new File(container, id.toSeparatedString("."));
147                if (oldFile.exists()) {
148                    oldFile.renameTo(destination);
149                }
150            }
151        }
152        // Duplicate 0;0
153        if (builder.plotAreaType() != PlotAreaType.NORMAL) {
154            if (!destination.exists()) {
155                File src = new File(container, "0_0");
156                if (src.exists()) {
157                    if (!destination.exists()) {
158                        destination.mkdirs();
159                    }
160                    File levelDat = new File(src, "level.dat");
161                    if (levelDat.exists()) {
162                        try {
163                            Files.copy(
164                                    levelDat.toPath(),
165                                    new File(destination, levelDat.getName()).toPath()
166                            );
167                            File data = new File(src, "data");
168                            if (data.exists()) {
169                                File dataDest = new File(destination, "data");
170                                dataDest.mkdirs();
171                                for (File file : data.listFiles()) {
172                                    Files.copy(
173                                            file.toPath(),
174                                            new File(dataDest, file.getName()).toPath()
175                                    );
176                                }
177                            }
178                        } catch (IOException exception) {
179                            exception.printStackTrace();
180                        }
181                    }
182                }
183            }
184        }
185
186        try {
187            TaskManager.getPlatformImplementation().sync(() -> {
188                final String name = id.toUnderscoreSeparatedString();
189                if (!PlotSquared.platform().worldUtil().isWorld(name)) {
190                    PlotSquared.platform().setupUtils().setupWorld(builder);
191                }
192                return null;
193            });
194        } catch (final Exception e) {
195            e.printStackTrace();
196        }
197
198        //        String worldName = plot.getWorldName();
199        //        World world = Bukkit.getWorld(worldName);
200        //        if (world != null) {
201        //            return world;
202        //        }
203        //        WorldCreator wc = new WorldCreator(worldName);
204        //        wc.generator("PlotSquared:single");
205        //        wc.environment(World.Environment.NORMAL);
206        //        wc.type(WorldType.FLAT);
207        //        return AsyncWorld.create(wc);
208    }
209
210
211    @Override
212    public ConfigurationNode[] getSettingNodes() {
213        return new ConfigurationNode[]{
214                new ConfigurationNode(
215                        "void",
216                        this.VOID,
217                        TranslatableCaption.of("setup.singleplotarea_void_world"),
218                        ConfigurationUtil.BOOLEAN
219                )};
220    }
221
222    @Nullable
223    @Override
224    public Plot getOwnedPlot(final @NonNull Location location) {
225        PlotId pid = PlotId.fromStringOrNull(location.getWorldName());
226        Plot plot = pid == null ? null : this.plots.get(pid);
227        return plot == null ? null : plot.getBasePlot(false);
228    }
229
230    @Nullable
231    @Override
232    public Plot getOwnedPlotAbs(@NonNull Location location) {
233        PlotId pid = PlotId.fromStringOrNull(location.getWorldName());
234        return pid == null ? null : plots.get(pid);
235    }
236
237    @Nullable
238    @Override
239    public Plot getPlot(final @NonNull Location location) {
240        PlotId pid = PlotId.fromStringOrNull(location.getWorldName());
241        return pid == null ? null : getPlot(pid);
242    }
243
244    @Nullable
245    @Override
246    public Plot getPlotAbs(final @NonNull Location location) {
247        final PlotId pid = PlotId.fromStringOrNull(location.getWorldName());
248        return pid == null ? null : getPlotAbs(pid);
249    }
250
251    public boolean addPlot(@NonNull Plot plot) {
252        plot = adapt(plot);
253        return super.addPlot(plot);
254    }
255
256    @Override
257    public boolean addPlotAbs(@NonNull Plot plot) {
258        plot = adapt(plot);
259        return super.addPlotAbs(plot);
260    }
261
262    @Override
263    public boolean addPlotIfAbsent(@NonNull Plot plot) {
264        plot = adapt(plot);
265        return super.addPlotIfAbsent(plot);
266    }
267
268    @Override
269    public boolean allowSigns() {
270        return false; // do not create signs for single plots
271    }
272
273    @SuppressWarnings("deprecation")
274    protected Plot adapt(Plot p) {
275        if (p instanceof SinglePlot) {
276            return p;
277        }
278        PlotSettings s = p.getSettings();
279
280        final FlagContainer oldContainer = p.getFlagContainer();
281        p = new SinglePlot(p.getId(), p.getOwnerAbs(), p.getTrusted(), p.getMembers(),
282                p.getDenied(), s.getAlias(), s.getPosition(), null, this, s.getMerged(),
283                p.getTimestamp(), p.temp
284        );
285        p.getFlagContainer().addAll(oldContainer);
286
287        return p;
288    }
289
290    public @Nullable Plot getPlotAbs(final @NonNull PlotId id) {
291        Plot plot = getOwnedPlotAbs(id);
292        if (plot == null) {
293            return new SinglePlot(this, id);
294        }
295        return plot;
296    }
297
298    public @Nullable Plot getPlot(@NonNull PlotId id) {
299        // TODO
300        Plot plot = getOwnedPlotAbs(id);
301        if (plot == null) {
302            return new SinglePlot(this, id);
303        }
304        return plot.getBasePlot(false);
305    }
306
307}