From 0fbd5317a46a3d4ef462b011905fa813aaabd3fd Mon Sep 17 00:00:00 2001 From: violetc <58360096+s-yh-china@users.noreply.github.com> Date: Wed, 19 Mar 2025 10:49:35 +0800 Subject: [PATCH] Configurable force peaceful mode switch type list (#423) --- gradle.properties | 2 +- .../0073-Force-peaceful-mode-switch.patch | 6 +- .../org/leavesmc/leaves/LeavesConfig.java | 43 +++++++-- .../leaves/config/AutoConfigTransformer.java | 10 -- .../leaves/config/AutoConfigValidator.java | 7 +- .../leaves/config/ConfigConverter.java | 2 - .../leaves/config/ConfigValidatorImpl.java | 93 ++++++++++++++----- .../leaves/config/GlobalConfigManager.java | 6 +- .../leaves/config/VerifiedConfig.java | 5 +- .../leaves/config/VerifiedRemovedConfig.java | 4 +- .../util/ForcePeacefulModeSwitchType.java | 61 ++++++++++++ 11 files changed, 177 insertions(+), 62 deletions(-) create mode 100644 leaves-server/src/main/java/org/leavesmc/leaves/util/ForcePeacefulModeSwitchType.java diff --git a/gradle.properties b/gradle.properties index a6c1cb3f..9c9b7d54 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ group=org.leavesmc.leaves version=1.21.4-R0.1-SNAPSHOT mcVersion=1.21.4 paperRef=bb1beda67bfd94632815acc8ac5d68f5a8e3e410 -preVersion=true +preVersion=false org.gradle.jvmargs=-Xmx2G org.gradle.caching=true org.gradle.parallel=true diff --git a/leaves-server/minecraft-patches/features/0073-Force-peaceful-mode-switch.patch b/leaves-server/minecraft-patches/features/0073-Force-peaceful-mode-switch.patch index 2267464b..44987584 100644 --- a/leaves-server/minecraft-patches/features/0073-Force-peaceful-mode-switch.patch +++ b/leaves-server/minecraft-patches/features/0073-Force-peaceful-mode-switch.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Force peaceful mode switch diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index 6540b2d6a1062d883811ce240c49d30d1925b291..d9e7c31748cdc1c9438cfcdd66468fd7aa9fc102 100644 +index 6540b2d6a1062d883811ce240c49d30d1925b291..67f7a71c70095dccd5a9f1a17a422c2d1854f8da 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java @@ -181,6 +181,12 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon @@ -13,9 +13,9 @@ index 6540b2d6a1062d883811ce240c49d30d1925b291..d9e7c31748cdc1c9438cfcdd66468fd7 // Paper end - chunk tick iteration optimisations + // Leaves start - peaceful mode switch -+ public int peacefulModeSwitchTick = org.leavesmc.leaves.LeavesConfig.modify.forcePeacefulMode; ++ public int peacefulModeSwitchTick = org.leavesmc.leaves.LeavesConfig.modify.peacefulModeSwitch.tick; ++ public Set> peacefulModeSwitchEntityTypes = org.leavesmc.leaves.LeavesConfig.modify.peacefulModeSwitch.classTypes; + public int peacefulModeSwitchCount = -1; -+ private final List> peacefulModeSwitchEntityTypes = List.of(net.minecraft.world.entity.boss.wither.WitherBoss.class, net.minecraft.world.entity.monster.Shulker.class, net.minecraft.world.entity.monster.warden.Warden.class, net.minecraft.world.entity.monster.Blaze.class); + // Leaves end - peaceful mode switch + diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/LeavesConfig.java b/leaves-server/src/main/java/org/leavesmc/leaves/LeavesConfig.java index 7a3d19c8..f672f2ff 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/LeavesConfig.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/LeavesConfig.java @@ -4,6 +4,7 @@ import com.destroystokyo.paper.util.SneakyThrow; import io.papermc.paper.configuration.GlobalConfiguration; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; import org.bukkit.command.Command; import org.bukkit.configuration.file.YamlConfiguration; import org.jetbrains.annotations.NotNull; @@ -24,14 +25,18 @@ import org.leavesmc.leaves.protocol.CarpetServerProtocol.CarpetRules; import org.leavesmc.leaves.protocol.bladeren.BladerenProtocol.LeavesFeature; import org.leavesmc.leaves.protocol.bladeren.BladerenProtocol.LeavesFeatureSet; import org.leavesmc.leaves.region.RegionFileFormat; +import org.leavesmc.leaves.util.ForcePeacefulModeSwitchType; import org.leavesmc.leaves.util.MathUtils; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Random; +import java.util.Set; public final class LeavesConfig { @@ -531,14 +536,38 @@ public final class LeavesConfig { @GlobalConfig("fast-resume") public boolean fastResume = false; - @GlobalConfig(value = "force-peaceful-mode", validator = ForcePeacefulModeValidator.class) - public int forcePeacefulMode = -1; + public ForcePeacefulModeSwitchConfig peacefulModeSwitch = new ForcePeacefulModeSwitchConfig(); - private static class ForcePeacefulModeValidator extends IntConfigValidator { - @Override - public void verify(Integer old, Integer value) throws IllegalArgumentException { - for (ServerLevel level : MinecraftServer.getServer().getAllLevels()) { - level.chunkSource.peacefulModeSwitchTick = value; + @GlobalConfigCategory("force-peaceful-mode-switch") + public static class ForcePeacefulModeSwitchConfig { + @RemovedConfig(name = "force-peaceful-mode", category = "modify", transform = true) + @GlobalConfig(value = "tick", validator = TickValidator.class) + public int tick = -1; + + private static class TickValidator extends IntConfigValidator { + @Override + public void verify(Integer old, Integer value) throws IllegalArgumentException { + for (ServerLevel level : MinecraftServer.getServer().getAllLevels()) { + level.chunkSource.peacefulModeSwitchTick = value; + } + } + } + + @GlobalConfig(value = "types", validator = TypeValidator.class) + public List types = List.of(ForcePeacefulModeSwitchType.BLAZE, ForcePeacefulModeSwitchType.WITHER, ForcePeacefulModeSwitchType.SHULKER, ForcePeacefulModeSwitchType.WARDEN); + public Set> classTypes = new HashSet<>(); + + private static class TypeValidator extends ListConfigValidator.ENUM { + @Override + public void verify(List old, @NotNull List value) throws IllegalArgumentException { + Set> classes = new HashSet<>(); + for (ForcePeacefulModeSwitchType type : value) { + classes.add(type.getEntityClass()); + } + LeavesConfig.modify.peacefulModeSwitch.classTypes = classes; + for (ServerLevel level : MinecraftServer.getServer().getAllLevels()) { + level.chunkSource.peacefulModeSwitchEntityTypes = classes; + } } } } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/config/AutoConfigTransformer.java b/leaves-server/src/main/java/org/leavesmc/leaves/config/AutoConfigTransformer.java index 03e9d973..6d70790c 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/config/AutoConfigTransformer.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/config/AutoConfigTransformer.java @@ -23,11 +23,6 @@ public class AutoConfigTransformer implements ConfigTransformer throw new UnsupportedOperationException("Not supported yet."); } - @Override - public Class getFieldClass() { - throw new UnsupportedOperationException("Not supported yet."); - } - @SuppressWarnings({"unchecked", "rawtypes"}) public static class SimpleConfigTransformer implements ConfigTransformer { @@ -56,10 +51,5 @@ public class AutoConfigTransformer implements ConfigTransformer public Object saveConvert(Object value) { return validator.saveConvert(value); } - - @Override - public Class getFieldClass() { - return validator.getFieldClass(); - } } } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/config/AutoConfigValidator.java b/leaves-server/src/main/java/org/leavesmc/leaves/config/AutoConfigValidator.java index 679ec09d..1c4d4a7c 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/config/AutoConfigValidator.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/config/AutoConfigValidator.java @@ -42,6 +42,8 @@ public final class AutoConfigValidator implements ConfigValidator { if (typeArgs.length > 0 && typeArgs[0] instanceof Class genericClass) { if (genericClass.equals(String.class)) { return new ConfigValidatorImpl.ListConfigValidator.STRING(); + } else if (genericClass.isEnum()) { + return new ConfigValidatorImpl.ListConfigValidator.ENUM<>((Class) genericClass); } throw new IllegalArgumentException("List type " + genericClass.getTypeName() + " is not supported."); } @@ -60,9 +62,4 @@ public final class AutoConfigValidator implements ConfigValidator { public Object stringConvert(String value) throws IllegalArgumentException { throw new UnsupportedOperationException("Not supported yet."); } - - @Override - public Class getFieldClass() { - throw new UnsupportedOperationException("Not supported yet."); - } } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/config/ConfigConverter.java b/leaves-server/src/main/java/org/leavesmc/leaves/config/ConfigConverter.java index b4aba30c..43afb42c 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/config/ConfigConverter.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/config/ConfigConverter.java @@ -16,6 +16,4 @@ public interface ConfigConverter { default Object saveConvert(E value) { return value; } - - Class getFieldClass(); } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/config/ConfigValidatorImpl.java b/leaves-server/src/main/java/org/leavesmc/leaves/config/ConfigValidatorImpl.java index 10dc070b..16ed55ce 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/config/ConfigValidatorImpl.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/config/ConfigValidatorImpl.java @@ -7,29 +7,12 @@ import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.function.Function; +import java.util.stream.Collectors; public abstract class ConfigValidatorImpl implements ConfigValidator { - protected Class fieldClass; - - @SuppressWarnings("unchecked") - public ConfigValidatorImpl() { - Type superClass = getClass().getGenericSuperclass(); - if (superClass instanceof ParameterizedType) { - Type[] actualTypeArguments = ((ParameterizedType) superClass).getActualTypeArguments(); - if (actualTypeArguments[0] instanceof Class) { - this.fieldClass = (Class) actualTypeArguments[0]; - } - } - } - - @Override - public Class getFieldClass() { - return fieldClass; - } - public static class BooleanConfigValidator extends ConfigValidatorImpl { - @Override public Boolean stringConvert(String value) throws IllegalArgumentException { return Boolean.parseBoolean(value); @@ -63,21 +46,68 @@ public abstract class ConfigValidatorImpl implements ConfigValidator { } public abstract static class ListConfigValidator extends ConfigValidatorImpl> { + public static class STRING extends ListConfigValidator { + public STRING() { + super(new StringConfigValidator()); + } + } + + public static class ENUM> extends ListConfigValidator { + public ENUM() { + super(null); + this.elementValidator = new EnumConfigValidator(getTypeArgument(getClass(), ENUM.class, Class::isEnum)); + } + + public ENUM(@NotNull Class enumClass) { + super(new EnumConfigValidator<>(enumClass)); + } + } + + protected ConfigValidator elementValidator; + + public ListConfigValidator(ConfigValidator elementValidator) { + this.elementValidator = elementValidator; + } + + @Override + public List loadConvert(Object value) throws IllegalArgumentException { + if (elementValidator == null) { + throw new IllegalArgumentException("element validator is null"); + } + if (value instanceof List list) { + return list.stream().map(elementValidator::loadConvert).collect(Collectors.toList()); + } else { + throw new IllegalArgumentException("value is not a list"); + } + } + + @Override + public Object saveConvert(List value) { + if (elementValidator == null) { + throw new IllegalArgumentException("element validator is null"); + } + return value.stream().map(elementValidator::saveConvert).collect(Collectors.toList()); } @Override public List stringConvert(String value) throws IllegalArgumentException { throw new IllegalArgumentException("not support"); // TODO } + + @Override + public List valueSuggest() { + return List.of(""); + } } public static class EnumConfigValidator> extends ConfigValidatorImpl { + protected Class enumClass; private final List enumValues; public EnumConfigValidator(@NotNull Class enumClass) { - this.fieldClass = enumClass; + this.enumClass = enumClass; this.enumValues = new ArrayList<>() {{ for (E e : enumClass.getEnumConstants()) { add(e.name().toLowerCase(Locale.ROOT)); @@ -86,8 +116,9 @@ public abstract class ConfigValidatorImpl implements ConfigValidator { } public EnumConfigValidator() { + this.enumClass = getTypeArgument(getClass(), EnumConfigValidator.class, Class::isEnum); this.enumValues = new ArrayList<>() {{ - for (E e : fieldClass.getEnumConstants()) { + for (E e : enumClass.getEnumConstants()) { add(e.name().toLowerCase(Locale.ROOT)); } }}; @@ -95,7 +126,7 @@ public abstract class ConfigValidatorImpl implements ConfigValidator { @Override public E stringConvert(@NotNull String value) throws IllegalArgumentException { - return Enum.valueOf(getFieldClass(), value.toUpperCase(Locale.ROOT)); + return Enum.valueOf(enumClass, value.toUpperCase(Locale.ROOT)); } @Override @@ -113,4 +144,22 @@ public abstract class ConfigValidatorImpl implements ConfigValidator { return enumValues; } } + + @SuppressWarnings("unchecked") + private static Class getTypeArgument(Class startClass, Class rawType, Function, Boolean> check) { + Type currentClass = startClass; + while (currentClass instanceof Class clazz) { + Type genericSuperclass = clazz.getGenericSuperclass(); + if (genericSuperclass instanceof ParameterizedType parameterizedType) { + if (rawType.equals(parameterizedType.getRawType())) { + Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); + if (actualTypeArguments.length > 0 && actualTypeArguments[0] instanceof Class parameterizedClass && (check == null || check.apply(parameterizedClass))) { + return (Class) parameterizedClass; + } + } + } + currentClass = genericSuperclass; + } + throw new IllegalArgumentException("Can't find type argument of " + startClass.getName() + " for " + rawType.getName()); + } } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/config/GlobalConfigManager.java b/leaves-server/src/main/java/org/leavesmc/leaves/config/GlobalConfigManager.java index 968ee856..171087a8 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/config/GlobalConfigManager.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/config/GlobalConfigManager.java @@ -103,12 +103,8 @@ public class GlobalConfigManager { throw new IllegalArgumentException("?"); } - if (savedValue.getClass() != validator.getFieldClass()) { - savedValue = validator.loadConvert(savedValue); - } - + savedValue = validator.loadConvert(savedValue); validator.verify(null, savedValue); - field.set(upstreamField, savedValue); } catch (IllegalArgumentException | ClassCastException e) { LeavesConfig.config.set(path, defValue); diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/config/VerifiedConfig.java b/leaves-server/src/main/java/org/leavesmc/leaves/config/VerifiedConfig.java index 7af4b31c..6cf7ee2a 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/config/VerifiedConfig.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/config/VerifiedConfig.java @@ -48,10 +48,7 @@ public record VerifiedConfig(ConfigValidator validator, boolean Object savedValue = LeavesConfig.config.get(path); try { if (savedValue != null) { - if (validator.getFieldClass() != savedValue.getClass()) { - savedValue = validator.loadConvert(savedValue); - } - + savedValue = validator.loadConvert(savedValue); if (!savedValue.equals(value)) { return value.toString() + "(" + savedValue + " after restart)"; } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/config/VerifiedRemovedConfig.java b/leaves-server/src/main/java/org/leavesmc/leaves/config/VerifiedRemovedConfig.java index bc264808..7b69e4de 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/config/VerifiedRemovedConfig.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/config/VerifiedRemovedConfig.java @@ -16,9 +16,7 @@ public record VerifiedRemovedConfig(ConfigTransformer entityClass; + + ForcePeacefulModeSwitchType(Class entityClass) { + this.entityClass = entityClass; + } + + public Class getEntityClass() { + return entityClass; + } +}