diff --git a/src/main/java/carpet/CarpetExtension.java b/src/main/java/carpet/CarpetExtension.java new file mode 100644 index 00000000..62bb6fe1 --- /dev/null +++ b/src/main/java/carpet/CarpetExtension.java @@ -0,0 +1,49 @@ +package carpet; + +import carpet.settings.SettingsManager; +import com.mojang.brigadier.CommandDispatcher; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.command.ServerCommandSource; + +public abstract class CarpetExtension +{ + /** + * When game started before world is loaded + */ + public void onGameStarted() {} + + /** + * Runs once per loaded world once the World files / gamerules etc are fully loaded + * Can be loaded multiple times in SinglePlayer + */ + public void onServerLoaded(MinecraftServer server) {} + + /** + * Runs once per game tick, as a first thing in the tick + */ + public void onTick(MinecraftServer server) {} + + /** + * Register your own commands right after vanilla commands are added + * If that matters for you + */ + public void registerCommands(CommandDispatcher dispatcher) {} + + /** + * Provide your own custom settings manager managed in the same way as base /carpet + * command, but separated to its own command as defined in SettingsManager. + */ + public SettingsManager customSettingsManager() {return null;} + + /** + * todiddalidoo + */ + public void onPlayerLoggedIn(PlayerEntity player) {} + + /** + * todiddalidoo + */ + public void onPlayerLoggedOut(PlayerEntity player) {} + +} diff --git a/src/main/java/carpet/CarpetServer.java b/src/main/java/carpet/CarpetServer.java index 6a378d10..4ffb9fc2 100644 --- a/src/main/java/carpet/CarpetServer.java +++ b/src/main/java/carpet/CarpetServer.java @@ -1,10 +1,11 @@ package carpet; +import java.util.ArrayList; +import java.util.List; import java.util.Random; import carpet.commands.CameraModeCommand; -import carpet.commands.CarpetCommand; import carpet.commands.CounterCommand; import carpet.commands.DistanceCommand; import carpet.commands.DrawCommand; @@ -14,7 +15,6 @@ import carpet.commands.PerimeterInfoCommand; import carpet.commands.PlayerCommand; import carpet.commands.ScriptCommand; import carpet.commands.SpawnCommand; -import carpet.commands.TestCommand; import carpet.commands.TickCommand; import carpet.helpers.TickSpeed; import carpet.logging.LoggerRegistry; @@ -32,25 +32,37 @@ public class CarpetServer // static for now - easier to handle all around the co public static MinecraftServer minecraft_server; public static CarpetScriptServer scriptServer; public static SettingsManager settingsManager; - static + public static List extensions = new ArrayList<>(); + + // Separate from onServerLoaded, because a server can be loaded multiple times in singleplayer + public static void manageExtension(CarpetExtension extension) { - SettingsManager.parseSettingsClass(CarpetSettings.class); - //... + extensions.add(extension); } + + public static void onGameStarted() + { + LoggerRegistry.initLoggers(); + settingsManager = new SettingsManager(CarpetSettings.carpetVersion, "carpet", "Carpet Mod"); + settingsManager.parseSettingsClass(CarpetSettings.class); + extensions.forEach(CarpetExtension::onGameStarted); + } + public static void init(MinecraftServer server) //aka constructor of this static singleton class { + // no sure we really need this here, needs testing and moving to onServerLoaded CarpetServer.minecraft_server = server; } public static void onServerLoaded(MinecraftServer server) { - settingsManager = new SettingsManager(server); + settingsManager.attachServer(server); + extensions.forEach(e -> { + if (e.customSettingsManager() != null) + e.customSettingsManager().attachServer(server); + e.onServerLoaded(server); + }); scriptServer = new CarpetScriptServer(); } - // Separate from onServerLoaded, because a server can be loaded multiple times in singleplayer - public static void onGameStarted() - { - LoggerRegistry.initLoggers(); - } public static void tick(MinecraftServer server) { @@ -59,6 +71,7 @@ public class CarpetServer // static for now - easier to handle all around the co scriptServer.events.tick(); //in case something happens CarpetSettings.impendingFillSkipUpdates = false; + extensions.forEach(e -> e.onTick(server)); } public static void registerCarpetCommands(CommandDispatcher dispatcher) @@ -74,7 +87,7 @@ public class CarpetServer // static for now - easier to handle all around the co PerimeterInfoCommand.register(dispatcher); DrawCommand.register(dispatcher); ScriptCommand.register(dispatcher); - CarpetCommand.register(dispatcher); + extensions.forEach(e -> e.registerCommands(dispatcher)); //TestCommand.register(dispatcher); } } diff --git a/src/main/java/carpet/commands/CarpetCommand.java b/src/main/java/carpet/commands/CarpetCommand.java deleted file mode 100644 index cbea2e8f..00000000 --- a/src/main/java/carpet/commands/CarpetCommand.java +++ /dev/null @@ -1,213 +0,0 @@ -package carpet.commands; - -import carpet.CarpetServer; -import carpet.settings.CarpetSettings; -import carpet.settings.ParsedRule; -import carpet.settings.SettingsManager; -import carpet.utils.Messenger; -import com.mojang.brigadier.CommandDispatcher; -import com.mojang.brigadier.arguments.StringArgumentType; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.text.BaseText; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import static net.minecraft.server.command.CommandManager.argument; -import static net.minecraft.server.command.CommandManager.literal; -import static net.minecraft.server.command.CommandSource.suggestMatching; - -public class CarpetCommand -{ - private static ParsedRule getRule(CommandContext ctx) throws CommandSyntaxException - { - String ruleName = StringArgumentType.getString(ctx, "rule"); - ParsedRule rule = SettingsManager.getRule(ruleName); - if (rule == null) - throw new SimpleCommandExceptionType(Messenger.c("rb Unknown rule: "+ruleName)).create(); - return rule; - } - public static void register(CommandDispatcher dispatcher) - { - LiteralArgumentBuilder literalargumentbuilder = literal("carpet").requires((player) -> - player.hasPermissionLevel(2) && !CarpetServer.settingsManager.locked); - - literalargumentbuilder.executes((context)->listAllSettings(context.getSource())). - then(literal("list"). - executes( (c) -> listSettings(c.getSource(), - "All CarpetMod Settings", - SettingsManager.getRules())). - then(literal("defaults"). - executes( (c)-> listSettings(c.getSource(), - "Current CarpetMod Startup Settings from carpet.conf", - CarpetServer.settingsManager.findStartupOverrides()))). - then(argument("tag",StringArgumentType.word()). - suggests( (c, b)->suggestMatching(SettingsManager.getCategories(), b)). - executes( (c) -> listSettings(c.getSource(), - String.format("CarpetMod Settings matching \"%s\"", StringArgumentType.getString(c, "tag")), - CarpetServer.settingsManager.getRulesMatching(StringArgumentType.getString(c, "tag")))))). - then(literal("removeDefault"). - requires(s -> !CarpetServer.settingsManager.locked). - then(argument("rule", StringArgumentType.word()). - suggests( (c, b) -> suggestMatching(SettingsManager.getRules().stream().map(r -> r.name), b)). - executes((c) -> removeDefault(c.getSource(), getRule(c))))). - then(literal("setDefault"). - requires(s -> !CarpetServer.settingsManager.locked). - then(argument("rule", StringArgumentType.word()). - suggests( (c, b) -> suggestMatching(SettingsManager.getRules().stream().map(r -> r.name), b)). - then(argument("value", StringArgumentType.word()). - suggests((c, b)-> suggestMatching(getRule(c).options, b)). - executes((c) -> setDefault(c.getSource(), getRule(c), StringArgumentType.getString(c, "value")))))). - then(argument("rule", StringArgumentType.word()). - suggests( (c, b) -> suggestMatching(SettingsManager.getRules().stream().map(r -> r.name), b)). - requires(s -> !CarpetServer.settingsManager.locked ). - executes( (c) -> displayRuleMenu(c.getSource(),getRule(c))). - then(argument("value", StringArgumentType.word()). - suggests((c, b)-> suggestMatching(getRule(c).options,b)). - executes((c) -> setRule(c.getSource(), getRule(c), StringArgumentType.getString(c, "value"))))); - - dispatcher.register(literalargumentbuilder); - } - - private static int displayRuleMenu(ServerCommandSource source, ParsedRule rule) - { - PlayerEntity player; - try - { - player = source.getPlayer(); - } - catch (CommandSyntaxException e) - { - Messenger.m(source, "w "+rule.name +" is set to: ","wb "+rule.getAsString()); - return 1; - } - - Messenger.m(player, ""); - Messenger.m(player, "wb "+rule.name,"!/carpet "+rule.name,"^g refresh"); - Messenger.m(player, "w "+rule.description); - - rule.extraInfo.forEach(s -> Messenger.m(player, "g "+s)); - - List tags = new ArrayList<>(); - tags.add(Messenger.c("w Tags: ")); - for (String t: rule.categories) - { - tags.add(Messenger.c("c ["+t+"]", "^g list all "+t+" settings","!/carpet list "+t)); - tags.add(Messenger.c("w , ")); - } - tags.remove(tags.size()-1); - Messenger.m(player, tags.toArray(new Object[0])); - - Messenger.m(player, "w Current value: ",String.format("%s %s (%s value)",rule.getBoolValue()?"lb":"nb", rule.getAsString(),rule.isDefault()?"default":"modified")); - List options = new ArrayList<>(); - options.add(Messenger.c("w Options: ", "y [ ")); - for (String o: rule.options) - { - options.add(makeSetRuleButton(rule, o, false)); - options.add(Messenger.c("w ")); - } - options.remove(options.size()-1); - options.add(Messenger.c("y ]")); - Messenger.m(player, options.toArray(new Object[0])); - - return 1; - } - - private static int setRule(ServerCommandSource source, ParsedRule rule, String newValue) - { - if (rule.set(source, newValue) != null) - Messenger.m(source, "w "+rule.toString()+", ", "c [change permanently?]", - "^w Click to keep the settings in carpet.conf to save across restarts", - "?/carpet setDefault "+rule.name+" "+rule.getAsString()); - return 1; - } - private static int setDefault(ServerCommandSource source, ParsedRule rule, String defaultValue) - { - if (CarpetServer.settingsManager.setDefaultRule(source, rule.name, defaultValue)) - Messenger.m(source ,"gi rule "+ rule.name+" will now default to "+ defaultValue); - return 1; - } - private static int removeDefault(ServerCommandSource source, ParsedRule rule) - { - if (CarpetServer.settingsManager.removeDefaultRule(source, rule.name)) - Messenger.m(source ,"gi rule "+ rule.name+" defaults to Vanilla"); - return 1; - } - - - private static BaseText displayInteractiveSetting(ParsedRule rule) - { - List args = new ArrayList<>(); - args.add("w - "+rule.name+" "); - args.add("!/carpet "+rule.name); - args.add("^y "+rule.description); - for (String option: rule.options) - { - args.add(makeSetRuleButton(rule, option, true)); - args.add("w "); - } - args.remove(args.size()-1); - return Messenger.c(args.toArray(new Object[0])); - } - - private static BaseText makeSetRuleButton(ParsedRule rule, String option, boolean brackets) - { - String style = rule.isDefault()?"g":(option.equalsIgnoreCase(rule.defaultAsString)?"y":"e"); - if (option.equalsIgnoreCase(rule.defaultAsString)) - style = style+"b"; - else if (option.equalsIgnoreCase(rule.getAsString())) - style = style+"u"; - String baseText = style + (brackets ? " [" : " ") + option + (brackets ? "]" : ""); - if (CarpetServer.settingsManager.locked) - return Messenger.c(baseText, "^g Settings are locked"); - if (option.equalsIgnoreCase(rule.getAsString())) - return Messenger.c(baseText); - return Messenger.c(baseText, "^g Switch to " + option, "?/carpet " + rule.name + " " + option); - } - - private static int listSettings(ServerCommandSource source, String title, Collection> settings_list) - { - try - { - PlayerEntity player = source.getPlayer(); - Messenger.m(player,String.format("wb %s:",title)); - settings_list.forEach(e -> Messenger.m(player,displayInteractiveSetting(e))); - - } - catch (CommandSyntaxException e) - { - Messenger.m(source, "w s:"+title); - settings_list.forEach(r -> Messenger.m(source, "w - "+ r.toString())); - } - return 1; - } - private static int listAllSettings(ServerCommandSource source) - { - listSettings(source, "Current CarpetMod Settings", CarpetServer.settingsManager.getNonDefault()); - - Messenger.m(source, "Carpet Mod version: "+ CarpetSettings.carpetVersion); - try - { - PlayerEntity player = source.getPlayer(); - List tags = new ArrayList<>(); - tags.add("w Browse Categories:\n"); - for (String t : SettingsManager.getCategories()) - { - tags.add("c [" + t+"]"); - tags.add("^g list all " + t + " settings"); - tags.add("!/carpet list " + t); - tags.add("w "); - } - tags.remove(tags.size() - 1); - Messenger.m(player, tags.toArray(new Object[0])); - } - catch (CommandSyntaxException ignored) { } - return 1; - } -} diff --git a/src/main/java/carpet/settings/CarpetSettings.java b/src/main/java/carpet/settings/CarpetSettings.java index 42b8b2e6..0fc5db9b 100644 --- a/src/main/java/carpet/settings/CarpetSettings.java +++ b/src/main/java/carpet/settings/CarpetSettings.java @@ -25,7 +25,7 @@ import static carpet.settings.RuleCategory.SURVIVAL; public class CarpetSettings { - public static final String carpetVersion = "v190627"; + public static final String carpetVersion = "v190704"; public static final Logger LOG = LogManager.getLogger(); public static boolean skipGenerationChecks = false; public static boolean impendingFillSkipUpdates = false; diff --git a/src/main/java/carpet/settings/ParsedRule.java b/src/main/java/carpet/settings/ParsedRule.java index 13f02aa5..e840f6b3 100644 --- a/src/main/java/carpet/settings/ParsedRule.java +++ b/src/main/java/carpet/settings/ParsedRule.java @@ -117,7 +117,7 @@ public final class ParsedRule implements Comparable { if (!value.equals(get())) { this.field.set(null, value); - SettingsManager.notifyRuleChanged(source, this, stringValue); + CarpetServer.settingsManager.notifyRuleChanged(source, this, stringValue); } } catch (IllegalAccessException e) diff --git a/src/main/java/carpet/settings/SettingsManager.java b/src/main/java/carpet/settings/SettingsManager.java index 5d0cd0b2..02629951 100644 --- a/src/main/java/carpet/settings/SettingsManager.java +++ b/src/main/java/carpet/settings/SettingsManager.java @@ -1,12 +1,21 @@ package carpet.settings; +import carpet.CarpetServer; +import carpet.utils.Messenger; import com.google.common.collect.ImmutableList; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.mojang.brigadier.tree.CommandNode; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.BaseText; import org.apache.commons.lang3.tuple.Pair; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.util.TriConsumer; import java.io.BufferedReader; @@ -28,21 +37,44 @@ import java.util.Set; import java.util.TreeMap; import java.util.stream.Collectors; +import static net.minecraft.server.command.CommandManager.argument; +import static net.minecraft.server.command.CommandManager.literal; +import static net.minecraft.server.command.CommandSource.suggestMatching; + public class SettingsManager { - private static final Logger LOG = LogManager.getLogger(); - private static Map> rules = new HashMap<>(); + private Map> rules = new HashMap<>(); public boolean locked; + private final String version; + private final String identifier; + private final String fancyName; private MinecraftServer server; - private static List, String>> observers = new ArrayList<>(); + private List, String>> observers = new ArrayList<>(); - public SettingsManager(MinecraftServer server) + public SettingsManager(String version, String identifier) + { + this.version = version; + this.identifier = identifier; + this.fancyName = identifier; + } + + public SettingsManager(String version, String identifier, String fancyName) + { + this.version = version; + this.identifier = identifier; + this.fancyName = fancyName; + } + + + public void attachServer(MinecraftServer server) { this.server = server; loadConfigurationFromConf(); + registerCommand(server.getCommandManager().getDispatcher()); + notifyPlayersCommandsChanged(); } - public static void parseSettingsClass(Class settingsClass) + public SettingsManager parseSettingsClass(Class settingsClass) { for (Field f : settingsClass.getDeclaredFields()) { @@ -51,19 +83,20 @@ public class SettingsManager ParsedRule parsed = new ParsedRule(f, rule); rules.put(parsed.name, parsed); } + return this; } - public static void addRuleObserver(TriConsumer, String> observer) + public void addRuleObserver(TriConsumer, String> observer) { observers.add(observer); } - static void notifyRuleChanged(ServerCommandSource source, ParsedRule rule, String userTypedValue) + void notifyRuleChanged(ServerCommandSource source, ParsedRule rule, String userTypedValue) { observers.forEach(observer -> observer.accept(source, rule, userTypedValue)); } - public static Iterable getCategories() + public Iterable getCategories() { Set categories = new HashSet<>(); getRules().stream().map(r -> r.categories).forEach(categories::addAll); @@ -71,12 +104,12 @@ public class SettingsManager } - public static ParsedRule getRule(String name) + public ParsedRule getRule(String name) { return rules.get(name); } - public static Collection> getRules() + public Collection> getRules() { return rules.values().stream().sorted().collect(Collectors.toList()); } @@ -96,7 +129,7 @@ public class SettingsManager private File getFile() { - return server.getLevelStorage().resolveFile(server.getLevelName(), "carpet.conf"); + return server.getLevelStorage().resolveFile(server.getLevelName(), identifier+".conf"); } public void disableBooleanFromCategory(String category) @@ -126,7 +159,7 @@ public class SettingsManager catch (IOException e) { e.printStackTrace(); - LOG.error("[CM]: failed write the carpet.conf"); + CarpetSettings.LOG.error("[CM]: failed write "+identifier+".conf config file"); } ///todo is it really needed? resendCommandTree(); } @@ -150,13 +183,13 @@ public class SettingsManager locked = false; if (conf.getRight()) { - LOG.info("[CM]: Carpet Mod is locked by the administrator"); + CarpetSettings.LOG.info("[CM]: "+fancyName+" features are locked by the administrator"); disableBooleanFromCategory(RuleCategory.COMMAND); } for (String key: conf.getLeft().keySet()) { if (rules.get(key).set(server.getCommandSource(), conf.getLeft().get(key)) != null) - LOG.info("[CM]: loaded setting "+key+" as "+conf.getLeft().get(key)+" from carpet.conf"); + CarpetSettings.LOG.info("[CM]: loaded setting "+key+" as "+conf.getLeft().get(key)+" from "+identifier+".conf"); } locked = conf.getRight(); } @@ -182,14 +215,14 @@ public class SettingsManager { if (!rules.containsKey(fields[0])) { - LOG.error("[CM]: Setting " + fields[0] + " is not a valid - ignoring..."); + CarpetSettings.LOG.error("[CM]: "+fancyName+" Setting " + fields[0] + " is not a valid - ignoring..."); continue; } ParsedRule rule = rules.get(fields[0]); if (!(rule.options.contains(fields[1])) && rule.isStrict) { - LOG.error("[CM]: The value of " + fields[1] + " for " + fields[0] + " is not valid - ignoring..."); + CarpetSettings.LOG.error("[CM]: The value of " + fields[1] + " for " + fields[0] + "("+fancyName+") is not valid - ignoring..."); continue; } result.put(fields[0],fields[1]); @@ -210,35 +243,7 @@ public class SettingsManager } } - // stores different defaults in the file - public boolean setDefaultRule(ServerCommandSource source, String settingName, String stringValue) - { - if (locked) return false; - if (rules.containsKey(settingName)) - { - Pair,Boolean> conf = readSettingsFromConf(); - conf.getLeft().put(settingName, stringValue); - writeSettingsToConf(conf.getLeft()); // this may feels weird, but if conf - // is locked, it will never reach this point. - rules.get(settingName).set(source,stringValue); - return true; - } - return false; - } - // removes overrides of the default values in the file - public boolean removeDefaultRule(ServerCommandSource source, String settingName) - { - if (locked) return false; - if (rules.containsKey(settingName)) - { - Pair,Boolean> conf = readSettingsFromConf(); - conf.getLeft().remove(settingName); - writeSettingsToConf(conf.getLeft()); - rules.get(settingName).resetToDefault(source); - return true; - } - return false; - } + public Collection> getRulesMatching(String search) { String lcSearch = search.toLowerCase(Locale.ROOT); @@ -253,7 +258,7 @@ public class SettingsManager public int printAllRulesToLog() { PrintStream ps = System.out; - ps.println("# Carpet Settings"); + ps.println("# "+fancyName+" Settings"); for (Map.Entry> e : new TreeMap<>(rules).entrySet()) { ParsedRule rule = e.getValue(); @@ -284,4 +289,214 @@ public class SettingsManager return 1; } + + private ParsedRule contextRule(CommandContext ctx) throws CommandSyntaxException + { + String ruleName = StringArgumentType.getString(ctx, "rule"); + ParsedRule rule = getRule(ruleName); + if (rule == null) + throw new SimpleCommandExceptionType(Messenger.c("rb Unknown rule: "+ruleName)).create(); + return rule; + } + + private void registerCommand(CommandDispatcher dispatcher) + { + if (dispatcher.getRoot().getChildren().stream().anyMatch(node -> node.getName().equalsIgnoreCase(identifier))) + { + Messenger.print_server_message(CarpetServer.minecraft_server, + Messenger.c("rb Failed to add settings command for " + identifier + ". It is masking previous command.")); + return; + } + CarpetSettings.LOG.error("\n\n\n\n REGISTERIN\n\n\n\n"); + + LiteralArgumentBuilder literalargumentbuilder = literal(identifier).requires((player) -> + player.hasPermissionLevel(2) && !locked); + + literalargumentbuilder.executes((context)->listAllSettings(context.getSource())). + then(literal("list"). + executes( (c) -> listSettings(c.getSource(), "All "+fancyName+" Settings", + getRules())). + then(literal("defaults"). + executes( (c)-> listSettings(c.getSource(), + "Current "+fancyName+" Startup Settings from "+identifier+".conf", + findStartupOverrides()))). + then(argument("tag",StringArgumentType.word()). + suggests( (c, b)->suggestMatching(getCategories(), b)). + executes( (c) -> listSettings(c.getSource(), + String.format(fancyName+" Settings matching \"%s\"", StringArgumentType.getString(c, "tag")), + getRulesMatching(StringArgumentType.getString(c, "tag")))))). + then(literal("removeDefault"). + requires(s -> !locked). + then(argument("rule", StringArgumentType.word()). + suggests( (c, b) -> suggestMatching(getRules().stream().map(r -> r.name), b)). + executes((c) -> removeDefault(c.getSource(), contextRule(c))))). + then(literal("setDefault"). + requires(s -> !locked). + then(argument("rule", StringArgumentType.word()). + suggests( (c, b) -> suggestMatching(getRules().stream().map(r -> r.name), b)). + then(argument("value", StringArgumentType.word()). + suggests((c, b)-> suggestMatching(contextRule(c).options, b)). + executes((c) -> setDefault(c.getSource(), contextRule(c), StringArgumentType.getString(c, "value")))))). + then(argument("rule", StringArgumentType.word()). + suggests( (c, b) -> suggestMatching(getRules().stream().map(r -> r.name), b)). + requires(s -> !locked ). + executes( (c) -> displayRuleMenu(c.getSource(), contextRule(c))). + then(argument("value", StringArgumentType.word()). + suggests((c, b)-> suggestMatching(contextRule(c).options,b)). + executes((c) -> setRule(c.getSource(), contextRule(c), StringArgumentType.getString(c, "value"))))); + + dispatcher.register(literalargumentbuilder); + } + + private int displayRuleMenu(ServerCommandSource source, ParsedRule rule) + { + PlayerEntity player; + try + { + player = source.getPlayer(); + } + catch (CommandSyntaxException e) + { + Messenger.m(source, "w "+rule.name +" is set to: ","wb "+rule.getAsString()); + return 1; + } + + Messenger.m(player, ""); + Messenger.m(player, "wb "+rule.name,"!/"+identifier+" "+rule.name,"^g refresh"); + Messenger.m(player, "w "+rule.description); + + rule.extraInfo.forEach(s -> Messenger.m(player, "g "+s)); + + List tags = new ArrayList<>(); + tags.add(Messenger.c("w Tags: ")); + for (String t: rule.categories) + { + tags.add(Messenger.c("c ["+t+"]", "^g list all "+t+" settings","!/"+identifier+" list "+t)); + tags.add(Messenger.c("w , ")); + } + tags.remove(tags.size()-1); + Messenger.m(player, tags.toArray(new Object[0])); + + Messenger.m(player, "w Current value: ",String.format("%s %s (%s value)",rule.getBoolValue()?"lb":"nb", rule.getAsString(),rule.isDefault()?"default":"modified")); + List options = new ArrayList<>(); + options.add(Messenger.c("w Options: ", "y [ ")); + for (String o: rule.options) + { + options.add(makeSetRuleButton(rule, o, false)); + options.add(Messenger.c("w ")); + } + options.remove(options.size()-1); + options.add(Messenger.c("y ]")); + Messenger.m(player, options.toArray(new Object[0])); + + return 1; + } + + private int setRule(ServerCommandSource source, ParsedRule rule, String newValue) + { + if (rule.set(source, newValue) != null) + Messenger.m(source, "w "+rule.toString()+", ", "c [change permanently?]", + "^w Click to keep the settings in carpet.conf to save across restarts", + "?/carpet setDefault "+rule.name+" "+rule.getAsString()); + return 1; + } + + // stores different defaults in the file + private int setDefault(ServerCommandSource source, ParsedRule rule, String stringValue) + { + if (locked) return 0; + if (!rules.containsKey(rule.name)) return 0; + Pair,Boolean> conf = readSettingsFromConf(); + conf.getLeft().put(rule.name, stringValue); + writeSettingsToConf(conf.getLeft()); // this may feels weird, but if conf + // is locked, it will never reach this point. + rule.set(source,stringValue); + Messenger.m(source ,"gi rule "+ rule.name+" will now default to "+ stringValue); + return 1; + } + // removes overrides of the default values in the file + private int removeDefault(ServerCommandSource source, ParsedRule rule) + { + if (locked) return 0; + if (!rules.containsKey(rule.name)) return 0; + Pair,Boolean> conf = readSettingsFromConf(); + conf.getLeft().remove(rule.name); + writeSettingsToConf(conf.getLeft()); + rules.get(rule.name).resetToDefault(source); + return 1; + } + + private BaseText displayInteractiveSetting(ParsedRule rule) + { + List args = new ArrayList<>(); + args.add("w - "+rule.name+" "); + args.add("!/"+identifier+" "+rule.name); + args.add("^y "+rule.description); + for (String option: rule.options) + { + args.add(makeSetRuleButton(rule, option, true)); + args.add("w "); + } + args.remove(args.size()-1); + return Messenger.c(args.toArray(new Object[0])); + } + + private BaseText makeSetRuleButton(ParsedRule rule, String option, boolean brackets) + { + String style = rule.isDefault()?"g":(option.equalsIgnoreCase(rule.defaultAsString)?"e":"y"); + if (option.equalsIgnoreCase(rule.getAsString())) + { + style = style + "u"; + if (option.equalsIgnoreCase(rule.defaultAsString)) + style = style + "b"; + } + String baseText = style + (brackets ? " [" : " ") + option + (brackets ? "]" : ""); + if (locked) + return Messenger.c(baseText, "^g "+fancyName+" settings are locked"); + if (option.equalsIgnoreCase(rule.getAsString())) + return Messenger.c(baseText); + return Messenger.c(baseText, "^g Switch to " + option+(option.equalsIgnoreCase(rule.defaultAsString)?" (default)":""), "?/"+identifier+" " + rule.name + " " + option); + } + + private int listSettings(ServerCommandSource source, String title, Collection> settings_list) + { + try + { + PlayerEntity player = source.getPlayer(); + Messenger.m(player,String.format("wb %s:",title)); + settings_list.forEach(e -> Messenger.m(player,displayInteractiveSetting(e))); + + } + catch (CommandSyntaxException e) + { + Messenger.m(source, "w s:"+title); + settings_list.forEach(r -> Messenger.m(source, "w - "+ r.toString())); + } + return 1; + } + private int listAllSettings(ServerCommandSource source) + { + listSettings(source, "Current "+fancyName+" Settings", getNonDefault()); + + if (version != null) + Messenger.m(source, fancyName+" version: "+ version); + try + { + PlayerEntity player = source.getPlayer(); + List tags = new ArrayList<>(); + tags.add("w Browse Categories:\n"); + for (String t : getCategories()) + { + tags.add("c [" + t+"]"); + tags.add("^g list all " + t + " settings"); + tags.add("!/"+identifier+" list " + t); + tags.add("w "); + } + tags.remove(tags.size() - 1); + Messenger.m(player, tags.toArray(new Object[0])); + } + catch (CommandSyntaxException ignored) { } + return 1; + } + }