Merge pull request #47 from gnembon/better_extensions
rule management and extensibility
This commit is contained in:
6 files changed
+336
-275
No files matched your search
@@ -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<ServerCommandSource> 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) {}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
package carpet;
|
package carpet;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import carpet.commands.CameraModeCommand;
|
import carpet.commands.CameraModeCommand;
|
||||||
import carpet.commands.CarpetCommand;
|
|
||||||
import carpet.commands.CounterCommand;
|
import carpet.commands.CounterCommand;
|
||||||
import carpet.commands.DistanceCommand;
|
import carpet.commands.DistanceCommand;
|
||||||
import carpet.commands.DrawCommand;
|
import carpet.commands.DrawCommand;
|
||||||
@@ -14,7 +15,6 @@ import carpet.commands.PerimeterInfoCommand;
|
|||||||
import carpet.commands.PlayerCommand;
|
import carpet.commands.PlayerCommand;
|
||||||
import carpet.commands.ScriptCommand;
|
import carpet.commands.ScriptCommand;
|
||||||
import carpet.commands.SpawnCommand;
|
import carpet.commands.SpawnCommand;
|
||||||
import carpet.commands.TestCommand;
|
|
||||||
import carpet.commands.TickCommand;
|
import carpet.commands.TickCommand;
|
||||||
import carpet.helpers.TickSpeed;
|
import carpet.helpers.TickSpeed;
|
||||||
import carpet.logging.LoggerRegistry;
|
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 MinecraftServer minecraft_server;
|
||||||
public static CarpetScriptServer scriptServer;
|
public static CarpetScriptServer scriptServer;
|
||||||
public static SettingsManager settingsManager;
|
public static SettingsManager settingsManager;
|
||||||
static
|
public static List<CarpetExtension> 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
|
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;
|
CarpetServer.minecraft_server = server;
|
||||||
}
|
}
|
||||||
public static void onServerLoaded(MinecraftServer 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();
|
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)
|
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();
|
scriptServer.events.tick();
|
||||||
//in case something happens
|
//in case something happens
|
||||||
CarpetSettings.impendingFillSkipUpdates = false;
|
CarpetSettings.impendingFillSkipUpdates = false;
|
||||||
|
extensions.forEach(e -> e.onTick(server));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void registerCarpetCommands(CommandDispatcher<ServerCommandSource> dispatcher)
|
public static void registerCarpetCommands(CommandDispatcher<ServerCommandSource> dispatcher)
|
||||||
@@ -74,7 +87,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);
|
||||||
CarpetCommand.register(dispatcher);
|
extensions.forEach(e -> e.registerCommands(dispatcher));
|
||||||
//TestCommand.register(dispatcher);
|
//TestCommand.register(dispatcher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<ServerCommandSource> 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<ServerCommandSource> dispatcher)
|
|
||||||
{
|
|
||||||
LiteralArgumentBuilder<ServerCommandSource> 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<BaseText> 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<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)
|
|
||||||
{
|
|
||||||
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<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 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<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 : 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -25,7 +25,7 @@ import static carpet.settings.RuleCategory.SURVIVAL;
|
|||||||
|
|
||||||
public class CarpetSettings
|
public class CarpetSettings
|
||||||
{
|
{
|
||||||
public static final String carpetVersion = "v190627";
|
public static final String carpetVersion = "v190704";
|
||||||
public static final Logger LOG = LogManager.getLogger();
|
public static final Logger LOG = LogManager.getLogger();
|
||||||
public static boolean skipGenerationChecks = false;
|
public static boolean skipGenerationChecks = false;
|
||||||
public static boolean impendingFillSkipUpdates = false;
|
public static boolean impendingFillSkipUpdates = false;
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ public final class ParsedRule<T> implements Comparable<ParsedRule> {
|
|||||||
if (!value.equals(get()))
|
if (!value.equals(get()))
|
||||||
{
|
{
|
||||||
this.field.set(null, value);
|
this.field.set(null, value);
|
||||||
SettingsManager.notifyRuleChanged(source, this, stringValue);
|
CarpetServer.settingsManager.notifyRuleChanged(source, this, stringValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IllegalAccessException e)
|
catch (IllegalAccessException e)
|
||||||
|
|||||||
@@ -1,12 +1,20 @@
|
|||||||
package carpet.settings;
|
package carpet.settings;
|
||||||
|
|
||||||
|
import carpet.CarpetServer;
|
||||||
|
import carpet.utils.Messenger;
|
||||||
import com.google.common.collect.ImmutableList;
|
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 net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.command.ServerCommandSource;
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.text.BaseText;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
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 org.apache.logging.log4j.util.TriConsumer;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
@@ -28,21 +36,44 @@ import java.util.Set;
|
|||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.stream.Collectors;
|
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
|
public class SettingsManager
|
||||||
{
|
{
|
||||||
private static final Logger LOG = LogManager.getLogger();
|
private Map<String, ParsedRule<?>> rules = new HashMap<>();
|
||||||
private static Map<String, ParsedRule<?>> rules = new HashMap<>();
|
|
||||||
public boolean locked;
|
public boolean locked;
|
||||||
|
private final String version;
|
||||||
|
private final String identifier;
|
||||||
|
private final String fancyName;
|
||||||
private MinecraftServer server;
|
private MinecraftServer server;
|
||||||
private static List<TriConsumer<ServerCommandSource, ParsedRule<?>, String>> observers = new ArrayList<>();
|
private List<TriConsumer<ServerCommandSource, ParsedRule<?>, 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;
|
this.server = server;
|
||||||
loadConfigurationFromConf();
|
loadConfigurationFromConf();
|
||||||
|
registerCommand(server.getCommandManager().getDispatcher());
|
||||||
|
notifyPlayersCommandsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void parseSettingsClass(Class settingsClass)
|
public void parseSettingsClass(Class settingsClass)
|
||||||
{
|
{
|
||||||
for (Field f : settingsClass.getDeclaredFields())
|
for (Field f : settingsClass.getDeclaredFields())
|
||||||
{
|
{
|
||||||
@@ -53,17 +84,17 @@ public class SettingsManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addRuleObserver(TriConsumer<ServerCommandSource, ParsedRule<?>, String> observer)
|
public void addRuleObserver(TriConsumer<ServerCommandSource, ParsedRule<?>, String> observer)
|
||||||
{
|
{
|
||||||
observers.add(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));
|
observers.forEach(observer -> observer.accept(source, rule, userTypedValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Iterable<String> getCategories()
|
public Iterable<String> getCategories()
|
||||||
{
|
{
|
||||||
Set<String> categories = new HashSet<>();
|
Set<String> categories = new HashSet<>();
|
||||||
getRules().stream().map(r -> r.categories).forEach(categories::addAll);
|
getRules().stream().map(r -> r.categories).forEach(categories::addAll);
|
||||||
@@ -71,12 +102,12 @@ public class SettingsManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static ParsedRule<?> getRule(String name)
|
public ParsedRule<?> getRule(String name)
|
||||||
{
|
{
|
||||||
return rules.get(name);
|
return rules.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Collection<ParsedRule<?>> getRules()
|
public Collection<ParsedRule<?>> getRules()
|
||||||
{
|
{
|
||||||
return rules.values().stream().sorted().collect(Collectors.toList());
|
return rules.values().stream().sorted().collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
@@ -96,7 +127,7 @@ public class SettingsManager
|
|||||||
|
|
||||||
private File getFile()
|
private File getFile()
|
||||||
{
|
{
|
||||||
return server.getLevelStorage().resolveFile(server.getLevelName(), "carpet.conf");
|
return server.getLevelStorage().resolveFile(server.getLevelName(), identifier+".conf");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disableBooleanFromCategory(String category)
|
public void disableBooleanFromCategory(String category)
|
||||||
@@ -126,7 +157,7 @@ public class SettingsManager
|
|||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
e.printStackTrace();
|
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();
|
///todo is it really needed? resendCommandTree();
|
||||||
}
|
}
|
||||||
@@ -150,13 +181,13 @@ public class SettingsManager
|
|||||||
locked = false;
|
locked = false;
|
||||||
if (conf.getRight())
|
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);
|
disableBooleanFromCategory(RuleCategory.COMMAND);
|
||||||
}
|
}
|
||||||
for (String key: conf.getLeft().keySet())
|
for (String key: conf.getLeft().keySet())
|
||||||
{
|
{
|
||||||
if (rules.get(key).set(server.getCommandSource(), conf.getLeft().get(key)) != null)
|
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();
|
locked = conf.getRight();
|
||||||
}
|
}
|
||||||
@@ -182,14 +213,14 @@ public class SettingsManager
|
|||||||
{
|
{
|
||||||
if (!rules.containsKey(fields[0]))
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
ParsedRule rule = rules.get(fields[0]);
|
ParsedRule rule = rules.get(fields[0]);
|
||||||
|
|
||||||
if (!(rule.options.contains(fields[1])) && rule.isStrict)
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
result.put(fields[0],fields[1]);
|
result.put(fields[0],fields[1]);
|
||||||
@@ -210,35 +241,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<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(String search) {
|
public Collection<ParsedRule<?>> getRulesMatching(String search) {
|
||||||
String lcSearch = search.toLowerCase(Locale.ROOT);
|
String lcSearch = search.toLowerCase(Locale.ROOT);
|
||||||
@@ -253,7 +256,7 @@ public class SettingsManager
|
|||||||
public int printAllRulesToLog()
|
public int printAllRulesToLog()
|
||||||
{
|
{
|
||||||
PrintStream ps = System.out;
|
PrintStream ps = System.out;
|
||||||
ps.println("# Carpet Settings");
|
ps.println("# "+fancyName+" Settings");
|
||||||
for (Map.Entry<String, ParsedRule<?>> e : new TreeMap<>(rules).entrySet())
|
for (Map.Entry<String, ParsedRule<?>> e : new TreeMap<>(rules).entrySet())
|
||||||
{
|
{
|
||||||
ParsedRule<?> rule = e.getValue();
|
ParsedRule<?> rule = e.getValue();
|
||||||
@@ -284,4 +287,213 @@ public class SettingsManager
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private ParsedRule<?> contextRule(CommandContext<ServerCommandSource> 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<ServerCommandSource> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
LiteralArgumentBuilder<ServerCommandSource> 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<BaseText> 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<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 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<Map<String, String>,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<Map<String, String>,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<Object> 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<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 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<Object> 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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user