From 90fb708739f8974f325befad8d0499b8464a4dde Mon Sep 17 00:00:00 2001 From: Not Flamgop <76978462+Flopgop@users.noreply.github.com> Date: Tue, 2 Jul 2024 15:59:38 -0700 Subject: [PATCH] Autogenerate Feature Flags (#2201) * Autogenerate Feature Flags (Won't work until MinestomDataGen 1.21-rev2 is released with datagen changes.) * Rewrite feature flag auto-generation, add example in demo. * Update data gen * Remove dead code and fix access modifier on FeatureFlagImpl --- .../java/net/minestom/codegen/Generators.java | 1 + .../java/net/minestom/demo/PlayerInit.java | 5 +++ gradle/libs.versions.toml | 2 +- .../net/minestom/server/FeatureFlags.java | 13 ++++++++ .../java/net/minestom/server/FeatureFlag.java | 6 ++++ .../net/minestom/server/FeatureFlagImpl.java | 33 +++++++++++++++++++ .../player/AsyncPlayerConfigurationEvent.java | 15 +++++---- .../server/network/ConnectionManager.java | 4 ++- .../minestom/server/registry/Registry.java | 15 +++++++++ 9 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 src/autogenerated/java/net/minestom/server/FeatureFlags.java create mode 100644 src/main/java/net/minestom/server/FeatureFlag.java create mode 100644 src/main/java/net/minestom/server/FeatureFlagImpl.java diff --git a/code-generators/src/main/java/net/minestom/codegen/Generators.java b/code-generators/src/main/java/net/minestom/codegen/Generators.java index 0db7d9f81..deddd0e90 100644 --- a/code-generators/src/main/java/net/minestom/codegen/Generators.java +++ b/code-generators/src/main/java/net/minestom/codegen/Generators.java @@ -37,6 +37,7 @@ public class Generators { generator.generate(resource("sounds.json"), "net.minestom.server.sound", "SoundEvent", "BuiltinSoundEvent", "SoundEvents"); generator.generate(resource("custom_statistics.json"), "net.minestom.server.statistic", "StatisticType", "StatisticTypeImpl", "StatisticTypes"); generator.generate(resource("attributes.json"), "net.minestom.server.entity.attribute", "Attribute", "AttributeImpl", "Attributes"); + generator.generate(resource("feature_flags.json"), "net.minestom.server", "FeatureFlag", "FeatureFlagImpl", "FeatureFlags"); // Dynamic registries generator.generateKeys(resource("chat_types.json"), "net.minestom.server.message", "ChatType", "ChatTypes"); diff --git a/demo/src/main/java/net/minestom/demo/PlayerInit.java b/demo/src/main/java/net/minestom/demo/PlayerInit.java index 0b0cf2a34..d82add7d8 100644 --- a/demo/src/main/java/net/minestom/demo/PlayerInit.java +++ b/demo/src/main/java/net/minestom/demo/PlayerInit.java @@ -2,6 +2,7 @@ package net.minestom.demo; import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.Component; +import net.minestom.server.FeatureFlag; import net.minestom.server.MinecraftServer; import net.minestom.server.advancements.FrameType; import net.minestom.server.advancements.notifications.Notification; @@ -103,6 +104,10 @@ public class PlayerInit { .addListener(AsyncPlayerConfigurationEvent.class, event -> { final Player player = event.getPlayer(); + // Show off adding and removing feature flags + event.addFeatureFlag(FeatureFlag.BUNDLE); + event.removeFeatureFlag(FeatureFlag.TRADE_REBALANCE); // not enabled by default, just removed for demonstration + var instances = MinecraftServer.getInstanceManager().getInstances(); Instance instance = instances.stream().skip(new Random().nextInt(instances.size())).findFirst().orElse(null); event.setSpawningInstance(instance); diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1fe273530..3001da3cf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ metadata.format.version = "1.1" [versions] # Important dependencies -data = "1.21" +data = "1.21-rv2" adventure = "4.17.0" jetbrainsAnnotations = "23.0.0" slf4j = "2.0.7" diff --git a/src/autogenerated/java/net/minestom/server/FeatureFlags.java b/src/autogenerated/java/net/minestom/server/FeatureFlags.java new file mode 100644 index 000000000..8122bd62b --- /dev/null +++ b/src/autogenerated/java/net/minestom/server/FeatureFlags.java @@ -0,0 +1,13 @@ +package net.minestom.server; + +/** + * Code autogenerated, do not edit! + */ +@SuppressWarnings("unused") +interface FeatureFlags { + FeatureFlag BUNDLE = FeatureFlagImpl.get("minecraft:bundle"); + + FeatureFlag VANILLA = FeatureFlagImpl.get("minecraft:vanilla"); + + FeatureFlag TRADE_REBALANCE = FeatureFlagImpl.get("minecraft:trade_rebalance"); +} diff --git a/src/main/java/net/minestom/server/FeatureFlag.java b/src/main/java/net/minestom/server/FeatureFlag.java new file mode 100644 index 000000000..811a545fe --- /dev/null +++ b/src/main/java/net/minestom/server/FeatureFlag.java @@ -0,0 +1,6 @@ +package net.minestom.server; + +import net.minestom.server.registry.StaticProtocolObject; + +public sealed interface FeatureFlag extends StaticProtocolObject, FeatureFlags permits FeatureFlagImpl { +} diff --git a/src/main/java/net/minestom/server/FeatureFlagImpl.java b/src/main/java/net/minestom/server/FeatureFlagImpl.java new file mode 100644 index 000000000..94fa2ac6d --- /dev/null +++ b/src/main/java/net/minestom/server/FeatureFlagImpl.java @@ -0,0 +1,33 @@ +package net.minestom.server; + +import net.minestom.server.registry.Registry; +import net.minestom.server.utils.NamespaceID; +import org.jetbrains.annotations.NotNull; + +record FeatureFlagImpl(@NotNull Registry.FeatureFlagEntry registry) implements FeatureFlag { + + private static final Registry.Container CONTAINER = Registry.createStaticContainer(Registry.Resource.FEATURE_FLAGS, + (namespace, properties) -> new FeatureFlagImpl(Registry.featureFlag(namespace, properties))); + + static FeatureFlag get(@NotNull String namespace) { + return CONTAINER.get(namespace); + } + + static FeatureFlag getSafe(@NotNull String namespace) { + return CONTAINER.getSafe(namespace); + } + + static FeatureFlag getId(int id) { + return CONTAINER.getId(id); + } + + @Override + public @NotNull NamespaceID namespace() { + return registry.namespace(); + } + + @Override + public int id() { + return registry.id(); + } +} diff --git a/src/main/java/net/minestom/server/event/player/AsyncPlayerConfigurationEvent.java b/src/main/java/net/minestom/server/event/player/AsyncPlayerConfigurationEvent.java index 3aa52f177..0747dc78c 100644 --- a/src/main/java/net/minestom/server/event/player/AsyncPlayerConfigurationEvent.java +++ b/src/main/java/net/minestom/server/event/player/AsyncPlayerConfigurationEvent.java @@ -2,12 +2,12 @@ package net.minestom.server.event.player; import it.unimi.dsi.fastutil.objects.ObjectArraySet; import it.unimi.dsi.fastutil.objects.ObjectSets; +import net.minestom.server.FeatureFlag; import net.minestom.server.entity.Player; import net.minestom.server.event.trait.PlayerEvent; import net.minestom.server.instance.Instance; import net.minestom.server.network.packet.server.configuration.ResetChatPacket; import net.minestom.server.network.packet.server.configuration.UpdateEnabledFeaturesPacket; -import net.minestom.server.utils.NamespaceID; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -26,7 +26,7 @@ public class AsyncPlayerConfigurationEvent implements PlayerEvent { private final Player player; private final boolean isFirstConfig; - private final ObjectArraySet featureFlags = new ObjectArraySet<>(); + private final ObjectArraySet featureFlags = new ObjectArraySet<>(); private boolean hardcore; private boolean clearChat; private boolean sendRegistryData; @@ -36,7 +36,7 @@ public class AsyncPlayerConfigurationEvent implements PlayerEvent { this.player = player; this.isFirstConfig = isFirstConfig; - this.featureFlags.add(NamespaceID.from("minecraft:vanilla")); // Vanilla feature-set, without this you get nothing at all. Kinda wacky! + this.featureFlags.add(FeatureFlag.VANILLA); // Vanilla feature-set, without this you get nothing at all. Kinda wacky! this.hardcore = false; this.clearChat = false; @@ -71,8 +71,9 @@ public class AsyncPlayerConfigurationEvent implements PlayerEvent { * @param feature A minecraft feature flag * * @see UpdateEnabledFeaturesPacket + * @see net.minestom.server.FeatureFlag */ - public void addFeatureFlag(@NotNull NamespaceID feature) { + public void addFeatureFlag(@NotNull FeatureFlag feature) { this.featureFlags.add(feature); } @@ -84,8 +85,9 @@ public class AsyncPlayerConfigurationEvent implements PlayerEvent { * @return if the feature specified existed prior to being removed * * @see UpdateEnabledFeaturesPacket + * @see net.minestom.server.FeatureFlag */ - public boolean removeFeatureFlag(@NotNull NamespaceID feature) { + public boolean removeFeatureFlag(@NotNull FeatureFlag feature) { return this.featureFlags.remove(feature); // Should this have sanity checking to see if the feature was actually contained in the list? } @@ -95,8 +97,9 @@ public class AsyncPlayerConfigurationEvent implements PlayerEvent { * @return An unmodifiable set of feature flags * * @see UpdateEnabledFeaturesPacket + * @see net.minestom.server.FeatureFlag */ - public @NotNull Set getFeatureFlags() { + public @NotNull Set getFeatureFlags() { return ObjectSets.unmodifiable(this.featureFlags); } diff --git a/src/main/java/net/minestom/server/network/ConnectionManager.java b/src/main/java/net/minestom/server/network/ConnectionManager.java index 6aeb78110..02200cb8e 100644 --- a/src/main/java/net/minestom/server/network/ConnectionManager.java +++ b/src/main/java/net/minestom/server/network/ConnectionManager.java @@ -24,6 +24,7 @@ import net.minestom.server.network.packet.server.play.StartConfigurationPacket; import net.minestom.server.network.player.PlayerConnection; import net.minestom.server.network.player.PlayerSocketConnection; import net.minestom.server.network.plugin.LoginPluginMessageProcessor; +import net.minestom.server.registry.StaticProtocolObject; import net.minestom.server.utils.StringUtils; import net.minestom.server.utils.async.AsyncUtils; import net.minestom.server.utils.debug.DebugUtils; @@ -37,6 +38,7 @@ import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.*; import java.util.function.Function; +import java.util.stream.Collectors; /** * Manages the connected clients. @@ -278,7 +280,7 @@ public final class ConnectionManager { EventDispatcher.call(event); if (!player.isOnline()) return; // Player was kicked during config. - player.sendPacket(new UpdateEnabledFeaturesPacket(event.getFeatureFlags())); // send player features that were enabled or disabled during async config event + player.sendPacket(new UpdateEnabledFeaturesPacket(event.getFeatureFlags().stream().map(StaticProtocolObject::namespace).collect(Collectors.toSet()))); // send player features that were enabled or disabled during async config event final Instance spawningInstance = event.getSpawningInstance(); Check.notNull(spawningInstance, "You need to specify a spawning instance in the AsyncPlayerConfigurationEvent"); diff --git a/src/main/java/net/minestom/server/registry/Registry.java b/src/main/java/net/minestom/server/registry/Registry.java index 007a9a94b..8093e7a87 100644 --- a/src/main/java/net/minestom/server/registry/Registry.java +++ b/src/main/java/net/minestom/server/registry/Registry.java @@ -70,6 +70,11 @@ public final class Registry { return new EntityEntry(namespace, main, null); } + @ApiStatus.Internal + public static FeatureFlagEntry featureFlag(String namespace, @NotNull Properties main) { + return new FeatureFlagEntry(namespace, main, null); + } + @ApiStatus.Internal public static PotionEffectEntry potionEffect(String namespace, @NotNull Properties main) { return new PotionEffectEntry(namespace, main, null); @@ -207,6 +212,7 @@ public final class Registry { BLOCKS("blocks.json"), ITEMS("items.json"), ENTITIES("entities.json"), + FEATURE_FLAGS("feature_flags.json"), SOUNDS("sounds.json"), COMMAND_ARGUMENTS("command_arguments.json"), STATISTICS("custom_statistics.json"), @@ -708,6 +714,15 @@ public final class Registry { } } + public record FeatureFlagEntry(NamespaceID namespace, int id, Properties custom) implements Entry { + public FeatureFlagEntry(String namespace, Properties main, Properties custom) { + this(NamespaceID.from(namespace), + main.getInt("id"), + null + ); + } + } + public record DamageTypeEntry(NamespaceID namespace, float exhaustion, String messageId, String scaling,