settings system
This commit is contained in:
1 parent
c7739f1963
commit
92f40c36b8
9 files changed
+863
-21
No files matched your search
@@ -10,6 +10,7 @@ import carpet.commands.DistanceCommand;
|
|||||||
import carpet.commands.DrawCommand;
|
import carpet.commands.DrawCommand;
|
||||||
import carpet.commands.InfoCommand;
|
import carpet.commands.InfoCommand;
|
||||||
import carpet.commands.LogCommand;
|
import carpet.commands.LogCommand;
|
||||||
|
import carpet.commands.ParcetCommand;
|
||||||
import carpet.commands.PerimeterInfoCommand;
|
import carpet.commands.PerimeterInfoCommand;
|
||||||
import carpet.commands.PlayerCommand;
|
import carpet.commands.PlayerCommand;
|
||||||
import carpet.commands.ScriptCommand;
|
import carpet.commands.ScriptCommand;
|
||||||
@@ -18,6 +19,8 @@ import carpet.commands.TickCommand;
|
|||||||
import carpet.helpers.TickSpeed;
|
import carpet.helpers.TickSpeed;
|
||||||
import carpet.logging.LoggerRegistry;
|
import carpet.logging.LoggerRegistry;
|
||||||
import carpet.script.CarpetScriptServer;
|
import carpet.script.CarpetScriptServer;
|
||||||
|
import carpet.settings.Settings;
|
||||||
|
import carpet.settings.SettingsManager;
|
||||||
import carpet.utils.HUDController;
|
import carpet.utils.HUDController;
|
||||||
import com.mojang.brigadier.CommandDispatcher;
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
import net.minecraft.server.command.ServerCommandSource;
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
@@ -28,12 +31,21 @@ public class CarpetServer // static for now - easier to handle all around the co
|
|||||||
public static final Random rand = new Random((int)((2>>16)*Math.random()));
|
public static final Random rand = new Random((int)((2>>16)*Math.random()));
|
||||||
public static MinecraftServer minecraft_server;
|
public static MinecraftServer minecraft_server;
|
||||||
public static CarpetScriptServer scriptServer;
|
public static CarpetScriptServer scriptServer;
|
||||||
|
public static SettingsManager settingsManager;
|
||||||
|
static {
|
||||||
|
SettingsManager.parseSettingsClass(Settings.class);
|
||||||
|
//...
|
||||||
|
}
|
||||||
public static void init(MinecraftServer server) //aka constructor of this static singleton class
|
public static void init(MinecraftServer server) //aka constructor of this static singleton class
|
||||||
{
|
{
|
||||||
CarpetServer.minecraft_server = server;
|
CarpetServer.minecraft_server = server;
|
||||||
}
|
}
|
||||||
public static void onServerLoaded(MinecraftServer server)
|
public static void onServerLoaded(MinecraftServer server)
|
||||||
{
|
{
|
||||||
|
//new
|
||||||
|
settingsManager = new SettingsManager(server);
|
||||||
|
|
||||||
|
//old
|
||||||
CarpetSettings.apply_settings_from_conf(server);
|
CarpetSettings.apply_settings_from_conf(server);
|
||||||
scriptServer = new CarpetScriptServer();
|
scriptServer = new CarpetScriptServer();
|
||||||
}
|
}
|
||||||
@@ -65,6 +77,7 @@ public class CarpetServer // static for now - easier to handle all around the co
|
|||||||
PerimeterInfoCommand.register(dispatcher);
|
PerimeterInfoCommand.register(dispatcher);
|
||||||
DrawCommand.register(dispatcher);
|
DrawCommand.register(dispatcher);
|
||||||
ScriptCommand.register(dispatcher);
|
ScriptCommand.register(dispatcher);
|
||||||
|
ParcetCommand.register(dispatcher);
|
||||||
|
|
||||||
//TestCommand.register(dispatcher);
|
//TestCommand.register(dispatcher);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import net.minecraft.server.MinecraftServer;
|
|||||||
import net.minecraft.server.command.ServerCommandSource;
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
import net.minecraft.server.dedicated.DedicatedServer;
|
import net.minecraft.server.dedicated.DedicatedServer;
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
@@ -214,19 +215,19 @@ public class CarpetSettings
|
|||||||
|
|
||||||
public static void apply_settings_from_conf(MinecraftServer server)
|
public static void apply_settings_from_conf(MinecraftServer server)
|
||||||
{
|
{
|
||||||
Map<String, String> conf = read_conf(server);
|
Pair<Map<String, String>,Boolean> conf = read_conf(server);
|
||||||
boolean is_locked = locked;
|
|
||||||
locked = false;
|
locked = false;
|
||||||
if (is_locked)
|
if (conf.getRight())
|
||||||
{
|
{
|
||||||
LOG.info("[CM]: Carpet Mod is locked by the administrator");
|
LOG.info("[CM]: Carpet Mod is locked by the administrator");
|
||||||
|
disable_commands_by_default();
|
||||||
}
|
}
|
||||||
for (String key: conf.keySet())
|
for (String key: conf.getLeft().keySet())
|
||||||
{
|
{
|
||||||
set(server.getCommandSource(), key, conf.get(key));
|
set(server.getCommandSource(), key, conf.getLeft().get(key));
|
||||||
LOG.info("[CM]: loaded setting "+key+" as "+conf.get(key)+" from carpet.conf");
|
LOG.info("[CM]: loaded setting "+key+" as "+conf.getLeft().get(key)+" from carpet.conf");
|
||||||
}
|
}
|
||||||
locked = is_locked;
|
locked = conf.getRight();
|
||||||
}
|
}
|
||||||
private static void disable_commands_by_default()
|
private static void disable_commands_by_default()
|
||||||
{
|
{
|
||||||
@@ -239,21 +240,21 @@ public class CarpetSettings
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, String> read_conf(MinecraftServer server)
|
private static Pair<Map<String, String>,Boolean> read_conf(MinecraftServer server)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File settings_file = server.getLevelStorage().resolveFile(server.getLevelName(), "carpet.conf");
|
File settings_file = server.getLevelStorage().resolveFile(server.getLevelName(), "carpet.conf");
|
||||||
BufferedReader b = new BufferedReader(new FileReader(settings_file));
|
BufferedReader b = new BufferedReader(new FileReader(settings_file));
|
||||||
String line = "";
|
String line = "";
|
||||||
|
boolean confLocked = false;
|
||||||
Map<String,String> result = new HashMap<String, String>();
|
Map<String,String> result = new HashMap<String, String>();
|
||||||
while ((line = b.readLine()) != null)
|
while ((line = b.readLine()) != null)
|
||||||
{
|
{
|
||||||
line = line.replaceAll("\\r|\\n", "");
|
line = line.replaceAll("\\r|\\n", "");
|
||||||
if ("locked".equalsIgnoreCase(line))
|
if ("locked".equalsIgnoreCase(line))
|
||||||
{
|
{
|
||||||
disable_commands_by_default();
|
confLocked = true;
|
||||||
locked = true;
|
|
||||||
}
|
}
|
||||||
String[] fields = line.split("\\s+",2);
|
String[] fields = line.split("\\s+",2);
|
||||||
if (fields.length > 1)
|
if (fields.length > 1)
|
||||||
@@ -272,16 +273,16 @@ public class CarpetSettings
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
b.close();
|
b.close();
|
||||||
return result;
|
return Pair.of(result, confLocked);
|
||||||
}
|
}
|
||||||
catch(FileNotFoundException e)
|
catch(FileNotFoundException e)
|
||||||
{
|
{
|
||||||
return new HashMap<>();
|
return Pair.of(new HashMap<>(), false);
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return new HashMap<>();
|
return Pair.of(new HashMap<>(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -311,9 +312,10 @@ public class CarpetSettings
|
|||||||
if (locked) return false;
|
if (locked) return false;
|
||||||
if (settings_store.containsKey(setting_name))
|
if (settings_store.containsKey(setting_name))
|
||||||
{
|
{
|
||||||
Map<String, String> conf = read_conf(source.getMinecraftServer());
|
Pair<Map<String, String>,Boolean> conf = read_conf(source.getMinecraftServer());
|
||||||
conf.put(setting_name, string_value);
|
conf.getLeft().put(setting_name, string_value);
|
||||||
write_conf(source.getMinecraftServer(), conf);
|
write_conf(source.getMinecraftServer(), conf.getLeft()); // this may feels weird, but if conf
|
||||||
|
// is locked, it will never reach this point.
|
||||||
set(source, setting_name,string_value);
|
set(source, setting_name,string_value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -325,9 +327,9 @@ public class CarpetSettings
|
|||||||
if (locked) return false;
|
if (locked) return false;
|
||||||
if (settings_store.containsKey(setting_name))
|
if (settings_store.containsKey(setting_name))
|
||||||
{
|
{
|
||||||
Map<String, String> conf = read_conf(source.getMinecraftServer());
|
Pair<Map<String, String>,Boolean> conf = read_conf(source.getMinecraftServer());
|
||||||
conf.remove(setting_name);
|
conf.getLeft().remove(setting_name);
|
||||||
write_conf(source.getMinecraftServer(), conf);
|
write_conf(source.getMinecraftServer(), conf.getLeft());
|
||||||
set(source, setting_name,get(setting_name).getDefault());
|
set(source, setting_name,get(setting_name).getDefault());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -386,7 +388,7 @@ public class CarpetSettings
|
|||||||
public static CarpetSettingEntry[] find_nondefault(MinecraftServer server)
|
public static CarpetSettingEntry[] find_nondefault(MinecraftServer server)
|
||||||
{
|
{
|
||||||
ArrayList<CarpetSettingEntry> res = new ArrayList<CarpetSettingEntry>();
|
ArrayList<CarpetSettingEntry> res = new ArrayList<CarpetSettingEntry>();
|
||||||
Map <String,String> defaults = read_conf(server);
|
Map <String,String> defaults = read_conf(server).getLeft();
|
||||||
for (String rule: settings_store.keySet().stream().sorted().collect(Collectors.toList()))
|
for (String rule: settings_store.keySet().stream().sorted().collect(Collectors.toList()))
|
||||||
{
|
{
|
||||||
if (!settings_store.get(rule).isDefault() || defaults.containsKey(rule))
|
if (!settings_store.get(rule).isDefault() || defaults.containsKey(rule))
|
||||||
@@ -400,7 +402,7 @@ public class CarpetSettings
|
|||||||
{
|
{
|
||||||
ArrayList<CarpetSettingEntry> res = new ArrayList<CarpetSettingEntry>();
|
ArrayList<CarpetSettingEntry> res = new ArrayList<CarpetSettingEntry>();
|
||||||
if (locked) return res.toArray(new CarpetSettingEntry[0]);
|
if (locked) return res.toArray(new CarpetSettingEntry[0]);
|
||||||
Map <String,String> defaults = read_conf(server);
|
Map <String,String> defaults = read_conf(server).getLeft();
|
||||||
for (String rule: settings_store.keySet().stream().sorted().collect(Collectors.toList()))
|
for (String rule: settings_store.keySet().stream().sorted().collect(Collectors.toList()))
|
||||||
{
|
{
|
||||||
if (defaults.containsKey(rule))
|
if (defaults.containsKey(rule))
|
||||||
|
|||||||
@@ -0,0 +1,209 @@
|
|||||||
|
package carpet.commands;
|
||||||
|
|
||||||
|
import carpet.CarpetServer;
|
||||||
|
import carpet.CarpetSettings;
|
||||||
|
import carpet.settings.ParsedRule;
|
||||||
|
import carpet.settings.RuleCategory;
|
||||||
|
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.exceptions.CommandSyntaxException;
|
||||||
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
|
import net.minecraft.server.command.CommandManager;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.text.BaseText;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
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 ParcetCommand
|
||||||
|
{
|
||||||
|
public static void register(CommandDispatcher<ServerCommandSource> dispatcher)
|
||||||
|
{
|
||||||
|
LiteralArgumentBuilder<ServerCommandSource> literalargumentbuilder = literal("parcet").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(Arrays.stream(RuleCategory.values()).map(r -> r.lowerCase), b)).
|
||||||
|
executes( (c) -> listSettings(c.getSource(),
|
||||||
|
String.format("CarpetMod Settings matching \"%s\"", StringArgumentType.getString(c, "tag")),
|
||||||
|
CarpetServer.settingsManager.getRulesMatching(StringArgumentType.getString(c, "tag"))))));
|
||||||
|
|
||||||
|
for (ParsedRule<?> rule: SettingsManager.getRules())
|
||||||
|
{
|
||||||
|
literalargumentbuilder.then(literal(rule.name).executes( (context) ->
|
||||||
|
displayRuleMenu(context.getSource(),rule)));
|
||||||
|
literalargumentbuilder.then(literal("removeDefault").
|
||||||
|
requires(s -> !CarpetServer.settingsManager.locked).
|
||||||
|
then(literal(rule.name).executes((context) ->
|
||||||
|
removeDefault(context.getSource(), rule))));
|
||||||
|
literalargumentbuilder.then(literal(rule.name).
|
||||||
|
requires(s -> !CarpetServer.settingsManager.locked).
|
||||||
|
then(argument("value", StringArgumentType.word()).
|
||||||
|
suggests((c, b)-> suggestMatching(rule.options,b)).
|
||||||
|
executes((context) ->
|
||||||
|
setRule(context.getSource(), rule, StringArgumentType.getString(context, "value")))));
|
||||||
|
literalargumentbuilder.then(literal("setDefault").
|
||||||
|
requires(s -> !CarpetServer.settingsManager.locked).
|
||||||
|
then(literal(rule.name).
|
||||||
|
then(argument("value", StringArgumentType.word()).
|
||||||
|
suggests((c, b)-> suggestMatching(rule.options,b)).
|
||||||
|
executes((context) ->
|
||||||
|
setDefault(context.getSource(), rule, StringArgumentType.getString(context, "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<BaseText> tags = new ArrayList<>();
|
||||||
|
tags.add(Messenger.c("w Tags: "));
|
||||||
|
for (String t: Arrays.stream(RuleCategory.values()).sorted().map(c -> c.lowerCase).collect(Collectors.toList()))
|
||||||
|
{
|
||||||
|
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<BaseText> 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)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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<Object> 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 color = "";
|
||||||
|
if (option.equals(rule.defaultAsString) && !brackets) color += "u";
|
||||||
|
color += option.equals(rule.getAsString()) ? "bl" : "y";
|
||||||
|
String baseText = color + (brackets ? " [" : " ") + option + (brackets ? "]" : "");
|
||||||
|
if (CarpetServer.settingsManager.locked) {
|
||||||
|
return Messenger.c(baseText, "^g Settings are locked");
|
||||||
|
}
|
||||||
|
return Messenger.c(baseText, "^g Switch to " + option, "?/carpet " + rule.name + " " + option);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int listSettings(ServerCommandSource source, String title, Collection<ParsedRule<?>> 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<Object> tags = new ArrayList<>();
|
||||||
|
tags.add("w Browse Categories:\n");
|
||||||
|
for (String t : Arrays.stream(RuleCategory.values()).map(r -> r.lowerCase).collect(Collectors.toList()))
|
||||||
|
{
|
||||||
|
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 e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,170 @@
|
|||||||
|
package carpet.settings;
|
||||||
|
|
||||||
|
import carpet.utils.Messenger;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public final class ParsedRule<T> implements Comparable<ParsedRule> {
|
||||||
|
public final Rule rule;
|
||||||
|
public final Field field;
|
||||||
|
|
||||||
|
public final String name;
|
||||||
|
public final String description;
|
||||||
|
public final ImmutableList<String> extraInfo;
|
||||||
|
public final ImmutableList<RuleCategory> categories;
|
||||||
|
public final ImmutableList<String> options;
|
||||||
|
public boolean isStrict;
|
||||||
|
public final Class<T> type;
|
||||||
|
public final List<Validator<T>> validators;
|
||||||
|
public final T defaultValue;
|
||||||
|
public final String defaultAsString;
|
||||||
|
|
||||||
|
public static <T> T callConstructor(Class<T> cls) {
|
||||||
|
try {
|
||||||
|
Constructor<T> constr = cls.getDeclaredConstructor();
|
||||||
|
constr.setAccessible(true);
|
||||||
|
return constr.newInstance();
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParsedRule(Field field, Rule rule) {
|
||||||
|
this.rule = rule;
|
||||||
|
this.field = field;
|
||||||
|
this.name = rule.name().isEmpty() ? field.getName() : rule.name();
|
||||||
|
this.type = (Class<T>) field.getType();
|
||||||
|
this.description = rule.desc();
|
||||||
|
this.isStrict = rule.strict();
|
||||||
|
this.extraInfo = ImmutableList.copyOf(rule.extra());
|
||||||
|
this.categories = ImmutableList.copyOf(rule.category());
|
||||||
|
this.validators = new ArrayList<>();
|
||||||
|
for (Class v : rule.validate())
|
||||||
|
{
|
||||||
|
this.validators.add((Validator<T>) callConstructor(v));
|
||||||
|
}
|
||||||
|
if (categories.contains(RuleCategory.COMMANDS))
|
||||||
|
this.validators.add(callConstructor(Validator._COMMAND.class));
|
||||||
|
|
||||||
|
this.defaultValue = get();
|
||||||
|
this.defaultAsString = convertToString(this.defaultValue);
|
||||||
|
if (this.type == boolean.class) {
|
||||||
|
this.isStrict = true; // it has no sense otherwise
|
||||||
|
this.options = ImmutableList.of("true", "false");
|
||||||
|
} else if (this.type.isEnum()) {
|
||||||
|
this.isStrict = true; // it has no sense otherwise
|
||||||
|
this.options = Arrays.stream(this.type.getEnumConstants()).map(e -> ((Enum) e).name().toLowerCase(Locale.ROOT)).collect(ImmutableList.toImmutableList());
|
||||||
|
} else {
|
||||||
|
this.options = ImmutableList.copyOf(rule.options());
|
||||||
|
}
|
||||||
|
if (isStrict)
|
||||||
|
this.validators.add(callConstructor(Validator._STRICT.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ParsedRule<T> set(ServerCommandSource source, String value) {
|
||||||
|
//if locked - prevent
|
||||||
|
if (type == String.class)
|
||||||
|
{
|
||||||
|
return set(source, (T) value, value);
|
||||||
|
}
|
||||||
|
else if (type == boolean.class)
|
||||||
|
{
|
||||||
|
return set(source, (T) (Object) Boolean.parseBoolean(value), value);
|
||||||
|
}
|
||||||
|
else if (type == int.class)
|
||||||
|
{
|
||||||
|
return set(source, (T) (Object) Integer.parseInt(value), value);
|
||||||
|
}
|
||||||
|
else if (type.isEnum())
|
||||||
|
{
|
||||||
|
String ucValue = value.toUpperCase(Locale.ROOT);
|
||||||
|
return set(source, (T) (Object) Enum.valueOf((Class<? extends Enum>) type, ucValue), value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Messenger.m(source, "r Unknown type " + type.getSimpleName());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParsedRule<T> set(ServerCommandSource source, T value, String stringValue) {
|
||||||
|
try {
|
||||||
|
for (Validator<T> validator : this.validators)
|
||||||
|
{
|
||||||
|
boolean allowed = validator.validate(source, this, value, stringValue);
|
||||||
|
if (!allowed)
|
||||||
|
{
|
||||||
|
Messenger.m(source, "r Wrong value for " + name + ": " + stringValue);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.field.set(null, value);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (IllegalAccessException e)
|
||||||
|
{
|
||||||
|
Messenger.m(source, "r Unable to access setting for "+name);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T get() {
|
||||||
|
try {
|
||||||
|
return (T) this.field.get(null);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAsString() {
|
||||||
|
return convertToString(get());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getBoolValue() {
|
||||||
|
if (type == boolean.class) return (Boolean) get();
|
||||||
|
if (type.isAssignableFrom(Number.class)) return ((Number) get()).doubleValue() > 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDefault() {
|
||||||
|
return defaultValue.equals(get());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetToDefault(ServerCommandSource source) {
|
||||||
|
set(source, defaultValue, defaultAsString);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static String convertToString(Object value) {
|
||||||
|
if (value instanceof Enum) return ((Enum) value).name().toLowerCase(Locale.ROOT);
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return obj.getClass() == ParsedRule.class && ((ParsedRule) obj).name.equals(this.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return this.name.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(ParsedRule o) {
|
||||||
|
return this.name.compareTo(o.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.name + ": " + getAsString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package carpet.settings;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any field in this class annotated with this class is interpreted as a carpet rule.
|
||||||
|
* The field must be static and have a type of one of:
|
||||||
|
* - boolean
|
||||||
|
* - int
|
||||||
|
* - double
|
||||||
|
* - String
|
||||||
|
* - a subclass of Enum
|
||||||
|
* The default value of the rule will be the initial value of the field.
|
||||||
|
*/
|
||||||
|
@Target(ElementType.FIELD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@interface Rule {
|
||||||
|
/**
|
||||||
|
* The rule name, by default the same as the field name
|
||||||
|
*/
|
||||||
|
String name() default ""; // default same as field name
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A description of the rule
|
||||||
|
*/
|
||||||
|
String desc();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra information about the rule
|
||||||
|
*/
|
||||||
|
String[] extra() default {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of categories the rule is in
|
||||||
|
*/
|
||||||
|
RuleCategory[] category();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options to select in menu.
|
||||||
|
* Inferred for booleans and enums. Otherwise, must be present.
|
||||||
|
*/
|
||||||
|
String[] options() default {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* if a rule is not strict - can take any value, otherwise it needs to match
|
||||||
|
* any of the options
|
||||||
|
* For enums, its always strict
|
||||||
|
*/
|
||||||
|
boolean strict() default true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class of the validator checked when the rule is changed.
|
||||||
|
*/
|
||||||
|
Class<? extends Validator>[] validate() default {};
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package carpet.settings;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public enum RuleCategory {
|
||||||
|
BUGFIX, SURVIVAL, CREATIVE, EXPERIMENTAL, OPTIMIZATIONS, FEATURE, COMMANDS ;
|
||||||
|
|
||||||
|
public final String lowerCase;
|
||||||
|
|
||||||
|
RuleCategory() {
|
||||||
|
this.lowerCase = this.name().toLowerCase(Locale.ROOT);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package carpet.settings;
|
||||||
|
|
||||||
|
import static carpet.settings.RuleCategory.BUGFIX;
|
||||||
|
import static carpet.settings.RuleCategory.COMMANDS;
|
||||||
|
import static carpet.settings.RuleCategory.CREATIVE;
|
||||||
|
import static carpet.settings.RuleCategory.EXPERIMENTAL;
|
||||||
|
import static carpet.settings.RuleCategory.FEATURE;
|
||||||
|
import static carpet.settings.RuleCategory.OPTIMIZATIONS;
|
||||||
|
import static carpet.settings.RuleCategory.SURVIVAL;
|
||||||
|
|
||||||
|
public class Settings
|
||||||
|
{
|
||||||
|
@Rule(
|
||||||
|
desc = "Fixes server crashing supposedly on falling behind 60s in ONE tick, yeah bs.",
|
||||||
|
extra = "Fixed 1.12 watchdog crash in 1.13 pre-releases, reintroduced with 1.13, GG.",
|
||||||
|
category = BUGFIX,
|
||||||
|
validate = Validator.WIP.class
|
||||||
|
)
|
||||||
|
public static boolean watchdogCrashFix = false;
|
||||||
|
|
||||||
|
@Rule(
|
||||||
|
desc = "Enables /c and /s commands to quickly switch between camera and survival modes",
|
||||||
|
extra = "/c and /s commands are available to all players regardless of their permission levels",
|
||||||
|
category = COMMANDS
|
||||||
|
)
|
||||||
|
public static boolean commandCameramode = true;
|
||||||
|
|
||||||
|
@Rule(desc = "fill/clone/setblock and structure blocks cause block updates", category = CREATIVE)
|
||||||
|
public static boolean fillUpdates = true;
|
||||||
|
|
||||||
|
@Rule(
|
||||||
|
desc = "Customizable fill/clone volume limit",
|
||||||
|
options = {"32768", "250000", "1000000"},
|
||||||
|
validate = Validator.POSITIVE_NUMBER.class,
|
||||||
|
category = CREATIVE
|
||||||
|
)
|
||||||
|
public static int fillLimit = 32768;
|
||||||
|
|
||||||
|
@Rule(
|
||||||
|
desc = "Hoppers pointing to wool will count items passing through them",
|
||||||
|
extra = {
|
||||||
|
"Enables /counter command, and actions while placing red and green carpets on wool blocks",
|
||||||
|
"Use /counter <color?> reset to reset the counter, and /counter <color?> to query",
|
||||||
|
"In survival, place green carpet on same color wool to query, red to reset the counters",
|
||||||
|
"Counters are global and shared between players, 16 channels available",
|
||||||
|
"Items counted are destroyed, count up to one stack per tick per hopper"
|
||||||
|
},
|
||||||
|
category = COMMANDS
|
||||||
|
)
|
||||||
|
public static boolean hopperCounters = false;
|
||||||
|
|
||||||
|
@Rule(desc = "Explosions won't destroy blocks", category = CREATIVE)
|
||||||
|
public static boolean explosionNoBlockDamage = false;
|
||||||
|
|
||||||
|
@Rule(
|
||||||
|
desc = "Silverfish drop a gravel item when breaking out of a block",
|
||||||
|
category = {FEATURE, EXPERIMENTAL}
|
||||||
|
)
|
||||||
|
public static boolean silverFishDropGravel = false;
|
||||||
|
|
||||||
|
@Rule(desc = "Shulkers will respawn in end cities", category = {FEATURE, EXPERIMENTAL})
|
||||||
|
public static boolean shulkerSpawningInEndCities = false;
|
||||||
|
|
||||||
|
@Rule(
|
||||||
|
desc = "Portals won't let a creative player go through instantly",
|
||||||
|
extra = "Holding obsidian in either hand won't let you through at all",
|
||||||
|
category = CREATIVE
|
||||||
|
)
|
||||||
|
public static boolean portalCreativeDelay = false;
|
||||||
|
|
||||||
|
@Rule(desc = "Pistons can push block entities, like hoppers, chests etc.", category = {FEATURE, EXPERIMENTAL})
|
||||||
|
public static boolean movableTileEntities = false;
|
||||||
|
|
||||||
|
@Rule(
|
||||||
|
desc = "Empty shulker boxes can stack to 64 when dropped on the ground",
|
||||||
|
extra = "To move them around between inventories, use shift click to move entire stacks",
|
||||||
|
category = SURVIVAL
|
||||||
|
)
|
||||||
|
public static boolean stackableShulkerBoxes = false;
|
||||||
|
|
||||||
|
@Rule(desc = "Optimizes spawning", category = {OPTIMIZATIONS, EXPERIMENTAL})
|
||||||
|
public static boolean lagFreeSpawning = false;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,230 @@
|
|||||||
|
package carpet.settings;
|
||||||
|
|
||||||
|
import carpet.CarpetSettings;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class SettingsManager {
|
||||||
|
private static final Logger LOG = LogManager.getLogger();
|
||||||
|
private static Map<String, ParsedRule<?>> rules = new HashMap<>();
|
||||||
|
public boolean locked;
|
||||||
|
MinecraftServer server;
|
||||||
|
|
||||||
|
public SettingsManager(MinecraftServer server)
|
||||||
|
{
|
||||||
|
this.server = server;
|
||||||
|
loadConfigurationFromConf();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void parseSettingsClass(Class settingsClass)
|
||||||
|
{
|
||||||
|
for (Field f : settingsClass.getDeclaredFields())
|
||||||
|
{
|
||||||
|
Rule rule = f.getAnnotation(Rule.class);
|
||||||
|
if (rule == null) continue;
|
||||||
|
ParsedRule parsed = new ParsedRule(f, rule);
|
||||||
|
CarpetSettings.LOG.error("REGISTERED RULE: "+parsed.name);
|
||||||
|
rules.put(parsed.name, parsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ParsedRule getRule(String name) {
|
||||||
|
return rules.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Collection<ParsedRule<?>> getRules() {
|
||||||
|
CarpetSettings.LOG.error("grabbing rules");
|
||||||
|
List<ParsedRule<?>> r = rules.values().stream().sorted().collect(Collectors.toList());
|
||||||
|
CarpetSettings.LOG.error("Got: "+r.size()+" rules");
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<ParsedRule<?>> findStartupOverrides()
|
||||||
|
{
|
||||||
|
Set<String> defaults = readSettingsFromConf().getLeft().keySet();
|
||||||
|
return rules.values().stream().filter(r -> defaults.contains(r.name)).
|
||||||
|
sorted().collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Collection<ParsedRule<?>> getNonDefault() {
|
||||||
|
return rules.values().stream().filter(r -> !r.isDefault()).sorted().collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private File getFile() {
|
||||||
|
return server.getLevelStorage().resolveFile(server.getLevelName(), "carpet.conf");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disableBooleanFromCategory(RuleCategory category) {
|
||||||
|
for (ParsedRule<?> rule : rules.values()) {
|
||||||
|
if (rule.type != boolean.class || !rule.categories.contains(category)) continue;
|
||||||
|
((ParsedRule<Boolean>) rule).set(server.getCommandSource(), false, "false");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void writeSettingsToConf(Map<String, String> values)
|
||||||
|
{
|
||||||
|
if (locked) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FileWriter fw = new FileWriter(getFile());
|
||||||
|
for (String key: values.keySet())
|
||||||
|
{
|
||||||
|
fw.write(key+" "+values.get(key)+"\n");
|
||||||
|
}
|
||||||
|
fw.close();
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
LOG.error("[CM]: failed write the carpet.conf");
|
||||||
|
}
|
||||||
|
///todo is it really needed? resendCommandTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifyPlayersCommandsChanged()
|
||||||
|
{
|
||||||
|
if (server.getPlayerManager() == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (ServerPlayerEntity entityplayermp : server.getPlayerManager().getPlayerList())
|
||||||
|
{
|
||||||
|
server.getCommandManager().sendCommandTree(entityplayermp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadConfigurationFromConf()
|
||||||
|
{
|
||||||
|
for (ParsedRule<?> rule : rules.values()) rule.resetToDefault(server.getCommandSource());
|
||||||
|
Pair<Map<String, String>,Boolean> conf = readSettingsFromConf();
|
||||||
|
locked = false;
|
||||||
|
if (conf.getRight())
|
||||||
|
{
|
||||||
|
LOG.info("[CM]: Carpet Mod is locked by the administrator");
|
||||||
|
disableBooleanFromCategory(RuleCategory.COMMANDS);
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
locked = conf.getRight();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Pair<Map<String, String>,Boolean> readSettingsFromConf()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
BufferedReader reader = new BufferedReader(new FileReader(getFile()));
|
||||||
|
String line = "";
|
||||||
|
boolean confLocked = false;
|
||||||
|
Map<String,String> result = new HashMap<String, String>();
|
||||||
|
while ((line = reader.readLine()) != null)
|
||||||
|
{
|
||||||
|
line = line.replaceAll("\\r|\\n", "");
|
||||||
|
if ("locked".equalsIgnoreCase(line))
|
||||||
|
{
|
||||||
|
confLocked = true;
|
||||||
|
}
|
||||||
|
String[] fields = line.split("\\s+",2);
|
||||||
|
if (fields.length > 1)
|
||||||
|
{
|
||||||
|
if (!rules.containsKey(fields[0]))
|
||||||
|
{
|
||||||
|
LOG.error("[CM]: 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...");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result.put(fields[0],fields[1]);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reader.close();
|
||||||
|
return Pair.of(result, confLocked);
|
||||||
|
}
|
||||||
|
catch(FileNotFoundException e)
|
||||||
|
{
|
||||||
|
return Pair.of(new HashMap<>(), false);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
return Pair.of(new HashMap<>(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// stores different defaults in the file
|
||||||
|
public boolean setDefaultRule(ServerCommandSource source, String settingName, String stringValue)
|
||||||
|
{
|
||||||
|
if (locked) return false;
|
||||||
|
if (rules.containsKey(settingName))
|
||||||
|
{
|
||||||
|
Pair<Map<String, String>,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<Map<String, String>,Boolean> conf = readSettingsFromConf();
|
||||||
|
conf.getLeft().remove(settingName);
|
||||||
|
writeSettingsToConf(conf.getLeft());
|
||||||
|
rules.get(settingName).resetToDefault(source);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<ParsedRule<?>> getRulesMatching(Predicate<ParsedRule<?>> predicate) {
|
||||||
|
return rules.values().stream().filter(predicate).collect(ImmutableList.toImmutableList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<ParsedRule<?>> getRulesMatching(String search) {
|
||||||
|
String lcSearch = search.toLowerCase(Locale.ROOT);
|
||||||
|
return getRulesMatching(rule -> {
|
||||||
|
if (rule.name.toLowerCase(Locale.ROOT).contains(lcSearch)) return true;
|
||||||
|
for (RuleCategory c : rule.categories) if (c.lowerCase.equals(search)) return true;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package carpet.settings;
|
||||||
|
|
||||||
|
import carpet.CarpetServer;
|
||||||
|
import carpet.utils.Messenger;
|
||||||
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public abstract class Validator<T> {
|
||||||
|
/**
|
||||||
|
* Validate the new value of a rule
|
||||||
|
* @return true if valid, false if new rule invalid.
|
||||||
|
*/
|
||||||
|
abstract boolean validate(ServerCommandSource source, ParsedRule<T> currentRule, T newValue, String string);
|
||||||
|
|
||||||
|
|
||||||
|
public static class POSITIVE_NUMBER<T extends Number> extends Validator<T> {
|
||||||
|
@Override
|
||||||
|
public boolean validate(ServerCommandSource source, ParsedRule<T> currentRule, T newValue, String string) {
|
||||||
|
return newValue.doubleValue() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class _COMMAND<T> extends Validator<T> {
|
||||||
|
@Override
|
||||||
|
public boolean validate(ServerCommandSource source, ParsedRule<T> currentRule, T newValue, String string) {
|
||||||
|
if (CarpetServer.settingsManager != null)
|
||||||
|
CarpetServer.settingsManager.notifyPlayersCommandsChanged();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class WIP<T> extends Validator<T> {
|
||||||
|
@Override
|
||||||
|
public boolean validate(ServerCommandSource source, ParsedRule<T> currentRule, T newValue, String string) {
|
||||||
|
if (source != null)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Messenger.m(source, "r Work in progress - limited or no functionality available for "+currentRule.name);
|
||||||
|
}
|
||||||
|
catch (NullPointerException ignored) { }
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static class _STRICT<T> extends Validator<T> {
|
||||||
|
@Override
|
||||||
|
public boolean validate(ServerCommandSource source, ParsedRule<T> currentRule, T newValue, String string) {
|
||||||
|
if (!currentRule.options.contains(string.toLowerCase(Locale.ROOT)))
|
||||||
|
{
|
||||||
|
if (source != null)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Messenger.m(source, "r Valid options: " + currentRule.options.toString());
|
||||||
|
}
|
||||||
|
catch (NullPointerException ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user