From c96ce10cdcf75cf642101b00cc9572304d276851 Mon Sep 17 00:00:00 2001 From: Keuin Date: Sat, 16 Jan 2021 15:34:15 +0800 Subject: Add runtime configuration editing command `/omvm set `. The set is temporary and will not be modified in disk. --- gradle.properties | 2 +- .../keuin/ohmyvanillamc/OhMyVanillaMinecraft.java | 219 ++++++++++++++------- .../com/keuin/ohmyvanillamc/OmvmConfiguration.java | 80 -------- .../com/keuin/ohmyvanillamc/ReflectionUtils.java | 32 ++- .../config/ImmutableOmvmConfiguration.java | 45 +++++ .../ohmyvanillamc/config/OmvmConfiguration.java | 113 +++++++++++ .../mixin/Mc113809BambooBlockMixin.java | 1 - 7 files changed, 322 insertions(+), 170 deletions(-) delete mode 100644 src/main/java/com/keuin/ohmyvanillamc/OmvmConfiguration.java create mode 100644 src/main/java/com/keuin/ohmyvanillamc/config/ImmutableOmvmConfiguration.java create mode 100644 src/main/java/com/keuin/ohmyvanillamc/config/OmvmConfiguration.java diff --git a/gradle.properties b/gradle.properties index 6d6c014..fe31ad3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ minecraft_version=1.16.4 yarn_mappings=1.16.4+build.9 loader_version=0.11.0 # Mod Properties -mod_version=1.5.2 +mod_version=1.5.3 maven_group=com.keuin.omvm archives_base_name=oh-my-vanilla-mc # Dependencies diff --git a/src/main/java/com/keuin/ohmyvanillamc/OhMyVanillaMinecraft.java b/src/main/java/com/keuin/ohmyvanillamc/OhMyVanillaMinecraft.java index 76936fa..e64708d 100644 --- a/src/main/java/com/keuin/ohmyvanillamc/OhMyVanillaMinecraft.java +++ b/src/main/java/com/keuin/ohmyvanillamc/OhMyVanillaMinecraft.java @@ -3,88 +3,171 @@ package com.keuin.ohmyvanillamc; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonIOException; +import com.keuin.ohmyvanillamc.config.ImmutableOmvmConfiguration; +import com.keuin.ohmyvanillamc.config.OmvmConfiguration; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.SuggestionProvider; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.LiteralText; +import net.minecraft.text.Style; +import net.minecraft.util.Formatting; import java.io.*; import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.logging.Logger; +import java.util.stream.Stream; + +import static com.keuin.ohmyvanillamc.ReflectionUtils.getFieldName; +import static com.keuin.ohmyvanillamc.ReflectionUtils.setPrivateField; public class OhMyVanillaMinecraft implements ModInitializer { - private static final Logger LOGGER = Logger.getLogger("OhMyVanillaMinecraft"); - - private static OmvmConfiguration configuration = null; - private static final OmvmConfiguration defaultConfiguration = new OmvmConfiguration(); - - public static OmvmConfiguration getConfiguration() { - return configuration != null ? configuration : defaultConfiguration; - } - - @Override - public void onInitialize() { - // This code runs as soon as Minecraft is in a mod-load-ready state. - // However, some things (like resources) may still be uninitialized. - // Proceed with mild caution. - - LOGGER.info("Loading configuration..."); - - // load configuration - - final String fileName = "omvm.json"; - final File file = new File(fileName); - if (!file.exists()) { - LOGGER.info("Configuration file does not exist! Use default configuration."); - try (FileOutputStream fileOutputStream = new FileOutputStream(file)) { - final String jsonString = (new GsonBuilder().setPrettyPrinting().create()).toJson(defaultConfiguration); - try (OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream)) { - outputStreamWriter.write(jsonString); - } - } catch (FileNotFoundException e) { - LOGGER.severe("Cannot write default configuration to file `" + fileName + "`: " + e); - } catch (IOException e) { - LOGGER.severe("Failed to write default configuration to file `" + fileName + "`: " + e); - } - } else { - try (FileInputStream fileInputStream = new FileInputStream(file)) { - try (InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8)) { - try (BufferedReader reader = new BufferedReader(inputStreamReader)) { - configuration = (new Gson()).fromJson(reader, OmvmConfiguration.class); - } - } - } catch (IOException e) { - LOGGER.severe("Failed to read config file `" + fileName + "`: " + e); - } catch (JsonIOException e) { - LOGGER.severe("Failed to decode config json file `" + fileName + "`: " + e); - } - } - - if (configuration == null) { - configuration = defaultConfiguration; - } - - LOGGER.info("Configuration: \n==========\n" + configuration + "\n=========="); - - CommandRegistrationCallback.EVENT.register(new CommandRegistrationCallback() { - @Override - public void register(CommandDispatcher commandDispatcher, boolean b) { - commandDispatcher.register(CommandManager.literal("omvm").executes(new Command() { - @Override - public int run(CommandContext context) throws CommandSyntaxException { - String text = "OhMyVanillaMinecraft\n==========\n" + getConfiguration() + "\n=========="; - context.getSource().sendFeedback(new LiteralText(text), false); - return 1; // 1: success, -1: fail - } - })); - } - }); - - } + private static final Logger LOGGER = Logger.getLogger("OhMyVanillaMinecraft"); + + private static final OmvmConfiguration defaultConfiguration = + new ImmutableOmvmConfiguration(true, true, true, true, true, true); + private static OmvmConfiguration configuration = null; + + public static OmvmConfiguration getConfiguration() { + return configuration; + } + + @Override + public void onInitialize() { + // This code runs as soon as Minecraft is in a mod-load-ready state. + // However, some things (like resources) may still be uninitialized. + // Proceed with mild caution. + + LOGGER.info("Loading configuration..."); + + // load configuration + + final String fileName = "omvm.json"; + final File file = new File(fileName); + if (!file.exists()) { + LOGGER.info("Configuration file does not exist! Use default configuration."); + try (FileOutputStream fileOutputStream = new FileOutputStream(file)) { + final String jsonString = (new GsonBuilder().setPrettyPrinting().create()).toJson(defaultConfiguration); + try (OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream)) { + outputStreamWriter.write(jsonString); + } + } catch (FileNotFoundException e) { + LOGGER.severe("Cannot write default configuration to file `" + fileName + "`: " + e); + } catch (IOException e) { + LOGGER.severe("Failed to write default configuration to file `" + fileName + "`: " + e); + } + } else { + try (FileInputStream fileInputStream = new FileInputStream(file)) { + try (InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8)) { + try (BufferedReader reader = new BufferedReader(inputStreamReader)) { + configuration = (new Gson()).fromJson(reader, OmvmConfiguration.class); + } + } + } catch (IOException e) { + LOGGER.severe("Failed to read config file `" + fileName + "`: " + e); + } catch (JsonIOException e) { + LOGGER.severe("Failed to decode config json file `" + fileName + "`: " + e); + } + } + + if (configuration == null) { + configuration = new OmvmConfiguration(defaultConfiguration); + } + + LOGGER.info("Configuration: \n==========\n" + configuration + "\n=========="); + + CommandRegistrationCallback.EVENT.register(new CommandRegistrationCallback() { + @Override + public void register(CommandDispatcher commandDispatcher, boolean b) { + commandDispatcher.register(CommandManager.literal("omvm").executes(new Command() { + @Override + public int run(CommandContext context) throws CommandSyntaxException { + String text = "OhMyVanillaMinecraft\n==========\n" + getConfiguration() + "\n=========="; + context.getSource().sendFeedback(new LiteralText(text), false); + return 1; // 1: success, -1: fail + } + })); + } + }); + + + String[] keys = getFieldName(configuration); + final Set keySet = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(keys))); + + CommandRegistrationCallback.EVENT.register(new CommandRegistrationCallback() { + @Override + public void register(CommandDispatcher commandDispatcher, boolean b) { + commandDispatcher.register(CommandManager.literal("omvm") + .then(CommandManager.literal("set") + .then(CommandManager.argument("key", StringArgumentType.word()) + .suggests(new SuggestionProvider() { + @Override + public CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) throws CommandSyntaxException { + String remaining = builder.getRemaining().toLowerCase(Locale.ROOT); + keySet.stream().filter(key -> key.toLowerCase().startsWith(remaining)).forEach(builder::suggest); + return builder.buildFuture(); + } + }) + .then(CommandManager.argument("value", StringArgumentType.word()).suggests(new SuggestionProvider() { + @Override + public CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) throws CommandSyntaxException { + String remaining = builder.getRemaining().toLowerCase(Locale.ROOT); + Stream.of("true", "false").filter(key -> key.toLowerCase().startsWith(remaining)).forEach(builder::suggest); + return builder.buildFuture(); + } + }) + .executes(new Command() { + @Override + public int run(CommandContext context) throws CommandSyntaxException { + try { + String key = context.getArgument("key", String.class); + String value = context.getArgument("value", String.class); + + if (!keySet.contains(key)) { + StringBuilder sb = new StringBuilder(); + sb.append("Invalid key. Available keys:"); + keySet.forEach(k -> sb.append("\n- ").append(k)); + context.getSource().sendFeedback(new LiteralText(sb.toString()) + .setStyle(Style.EMPTY.withColor(Formatting.RED)), false); + return -1; + } + + if (!Arrays.asList("true", "false").contains(value)) { + context.getSource().sendFeedback(new LiteralText("Value must be `true` or `false`.") + .setStyle(Style.EMPTY.withColor(Formatting.RED)), false); + return -1; + } + + setPrivateField(configuration, key, Boolean.valueOf(value)); + context.getSource().sendFeedback( + new LiteralText("`" + key + "` has been temporarily set to `" + value + "`."), true + ); + + return 1; // 1: success, -1: fail + } catch (NoSuchFieldException | IllegalAccessException e) { + context.getSource().sendFeedback(new LiteralText("There is a bug. Tell trueKeuin.") + .setStyle(Style.EMPTY.withColor(Formatting.RED)), false); + return -1; + } + } + }) + ) + ))); + } + }); + + } + + } diff --git a/src/main/java/com/keuin/ohmyvanillamc/OmvmConfiguration.java b/src/main/java/com/keuin/ohmyvanillamc/OmvmConfiguration.java deleted file mode 100644 index b3d7b83..0000000 --- a/src/main/java/com/keuin/ohmyvanillamc/OmvmConfiguration.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.keuin.ohmyvanillamc; - -import java.util.Objects; - -public class OmvmConfiguration { - - private final boolean fixEntityTrackerEntrySpamming; - private final boolean disableFishSchooling; - private final boolean disablePhantomSpawning; - private final boolean disableWanderingTraderSpawning; - private final boolean reintroduceLlamaItemDuplicating; - private final boolean reintroduceZeroTickFarm; - - public OmvmConfiguration() { - this(true, false, false, false, false, false); - } - - public OmvmConfiguration(boolean fixEntityTrackerEntrySpamming, boolean disableFishSchooling, boolean disablePhantomSpawning, boolean disableWanderingTraderSpawning, boolean reintroduceLlamaItemDuplicating, boolean reintroduceZeroTickFarm) { - this.fixEntityTrackerEntrySpamming = fixEntityTrackerEntrySpamming; - this.disableFishSchooling = disableFishSchooling; - this.disablePhantomSpawning = disablePhantomSpawning; - this.disableWanderingTraderSpawning = disableWanderingTraderSpawning; - this.reintroduceLlamaItemDuplicating = reintroduceLlamaItemDuplicating; - this.reintroduceZeroTickFarm = reintroduceZeroTickFarm; - } - - public boolean isFixEntityTrackerEntrySpamming() { - return fixEntityTrackerEntrySpamming; - } - - public boolean isDisableFishSchooling() { - return disableFishSchooling; - } - - public boolean isDisablePhantomSpawning() { - return disablePhantomSpawning; - } - - public boolean isDisableWanderingTraderSpawning() { - return disableWanderingTraderSpawning; - } - - public boolean isReintroduceLlamaItemDuplicating() { - return reintroduceLlamaItemDuplicating; - } - - public boolean isReintroduceZeroTickFarm() { - return reintroduceZeroTickFarm; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - OmvmConfiguration that = (OmvmConfiguration) o; - return fixEntityTrackerEntrySpamming == that.fixEntityTrackerEntrySpamming && - disableFishSchooling == that.disableFishSchooling && - disablePhantomSpawning == that.disablePhantomSpawning && - disableWanderingTraderSpawning == that.disableWanderingTraderSpawning && - reintroduceLlamaItemDuplicating == that.reintroduceLlamaItemDuplicating && - reintroduceZeroTickFarm == that.reintroduceZeroTickFarm; - } - - @Override - public int hashCode() { - return Objects.hash(fixEntityTrackerEntrySpamming, disableFishSchooling, disablePhantomSpawning, disableWanderingTraderSpawning, reintroduceLlamaItemDuplicating, reintroduceZeroTickFarm); - } - - @Override - public String toString() { - String s = ""; - s += "(BugFix) Fix Entity Tracker Entry Spamming: " + fixEntityTrackerEntrySpamming + "\n"; - s += "(Optimization) Disable Fish Schooling: " + disableFishSchooling + "\n"; - s += "(Exotic Feature) Disable Phantom Spawning: " + disablePhantomSpawning + "\n"; - s += "(Exotic Feature) Disable Wandering Trader Spawning: " + disableWanderingTraderSpawning + "\n"; - s += "(Obsolete Vanilla Feature) Reintroduce Llama Item Duplicating: " + reintroduceLlamaItemDuplicating + "\n"; - s += "(Obsolete Vanilla Feature) Reintroduce 0-tick Plants Farm: " + reintroduceZeroTickFarm; - return s; - } -} diff --git a/src/main/java/com/keuin/ohmyvanillamc/ReflectionUtils.java b/src/main/java/com/keuin/ohmyvanillamc/ReflectionUtils.java index 253c89d..a87632e 100644 --- a/src/main/java/com/keuin/ohmyvanillamc/ReflectionUtils.java +++ b/src/main/java/com/keuin/ohmyvanillamc/ReflectionUtils.java @@ -3,9 +3,10 @@ package com.keuin.ohmyvanillamc; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.Arrays; /** - * @Author 落叶飞翔的蜗牛 + * @Author 落叶飞翔的蜗牛 Keuin * @Date 2018/3/10 * @Description 常用反射函数 */ @@ -13,10 +14,6 @@ public final class ReflectionUtils { /** * 获取私有成员变量的值 - * - * @param instance - * @param filedName - * @return */ public static Object getPrivateField(Object instance, String filedName) throws NoSuchFieldException, IllegalAccessException { Field field = instance.getClass().getDeclaredField(filedName); @@ -26,12 +23,6 @@ public final class ReflectionUtils { /** * 设置私有成员的值 - * - * @param instance - * @param fieldName - * @param value - * @throws NoSuchFieldException - * @throws IllegalAccessException */ public static void setPrivateField(Object instance, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException { Field field = instance.getClass().getDeclaredField(fieldName); @@ -41,19 +32,20 @@ public final class ReflectionUtils { /** * 访问私有方法 - * - * @param instance - * @param methodName - * @param classes - * @param args - * @return - * @throws NoSuchMethodException - * @throws InvocationTargetException - * @throws IllegalAccessException */ public static Object invokePrivateMethod(Object instance, String methodName, Class[] classes, Object... args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Method method = instance.getClass().getDeclaredMethod(methodName, classes); method.setAccessible(true); return method.invoke(instance, args); } + + /** + * 获取所有成员变量的名字 + * + * @param o 要获取成员变量的对象实例 + * @return 所有成员变量名字数组 + */ + public static String[] getFieldName(Object o) { + return Arrays.stream(o.getClass().getDeclaredFields()).map(Field::getName).toArray(String[]::new); + } } \ No newline at end of file diff --git a/src/main/java/com/keuin/ohmyvanillamc/config/ImmutableOmvmConfiguration.java b/src/main/java/com/keuin/ohmyvanillamc/config/ImmutableOmvmConfiguration.java new file mode 100644 index 0000000..e5a34e1 --- /dev/null +++ b/src/main/java/com/keuin/ohmyvanillamc/config/ImmutableOmvmConfiguration.java @@ -0,0 +1,45 @@ +package com.keuin.ohmyvanillamc.config; + +public class ImmutableOmvmConfiguration extends OmvmConfiguration { + + public ImmutableOmvmConfiguration() { + } + + public ImmutableOmvmConfiguration(OmvmConfiguration omvmConfiguration) { + super(omvmConfiguration); + } + + public ImmutableOmvmConfiguration(boolean fixEntityTrackerEntrySpamming, boolean disableFishSchooling, boolean disablePhantomSpawning, boolean disableWanderingTraderSpawning, boolean reintroduceLlamaItemDuplicating, boolean reintroduceZeroTickFarm) { + super(fixEntityTrackerEntrySpamming, disableFishSchooling, disablePhantomSpawning, disableWanderingTraderSpawning, reintroduceLlamaItemDuplicating, reintroduceZeroTickFarm); + } + + @Override + public void setFixEntityTrackerEntrySpamming(boolean fixEntityTrackerEntrySpamming) { + throw new UnsupportedOperationException(); + } + + @Override + public void setDisableFishSchooling(boolean disableFishSchooling) { + throw new UnsupportedOperationException(); + } + + @Override + public void setDisablePhantomSpawning(boolean disablePhantomSpawning) { + throw new UnsupportedOperationException(); + } + + @Override + public void setDisableWanderingTraderSpawning(boolean disableWanderingTraderSpawning) { + throw new UnsupportedOperationException(); + } + + @Override + public void setReintroduceLlamaItemDuplicating(boolean reintroduceLlamaItemDuplicating) { + throw new UnsupportedOperationException(); + } + + @Override + public void setReintroduceZeroTickFarm(boolean reintroduceZeroTickFarm) { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/keuin/ohmyvanillamc/config/OmvmConfiguration.java b/src/main/java/com/keuin/ohmyvanillamc/config/OmvmConfiguration.java new file mode 100644 index 0000000..70ce1a7 --- /dev/null +++ b/src/main/java/com/keuin/ohmyvanillamc/config/OmvmConfiguration.java @@ -0,0 +1,113 @@ +package com.keuin.ohmyvanillamc.config; + +import java.util.Objects; + +public class OmvmConfiguration { + + private boolean fixEntityTrackerEntrySpamming; + private boolean disableFishSchooling; + private boolean disablePhantomSpawning; + private boolean disableWanderingTraderSpawning; + private boolean reintroduceLlamaItemDuplicating; + private boolean reintroduceZeroTickFarm; + + public OmvmConfiguration() { + this(true, false, false, false, false, false); + } + + public OmvmConfiguration(OmvmConfiguration omvmConfiguration) { + this.fixEntityTrackerEntrySpamming = omvmConfiguration.fixEntityTrackerEntrySpamming; + this.disableFishSchooling = omvmConfiguration.disableFishSchooling; + this.disablePhantomSpawning = omvmConfiguration.disablePhantomSpawning; + this.disableWanderingTraderSpawning = omvmConfiguration.disableWanderingTraderSpawning; + this.reintroduceLlamaItemDuplicating = omvmConfiguration.reintroduceLlamaItemDuplicating; + this.reintroduceZeroTickFarm = omvmConfiguration.reintroduceZeroTickFarm; + } + + public OmvmConfiguration(boolean fixEntityTrackerEntrySpamming, boolean disableFishSchooling, boolean disablePhantomSpawning, boolean disableWanderingTraderSpawning, boolean reintroduceLlamaItemDuplicating, boolean reintroduceZeroTickFarm) { + this.fixEntityTrackerEntrySpamming = fixEntityTrackerEntrySpamming; + this.disableFishSchooling = disableFishSchooling; + this.disablePhantomSpawning = disablePhantomSpawning; + this.disableWanderingTraderSpawning = disableWanderingTraderSpawning; + this.reintroduceLlamaItemDuplicating = reintroduceLlamaItemDuplicating; + this.reintroduceZeroTickFarm = reintroduceZeroTickFarm; + } + + public boolean isFixEntityTrackerEntrySpamming() { + return fixEntityTrackerEntrySpamming; + } + + public boolean isDisableFishSchooling() { + return disableFishSchooling; + } + + public boolean isDisablePhantomSpawning() { + return disablePhantomSpawning; + } + + public boolean isDisableWanderingTraderSpawning() { + return disableWanderingTraderSpawning; + } + + public boolean isReintroduceLlamaItemDuplicating() { + return reintroduceLlamaItemDuplicating; + } + + public boolean isReintroduceZeroTickFarm() { + return reintroduceZeroTickFarm; + } + + public void setFixEntityTrackerEntrySpamming(boolean fixEntityTrackerEntrySpamming) { + this.fixEntityTrackerEntrySpamming = fixEntityTrackerEntrySpamming; + } + + public void setDisableFishSchooling(boolean disableFishSchooling) { + this.disableFishSchooling = disableFishSchooling; + } + + public void setDisablePhantomSpawning(boolean disablePhantomSpawning) { + this.disablePhantomSpawning = disablePhantomSpawning; + } + + public void setDisableWanderingTraderSpawning(boolean disableWanderingTraderSpawning) { + this.disableWanderingTraderSpawning = disableWanderingTraderSpawning; + } + + public void setReintroduceLlamaItemDuplicating(boolean reintroduceLlamaItemDuplicating) { + this.reintroduceLlamaItemDuplicating = reintroduceLlamaItemDuplicating; + } + + public void setReintroduceZeroTickFarm(boolean reintroduceZeroTickFarm) { + this.reintroduceZeroTickFarm = reintroduceZeroTickFarm; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + OmvmConfiguration that = (OmvmConfiguration) o; + return fixEntityTrackerEntrySpamming == that.fixEntityTrackerEntrySpamming && + disableFishSchooling == that.disableFishSchooling && + disablePhantomSpawning == that.disablePhantomSpawning && + disableWanderingTraderSpawning == that.disableWanderingTraderSpawning && + reintroduceLlamaItemDuplicating == that.reintroduceLlamaItemDuplicating && + reintroduceZeroTickFarm == that.reintroduceZeroTickFarm; + } + + @Override + public int hashCode() { + return Objects.hash(fixEntityTrackerEntrySpamming, disableFishSchooling, disablePhantomSpawning, disableWanderingTraderSpawning, reintroduceLlamaItemDuplicating, reintroduceZeroTickFarm); + } + + @Override + public String toString() { + String s = ""; + s += "(BugFix) Fix Entity Tracker Entry Spamming: " + fixEntityTrackerEntrySpamming + "\n"; + s += "(Optimization) Disable Fish Schooling: " + disableFishSchooling + "\n"; + s += "(Exotic Feature) Disable Phantom Spawning: " + disablePhantomSpawning + "\n"; + s += "(Exotic Feature) Disable Wandering Trader Spawning: " + disableWanderingTraderSpawning + "\n"; + s += "(Obsolete Vanilla Feature) Reintroduce Llama Item Duplicating: " + reintroduceLlamaItemDuplicating + "\n"; + s += "(Obsolete Vanilla Feature) Reintroduce 0-tick Plants Farm: " + reintroduceZeroTickFarm; + return s; + } +} diff --git a/src/main/java/com/keuin/ohmyvanillamc/mixin/Mc113809BambooBlockMixin.java b/src/main/java/com/keuin/ohmyvanillamc/mixin/Mc113809BambooBlockMixin.java index 2e0e274..ef4b9c1 100644 --- a/src/main/java/com/keuin/ohmyvanillamc/mixin/Mc113809BambooBlockMixin.java +++ b/src/main/java/com/keuin/ohmyvanillamc/mixin/Mc113809BambooBlockMixin.java @@ -74,7 +74,6 @@ public abstract class Mc113809BambooBlockMixin extends Block { } else { realGrow(state, world, pos, random); } - } private void realGrow(BlockState state, ServerWorld world, BlockPos pos, Random random) { -- cgit v1.2.3