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.setup;
020
021import com.plotsquared.core.PlotSquared;
022import com.plotsquared.core.configuration.caption.Caption;
023import com.plotsquared.core.configuration.caption.TranslatableCaption;
024import com.plotsquared.core.events.TeleportCause;
025import com.plotsquared.core.generator.GeneratorWrapper;
026import com.plotsquared.core.player.MetaDataAccess;
027import com.plotsquared.core.player.PlayerMetaDataKeys;
028import com.plotsquared.core.player.PlotPlayer;
029import com.plotsquared.core.plot.PlotArea;
030import com.plotsquared.core.plot.PlotAreaTerrainType;
031import com.plotsquared.core.plot.PlotAreaType;
032import com.plotsquared.core.plot.PlotId;
033import com.plotsquared.core.util.SetupUtils;
034import com.plotsquared.core.util.StringMan;
035import net.kyori.adventure.text.minimessage.Template;
036import org.checkerframework.checker.nullness.qual.NonNull;
037import org.checkerframework.checker.nullness.qual.Nullable;
038
039import java.util.Arrays;
040import java.util.Collection;
041import java.util.Collections;
042import java.util.Optional;
043import java.util.stream.Collectors;
044
045public enum CommonSetupSteps implements SetupStep {
046    CHOOSE_GENERATOR(TranslatableCaption.of("setup.setup_init")) {
047        @Override
048        public SetupStep handleInput(PlotPlayer<?> plotPlayer, PlotAreaBuilder builder, String arg) {
049            if (!SetupUtils.generators.containsKey(arg)) {
050                plotPlayer.sendMessage(TranslatableCaption.of("setup.setup_world_generator_error"));
051                return this; // invalid input -> same setup step
052            }
053            builder.generatorName(arg);
054            return CommonSetupSteps.CHOOSE_PLOT_AREA_TYPE; // proceed with next step
055        }
056
057
058        @Override
059        public Collection<String> getSuggestions() {
060            return Collections.unmodifiableSet(SetupUtils.generators.keySet());
061        }
062
063        @Nullable
064        @Override
065        public String getDefaultValue() {
066            return PlotSquared.platform().pluginName();
067        }
068    },
069    CHOOSE_PLOT_AREA_TYPE(PlotAreaType.class, TranslatableCaption.of("setup.setup_world_type")) {
070        @Override
071        public SetupStep handleInput(PlotPlayer<?> plotPlayer, PlotAreaBuilder builder, String arg) {
072            Optional<PlotAreaType> plotAreaType = PlotAreaType.fromString(arg);
073            if (!plotAreaType.isPresent()) {
074                plotPlayer.sendMessage(TranslatableCaption.of("setup.setup_world_type_error"));
075                return this;
076            }
077            builder.plotAreaType(plotAreaType.get());
078            GeneratorWrapper<?> gen = SetupUtils.generators.get(builder.generatorName());
079            if (builder.plotAreaType() == PlotAreaType.NORMAL) {
080                if (builder.settingsNodesWrapper() == null) {
081                    builder.plotManager(builder.generatorName());
082                    builder.settingsNodesWrapper(CommonSetupSteps.wrap(builder.plotManager()));
083                    SetupUtils.generators.get(builder.plotManager()).getPlotGenerator()
084                            .processAreaSetup(builder);
085                }
086                return builder.settingsNodesWrapper().getFirstStep();
087            } else {
088                if (gen.isFull()) {
089                    builder.plotManager(builder.generatorName());
090                    builder.generatorName(null);
091                    builder.settingsNodesWrapper(CommonSetupSteps.wrap(builder.plotManager()));
092                    SetupUtils.generators.get(builder.plotManager()).getPlotGenerator()
093                            .processAreaSetup(builder);
094                } else {
095                    builder.plotManager(PlotSquared.platform().pluginName());
096                    plotPlayer.sendMessage(TranslatableCaption.of("setup.setup_world_generator_error"));
097                    builder.settingsNodesWrapper(CommonSetupSteps.wrap(builder.plotManager()));
098                    // TODO why is processSetup not called here?
099                }
100                if (builder.plotAreaType() == PlotAreaType.PARTIAL) {
101                    return CHOOSE_AREA_ID;
102                } else {
103                    return CHOOSE_TERRAIN_TYPE;
104                }
105            }
106        }
107
108        @Nullable
109        @Override
110        public String getDefaultValue() {
111            return PlotAreaType.NORMAL.toString();
112        }
113    },
114    CHOOSE_AREA_ID(TranslatableCaption.of("setup.setup_area_name")) {
115        @Override
116        public SetupStep handleInput(PlotPlayer<?> plotPlayer, PlotAreaBuilder builder, String argument) {
117            if (!StringMan.isAlphanumericUnd(argument)) {
118                plotPlayer.sendMessage(TranslatableCaption.of("setup.setup_area_non_alphanumerical"));
119                return this;
120            }
121            for (PlotArea area : PlotSquared.get().getPlotAreaManager().getAllPlotAreas()) {
122                if (area.getId() != null && area.getId().equalsIgnoreCase(argument)) {
123                    plotPlayer.sendMessage(TranslatableCaption.of("setup.setup_area_invalid_id"));
124                    return this;
125                }
126            }
127            builder.areaName(argument);
128            return CHOOSE_MINIMUM_PLOT_ID;
129        }
130
131        @Nullable
132        @Override
133        public String getDefaultValue() {
134            return null;
135        }
136    },
137    CHOOSE_MINIMUM_PLOT_ID(TranslatableCaption.of("setup.setup_area_min_plot_id")) {
138        @Override
139        public SetupStep handleInput(PlotPlayer<?> plotPlayer, PlotAreaBuilder builder, String argument) {
140            try {
141                builder.minimumId(PlotId.fromString(argument));
142            } catch (IllegalArgumentException ignored) {
143                plotPlayer.sendMessage(TranslatableCaption.of("setup.setup_area_min_plot_id_error"));
144                return this;
145            } catch (IllegalStateException ignored) {
146                plotPlayer.sendMessage(TranslatableCaption.of("setup.setup_area_plot_id_greater_than_minimum"));
147                return this;
148            }
149            return CHOOSE_MAXIMUM_PLOT_ID;
150        }
151
152        @Override
153        public String getDefaultValue() {
154            return "0;0";
155        }
156    },
157    CHOOSE_MAXIMUM_PLOT_ID(TranslatableCaption.of("setup.setup_area_max_plot_id")) {
158        @Override
159        public SetupStep handleInput(PlotPlayer<?> plotPlayer, PlotAreaBuilder builder, String argument) {
160            try {
161                builder.maximumId(PlotId.fromString(argument));
162            } catch (IllegalArgumentException ignored) {
163                plotPlayer.sendMessage(TranslatableCaption.of("setup.setup_area_max_plot_id_error"));
164                return this;
165            } catch (IllegalStateException ignored) {
166                plotPlayer.sendMessage(TranslatableCaption.of("setup.setup_area_plot_id_greater_than_minimum"));
167                return this;
168            }
169            return CHOOSE_TERRAIN_TYPE;
170        }
171
172        @Override
173        public String getDefaultValue() {
174            return "0;0";
175        }
176    },
177    CHOOSE_TERRAIN_TYPE(PlotAreaTerrainType.class, TranslatableCaption.of("setup.setup_partial_area")) {
178        @Override
179        public SetupStep handleInput(PlotPlayer<?> plotPlayer, PlotAreaBuilder builder, String argument) {
180            Optional<PlotAreaTerrainType> optTerrain;
181            if (!(optTerrain = PlotAreaTerrainType.fromString(argument))
182                    .isPresent()) {
183                plotPlayer.sendMessage(TranslatableCaption.of("setup.setup_partial_area_error"));
184                return this;
185            }
186            builder.terrainType(optTerrain.get());
187            if (builder.settingsNodesWrapper() == null) {
188                builder.settingsNodesWrapper(CommonSetupSteps.wrap(builder.plotManager()));
189            }
190            SettingsNodesWrapper wrapper = builder.settingsNodesWrapper();
191            return wrapper.getFirstStep();
192        }
193
194        @Nullable
195        @Override
196        public String getDefaultValue() {
197            return PlotAreaTerrainType.NONE.toString();
198        }
199    },
200    CHOOSE_WORLD_NAME(TranslatableCaption.of("setup.setup_world_name")) {
201        @Override
202        public SetupStep handleInput(PlotPlayer<?> plotPlayer, PlotAreaBuilder builder, String argument) {
203            if (!isValidWorldName(argument)) {
204                plotPlayer.sendMessage(TranslatableCaption.of("setup.setup_world_name_format"));
205                return this;
206            }
207            if (PlotSquared.platform().worldUtil().isWorld(argument)) {
208                if (PlotSquared.get().getPlotAreaManager().hasPlotArea(argument)) {
209                    plotPlayer.sendMessage(TranslatableCaption.of("setup.setup_world_taken"), Template.of("value", argument));
210                    return this;
211                }
212                plotPlayer.sendMessage(TranslatableCaption.of("setup.setup_world_apply_plotsquared"));
213            }
214            builder.worldName(argument);
215            try (final MetaDataAccess<SetupProcess> setupAccess = plotPlayer.accessTemporaryMetaData(
216                    PlayerMetaDataKeys.TEMPORARY_SETUP)) {
217                setupAccess.remove();
218            }
219            String world;
220            if (builder.setupManager() == null) {
221                world = PlotSquared.platform().injector().getInstance(SetupUtils.class).setupWorld(builder);
222            } else {
223                world = builder.setupManager().setupWorld(builder);
224            }
225            try {
226                plotPlayer.teleport(PlotSquared.platform().worldUtil().getSpawn(world), TeleportCause.COMMAND_SETUP);
227            } catch (Exception e) {
228                plotPlayer.sendMessage(TranslatableCaption.of("errors.error_console"));
229                e.printStackTrace();
230            }
231            plotPlayer.sendMessage(TranslatableCaption.of("setup.setup_finished"));
232            return null;
233        }
234
235        @Nullable
236        @Override
237        public String getDefaultValue() {
238            return null;
239        }
240    };
241
242    @NonNull
243    private final Collection<String> suggestions;
244    private final Caption description;
245
246    /**
247     * @param suggestions the input suggestions for this step
248     * @param description the caption describing this step
249     */
250    CommonSetupSteps(@NonNull Collection<String> suggestions, @NonNull Caption description) {
251        this.suggestions = suggestions;
252        this.description = description;
253    }
254
255    CommonSetupSteps(@NonNull Caption description) {
256        this.description = description;
257        this.suggestions = Collections.emptyList();
258    }
259
260    <E extends Enum<E>> CommonSetupSteps(@NonNull Class<E> argumentType, Caption description) {
261        this(enumToStrings(argumentType), description);
262    }
263
264    private static <E extends Enum<E>> Collection<String> enumToStrings(Class<E> type) {
265        return Arrays.stream(type.getEnumConstants()).map(e -> e.toString().toLowerCase()).collect(Collectors.toList());
266    }
267
268    private static SettingsNodesWrapper wrap(String plotManager) {
269        return new SettingsNodesWrapper(SetupUtils.generators.get(plotManager).getPlotGenerator()
270                .getNewPlotArea("CheckingPlotSquaredGenerator", null, null, null)
271                .getSettingNodes(), CHOOSE_WORLD_NAME);
272    }
273
274    private static boolean isValidWorldName(String s) {
275        return s
276                .chars()
277                .allMatch((i) -> i == 95 || i == 45 || i >= 97 && i <= 122 || i >= 65 && i <= 90 || i >= 48 && i <= 57 || i == 46);
278    }
279
280    @Override
281    public void announce(PlotPlayer<?> plotPlayer) {
282        plotPlayer.sendMessage(this.description);
283    }
284
285    public @NonNull Collection<String> getSuggestions() {
286        return this.suggestions;
287    }
288}