Skip to content

Commit 0ffe4de

Browse files
committed
feat: support int options
- add `maxAugmentLevel` option - change type of `nestedContainers` option from `boolean` to `int` closes #44
1 parent 78ac461 commit 0ffe4de

File tree

10 files changed

+142
-45
lines changed

10 files changed

+142
-45
lines changed

README.md

+21-19
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ The Augment enchantment expands the size of a Shulker Box. It is available in
7272
different levels where each level adds nine more slots to the Shulker's
7373
inventory. Just like [Vacuum](#vacuum) and [Void](#void) it is unobtainable in
7474
survival when using the default settings, but that can be configured with the
75-
[`generateAugment` option](#server).
75+
[`generateAugment` option](#server). The maximum level can also be changed with
76+
the [`maxAugmentLevel` option](#server).
7677

7778
## A note on Resource Packs
7879

@@ -137,24 +138,25 @@ The behavior of the mod can be tweaked per world in the `enchantedshulkers.toml`
137138
config file inside you world save folder, or with the `/enchantedshulkers`
138139
command in game. Below is a list of available options.
139140

140-
| **Option** | **Possible Values** | **Default Value** | **Description** |
141-
| ----------------------- | ------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
142-
| `refillOffhand` | `true`, `false` | `true` | Allow refilling stacks in the offhand |
143-
| `refillNonStackables` | `true`, `false` | `false` | Allow refilling non-stackable items like Totems of Undying |
144-
| `enchantableEnderChest` | `true`, `false` | `false` | Allows Ender Chests to also be enchanted |
145-
| `coloredNames` | `true`, `false` | `false` | Show the names of placed enchanted containers in aqua color. This applies to all players |
146-
| `creativeSiphon` | `true`, `false` | `false` | Enable the Siphon enchantment for creative players |
147-
| `creativeRefill` | `true`, `false` | `false` | Enable the Refill enchantment for creative players |
148-
| `creativeVacuum` | `true`, `false` | `false` | Enable the Vacuum enchantment for creative players |
149-
| `creativeVoid` | `true`, `false` | `false` | Enable the Void enchantment for creative players |
150-
| `generateSiphon` | `true`, `false` | `true` | Make the Siphon enchantment obtainable in survival by allowing enchanted books to generate with it |
151-
| `generateRefill` | `true`, `false` | `true` | Make the Refill enchantment obtainable in survival by allowing enchanted books to generate with it |
152-
| `generateVacuum` | `true`, `false` | `false` | Make the Vacuum enchantment obtainable in survival by allowing enchanted books to generate with it |
153-
| `generateVoid` | `true`, `false` | `false` | Make the Void enchantment obtainable in survival by allowing enchanted books to generate with it |
154-
| `generateAugment` | `true`, `false` | `false` | Make the Augment enchantment obtainable in survival by allowing enchanted books to generate with it |
155-
| `nestedContainers` | `true`, `false` | `true` | Search containers recursively up to 256 levels deep (e.g, search through Shulker Boxes in an Ender Chest) |
156-
| `strongerSiphon` | `true`, `false` | `false` | Allow the Siphon enchantment to fill empty slots. The same behavior can be enabled for the Vacuum enchantment with `weakerVacuum` |
157-
| `weakerVacuum` | `true`, `false` | `false` | Require the same item to already be present in the container. The same behavior can be enabled for the Siphon enchantment with `strongerSiphon` |
141+
| **Option** | **Possible Values** | **Default Value** | **Description** |
142+
| ----------------------- | ----------------------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
143+
| `refillOffhand` | `true`, `false` | `true` | Allow refilling stacks in the offhand |
144+
| `refillNonStackables` | `true`, `false` | `false` | Allow refilling non-stackable items like Totems of Undying |
145+
| `enchantableEnderChest` | `true`, `false` | `false` | Allows Ender Chests to also be enchanted |
146+
| `coloredNames` | `true`, `false` | `false` | Show the names of placed enchanted containers in aqua color. This applies to all players |
147+
| `creativeSiphon` | `true`, `false` | `false` | Enable the Siphon enchantment for creative players |
148+
| `creativeRefill` | `true`, `false` | `false` | Enable the Refill enchantment for creative players |
149+
| `creativeVacuum` | `true`, `false` | `false` | Enable the Vacuum enchantment for creative players |
150+
| `creativeVoid` | `true`, `false` | `false` | Enable the Void enchantment for creative players |
151+
| `generateSiphon` | `true`, `false` | `true` | Make the Siphon enchantment obtainable in survival by allowing enchanted books to generate with it |
152+
| `generateRefill` | `true`, `false` | `true` | Make the Refill enchantment obtainable in survival by allowing enchanted books to generate with it |
153+
| `generateVacuum` | `true`, `false` | `false` | Make the Vacuum enchantment obtainable in survival by allowing enchanted books to generate with it |
154+
| `generateVoid` | `true`, `false` | `false` | Make the Void enchantment obtainable in survival by allowing enchanted books to generate with it |
155+
| `generateAugment` | `true`, `false` | `false` | Make the Augment enchantment obtainable in survival by allowing enchanted books to generate with it |
156+
| `nestedContainers` | any integer between `0` and `32767` | `255` | Search containers recursively up to the specified number of levels deep (e.g, search through Shulker Boxes in an Ender Chest) |
157+
| `strongerSiphon` | `true`, `false` | `false` | Allow the Siphon enchantment to fill empty slots. The same behavior can be enabled for the Vacuum enchantment with `weakerVacuum` |
158+
| `weakerVacuum` | `true`, `false` | `false` | Require the same item to already be present in the container. The same behavior can be enabled for the Siphon enchantment with `strongerSiphon` |
159+
| `maxAugmentLevel` | `1`, `2`, `3` | `3` | The maximum level for the Augment enchantment. For the best experience execute `/reload` after changing this value |
158160

159161
## For Mod Developers
160162

src/main/java/de/rubixdev/enchantedshulkers/Utils.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ private static List<ItemStack> getContainers(
9494
// in case some other mod allows shulkers to stack, ignore them to prevent duping
9595
&& (stack.isOf(Items.ENDER_CHEST) || stack.getCount() == 1)) {
9696
out.add(stack);
97-
if (recursionDepth < (WorldConfig.nestedContainers() ? 255 : 0)) {
97+
if (recursionDepth < WorldConfig.nestedContainers()) {
9898
out.addAll(getContainers(
9999
getContainerInventory(stack, player),
100100
player,

src/main/java/de/rubixdev/enchantedshulkers/config/ConfigCommand.java

+31-11
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import static net.minecraft.server.command.CommandManager.literal;
66

77
import com.mojang.brigadier.CommandDispatcher;
8-
import com.mojang.brigadier.arguments.BoolArgumentType;
98
import com.mojang.brigadier.arguments.StringArgumentType;
109
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
1110
import com.mojang.brigadier.context.CommandContext;
@@ -16,6 +15,8 @@
1615
import net.minecraft.text.*;
1716
import net.minecraft.util.Formatting;
1817

18+
import java.lang.reflect.Field;
19+
1920
public class ConfigCommand {
2021
public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
2122
LiteralArgumentBuilder<ServerCommandSource> literalArgumentBuilder =
@@ -24,7 +25,8 @@ public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
2425
.then(argument("option", StringArgumentType.word())
2526
.suggests((context, builder) -> suggestMatching(WorldConfig.getOptions().sorted(), builder))
2627
.executes(ConfigCommand::displayOptionMenu)
27-
.then(argument("value", BoolArgumentType.bool())
28+
.then(argument("value", StringArgumentType.greedyString())
29+
.suggests((context, builder) -> suggestMatching(suggestions(context), builder))
2830
.executes(ConfigCommand::setOption)));
2931
dispatcher.register(literalArgumentBuilder);
3032
}
@@ -49,6 +51,18 @@ private static String optionFromContext(CommandContext<ServerCommandSource> cont
4951
return optionName;
5052
}
5153

54+
private static String[] suggestions(CommandContext<ServerCommandSource> context) throws CommandSyntaxException {
55+
return suggestions(optionFromContext(context));
56+
}
57+
58+
private static String[] suggestions(String option) {
59+
Field field = WorldConfig.getField(option);
60+
if (field.getType() == boolean.class || Boolean.class.isAssignableFrom(field.getType())) return new String[]{"true", "false"};
61+
IntOption intOption = field.getAnnotation(IntOption.class);
62+
if (intOption != null) return intOption.suggestions();
63+
return new String[]{String.valueOf(WorldConfig.getOptionDefault(option))};
64+
}
65+
5266
private static int listAllOptions(CommandContext<ServerCommandSource> context) {
5367
sendFeedback(context.getSource(), Text.empty());
5468
sendFeedback(
@@ -63,8 +77,9 @@ private static int listAllOptions(CommandContext<ServerCommandSource> context) {
6377
.setStyle(Style.EMPTY
6478
.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/" + Mod.MOD_ID + " " + option))
6579
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.translatable(Mod.MOD_ID + ".options." + option + ".desc").setStyle(Style.EMPTY.withColor(Formatting.YELLOW))))));
66-
text.append(makeSetOptionButton(option, "true", true));
67-
text.append(makeSetOptionButton(option, "false", true));
80+
for (String suggestion : suggestions(option)) {
81+
text.append(makeSetOptionButton(option, suggestion, true));
82+
}
6883
sendFeedback(
6984
context.getSource(),
7085
text
@@ -77,7 +92,7 @@ private static int listAllOptions(CommandContext<ServerCommandSource> context) {
7792
private static Text makeSetOptionButton(String option, String value, boolean brackets) {
7893
MutableText text = Text.literal((brackets ? "[" : "") + value + (brackets ? "]" : ""));
7994
Style style = Style.EMPTY;
80-
boolean optionIsDefault = WorldConfig.getOption(option) == WorldConfig.getOptionDefault(option);
95+
boolean optionIsDefault = WorldConfig.getOption(option).equals(WorldConfig.getOptionDefault(option));
8196
boolean valueIsOptionDefault = String.valueOf(WorldConfig.getOptionDefault(option)).equalsIgnoreCase(value);
8297
boolean valueIsOptionCurrent = String.valueOf(WorldConfig.getOption(option)).equalsIgnoreCase(value);
8398
if (optionIsDefault) {
@@ -113,11 +128,12 @@ private static int displayOptionMenu(CommandContext<ServerCommandSource> context
113128
sendFeedback(context.getSource(), Text.empty());
114129
sendFeedback(context.getSource(), Text.literal(option).setStyle(Style.EMPTY.withBold(true).withColor(Formatting.WHITE).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/" + Mod.MOD_ID + " " + option)).withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.translatable("commands." + Mod.MOD_ID + ".refresh").setStyle(Style.EMPTY.withColor(Formatting.GRAY))))));
115130
sendFeedback(context.getSource(), Text.translatable(Mod.MOD_ID + ".options." + option + ".desc").setStyle(Style.EMPTY.withColor(Formatting.GRAY)));
116-
sendFeedback(context.getSource(), Text.translatable("commands." + Mod.MOD_ID + ".current_value").append(Text.literal(WorldConfig.getOption(option) + (WorldConfig.getOption(option) == WorldConfig.getOptionDefault(option) ? " (default)" : " (modified)")).setStyle(Style.EMPTY.withColor(WorldConfig.getOption(option) ? Formatting.GREEN : Formatting.DARK_RED).withBold(true))));
131+
sendFeedback(context.getSource(), Text.translatable("commands." + Mod.MOD_ID + ".current_value").append(Text.literal(WorldConfig.getOption(option) + (WorldConfig.getOption(option).equals(WorldConfig.getOptionDefault(option)) ? " (default)" : " (modified)")).setStyle(Style.EMPTY.withColor(WorldConfig.getBooleanValue(option) ? Formatting.GREEN : Formatting.DARK_RED).withBold(true))));
117132

118133
MutableText optionsText = Text.literal("[").setStyle(Style.EMPTY.withColor(Formatting.YELLOW));
119-
optionsText.append(makeSetOptionButton(option, "true", false));
120-
optionsText.append(makeSetOptionButton(option, "false", false));
134+
for (String suggestion : suggestions(option)) {
135+
optionsText.append(makeSetOptionButton(option, suggestion, false));
136+
}
121137
optionsText.append(Text.literal(" ]"));
122138
sendFeedback(context.getSource(), Text.translatable("commands." + Mod.MOD_ID + ".options").append(optionsText));
123139

@@ -126,10 +142,14 @@ private static int displayOptionMenu(CommandContext<ServerCommandSource> context
126142

127143
private static int setOption(CommandContext<ServerCommandSource> context) throws CommandSyntaxException {
128144
String option = optionFromContext(context);
129-
boolean value = BoolArgumentType.getBool(context, "value");
145+
String value = StringArgumentType.getString(context, "value");
130146

131-
WorldConfig.setOption(option, value);
132-
sendFeedback(context.getSource(), Text.translatable("commands." + Mod.MOD_ID + ".set", option, String.valueOf(value)));
147+
try {
148+
WorldConfig.setOption(option, value);
149+
sendFeedback(context.getSource(), Text.translatable("commands." + Mod.MOD_ID + ".set", option, String.valueOf(value)));
150+
} catch (InvalidOptionValueException e) {
151+
context.getSource().sendError(e.getText());
152+
}
133153

134154
return 1;
135155
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package de.rubixdev.enchantedshulkers.config;
2+
3+
import java.lang.annotation.Retention;
4+
import java.lang.annotation.RetentionPolicy;
5+
6+
@Retention(RetentionPolicy.RUNTIME)
7+
public @interface IntOption {
8+
int min();
9+
int max();
10+
String[] suggestions();
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package de.rubixdev.enchantedshulkers.config;
2+
3+
import net.minecraft.text.Text;
4+
5+
public class InvalidOptionValueException extends Exception {
6+
private final Text text;
7+
8+
public InvalidOptionValueException(Text message) {
9+
super(message.getString());
10+
this.text = message;
11+
}
12+
13+
public Text getText() {
14+
return text;
15+
}
16+
}

0 commit comments

Comments
 (0)