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