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 3ac9a26e5..d251b5dec 100644 --- a/code-generators/src/main/java/net/minestom/codegen/Generators.java +++ b/code-generators/src/main/java/net/minestom/codegen/Generators.java @@ -52,6 +52,7 @@ public class Generators { 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"); generator.generate(resource("villager_professions.json"), "net.minestom.server.entity", "VillagerProfession", "VillagerProfessionImpl", "VillagerProfessions"); + generator.generate(resource("game_events.json"), "net.minestom.server.game", "GameEvent", "GameEventImpl", "GameEvents"); // Dynamic registries diff --git a/src/autogenerated/java/net/minestom/server/game/GameEvents.java b/src/autogenerated/java/net/minestom/server/game/GameEvents.java new file mode 100644 index 000000000..44e09b862 --- /dev/null +++ b/src/autogenerated/java/net/minestom/server/game/GameEvents.java @@ -0,0 +1,127 @@ +package net.minestom.server.game; + +/** + * Code autogenerated, do not edit! + */ +@SuppressWarnings("unused") +interface GameEvents { + GameEvent BLOCK_ACTIVATE = GameEventImpl.get("minecraft:block_activate"); + + GameEvent BLOCK_ATTACH = GameEventImpl.get("minecraft:block_attach"); + + GameEvent BLOCK_CHANGE = GameEventImpl.get("minecraft:block_change"); + + GameEvent BLOCK_CLOSE = GameEventImpl.get("minecraft:block_close"); + + GameEvent BLOCK_DEACTIVATE = GameEventImpl.get("minecraft:block_deactivate"); + + GameEvent BLOCK_DESTROY = GameEventImpl.get("minecraft:block_destroy"); + + GameEvent BLOCK_DETACH = GameEventImpl.get("minecraft:block_detach"); + + GameEvent BLOCK_OPEN = GameEventImpl.get("minecraft:block_open"); + + GameEvent BLOCK_PLACE = GameEventImpl.get("minecraft:block_place"); + + GameEvent CONTAINER_CLOSE = GameEventImpl.get("minecraft:container_close"); + + GameEvent CONTAINER_OPEN = GameEventImpl.get("minecraft:container_open"); + + GameEvent DRINK = GameEventImpl.get("minecraft:drink"); + + GameEvent EAT = GameEventImpl.get("minecraft:eat"); + + GameEvent ELYTRA_GLIDE = GameEventImpl.get("minecraft:elytra_glide"); + + GameEvent ENTITY_DAMAGE = GameEventImpl.get("minecraft:entity_damage"); + + GameEvent ENTITY_DIE = GameEventImpl.get("minecraft:entity_die"); + + GameEvent ENTITY_DISMOUNT = GameEventImpl.get("minecraft:entity_dismount"); + + GameEvent ENTITY_INTERACT = GameEventImpl.get("minecraft:entity_interact"); + + GameEvent ENTITY_MOUNT = GameEventImpl.get("minecraft:entity_mount"); + + GameEvent ENTITY_PLACE = GameEventImpl.get("minecraft:entity_place"); + + GameEvent ENTITY_ACTION = GameEventImpl.get("minecraft:entity_action"); + + GameEvent EQUIP = GameEventImpl.get("minecraft:equip"); + + GameEvent EXPLODE = GameEventImpl.get("minecraft:explode"); + + GameEvent FLAP = GameEventImpl.get("minecraft:flap"); + + GameEvent FLUID_PICKUP = GameEventImpl.get("minecraft:fluid_pickup"); + + GameEvent FLUID_PLACE = GameEventImpl.get("minecraft:fluid_place"); + + GameEvent HIT_GROUND = GameEventImpl.get("minecraft:hit_ground"); + + GameEvent INSTRUMENT_PLAY = GameEventImpl.get("minecraft:instrument_play"); + + GameEvent ITEM_INTERACT_FINISH = GameEventImpl.get("minecraft:item_interact_finish"); + + GameEvent ITEM_INTERACT_START = GameEventImpl.get("minecraft:item_interact_start"); + + GameEvent JUKEBOX_PLAY = GameEventImpl.get("minecraft:jukebox_play"); + + GameEvent JUKEBOX_STOP_PLAY = GameEventImpl.get("minecraft:jukebox_stop_play"); + + GameEvent LIGHTNING_STRIKE = GameEventImpl.get("minecraft:lightning_strike"); + + GameEvent NOTE_BLOCK_PLAY = GameEventImpl.get("minecraft:note_block_play"); + + GameEvent PRIME_FUSE = GameEventImpl.get("minecraft:prime_fuse"); + + GameEvent PROJECTILE_LAND = GameEventImpl.get("minecraft:projectile_land"); + + GameEvent PROJECTILE_SHOOT = GameEventImpl.get("minecraft:projectile_shoot"); + + GameEvent SCULK_SENSOR_TENDRILS_CLICKING = GameEventImpl.get("minecraft:sculk_sensor_tendrils_clicking"); + + GameEvent SHEAR = GameEventImpl.get("minecraft:shear"); + + GameEvent SHRIEK = GameEventImpl.get("minecraft:shriek"); + + GameEvent SPLASH = GameEventImpl.get("minecraft:splash"); + + GameEvent STEP = GameEventImpl.get("minecraft:step"); + + GameEvent SWIM = GameEventImpl.get("minecraft:swim"); + + GameEvent TELEPORT = GameEventImpl.get("minecraft:teleport"); + + GameEvent UNEQUIP = GameEventImpl.get("minecraft:unequip"); + + GameEvent RESONATE_1 = GameEventImpl.get("minecraft:resonate_1"); + + GameEvent RESONATE_2 = GameEventImpl.get("minecraft:resonate_2"); + + GameEvent RESONATE_3 = GameEventImpl.get("minecraft:resonate_3"); + + GameEvent RESONATE_4 = GameEventImpl.get("minecraft:resonate_4"); + + GameEvent RESONATE_5 = GameEventImpl.get("minecraft:resonate_5"); + + GameEvent RESONATE_6 = GameEventImpl.get("minecraft:resonate_6"); + + GameEvent RESONATE_7 = GameEventImpl.get("minecraft:resonate_7"); + + GameEvent RESONATE_8 = GameEventImpl.get("minecraft:resonate_8"); + + GameEvent RESONATE_9 = GameEventImpl.get("minecraft:resonate_9"); + + GameEvent RESONATE_10 = GameEventImpl.get("minecraft:resonate_10"); + + GameEvent RESONATE_11 = GameEventImpl.get("minecraft:resonate_11"); + + GameEvent RESONATE_12 = GameEventImpl.get("minecraft:resonate_12"); + + GameEvent RESONATE_13 = GameEventImpl.get("minecraft:resonate_13"); + + GameEvent RESONATE_14 = GameEventImpl.get("minecraft:resonate_14"); + + GameEvent RESONATE_15 = GameEventImpl.get("minecraft:resonate_15"); +} diff --git a/src/main/java/net/minestom/server/game/GameEvent.java b/src/main/java/net/minestom/server/game/GameEvent.java new file mode 100644 index 000000000..a2853834a --- /dev/null +++ b/src/main/java/net/minestom/server/game/GameEvent.java @@ -0,0 +1,66 @@ +package net.minestom.server.game; + + +import net.minestom.server.registry.Registry; +import net.minestom.server.registry.StaticProtocolObject; +import net.minestom.server.utils.NamespaceID; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +/** + * Represents a game event. + * Used for a wide variety of events, from weather to bed use to game mode to demo messages. + */ +public sealed interface GameEvent extends StaticProtocolObject permits GameEventImpl { + + /** + * Returns the game event registry. + * + * @return the game event registry or null if not found + */ + @Contract(pure = true) + @Nullable + Registry.GameEventEntry registry(); + + /** + * Gets the namespace ID of this game event. + * + * @return the namespace ID + */ + @Override + @NotNull + NamespaceID namespace(); + + /** + * Gets the game events from the registry. + * + * @return the game events + */ + static @NotNull Collection<@NotNull GameEvent> values() { + return GameEventImpl.values(); + } + + /** + * Gets a game event by its namespace ID. + * + * @param namespaceID the namespace ID + * @return the game event or null if not found + */ + static @Nullable GameEvent fromNamespaceId(@NotNull String namespaceID) { + return GameEventImpl.getSafe(namespaceID); + } + + /** + * Gets a game event by its namespace ID. + * + * @param namespaceID the namespace ID + * @return the game event or null if not found + */ + static @Nullable GameEvent fromNamespaceId(@NotNull NamespaceID namespaceID) { + return fromNamespaceId(namespaceID.asString()); + } + +} diff --git a/src/main/java/net/minestom/server/game/GameEventImpl.java b/src/main/java/net/minestom/server/game/GameEventImpl.java new file mode 100644 index 000000000..d07ab20d0 --- /dev/null +++ b/src/main/java/net/minestom/server/game/GameEventImpl.java @@ -0,0 +1,65 @@ +package net.minestom.server.game; + + +import net.minestom.server.registry.Registry; +import net.minestom.server.utils.NamespaceID; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; + +/** + * Represents a game event implementation. + * Used for a wide variety of events, from weather to bed use to game mode to demo messages. + */ +record GameEventImpl(Registry.GameEventEntry registry, NamespaceID namespace, int id) implements GameEvent { + private static final Registry.Container CONTAINER = Registry.createStaticContainer(Registry.Resource.GAME_EVENTS, GameEventImpl::createImpl); + + /** + * Creates a new {@link GameEventImpl} with the given namespace and properties. + * + * @param namespace the namespace + * @param properties the properties + * @return a new {@link GameEventImpl} + */ + private static GameEventImpl createImpl(String namespace, Registry.Properties properties) { + return new GameEventImpl(Registry.gameEventEntry(namespace, properties)); + } + + /** + * Creates a new {@link GameEventImpl} with the given registry. + * + * @param registry the registry + */ + private GameEventImpl(Registry.GameEventEntry registry) { + this(registry, registry.namespace(), registry.main().getInt("id")); + } + + /** + * Gets the game events from the registry. + * + * @return the game events + */ + static Collection values() { + return CONTAINER.values(); + } + + /** + * Gets a game event by its namespace ID. + * + * @param namespace the namespace ID + * @return the game event or null if not found + */ + public static GameEvent get(@NotNull String namespace) { + return CONTAINER.get(namespace); + } + + /** + * Gets a game event by its namespace ID. + * + * @param namespace the namespace ID + * @return the game event or null if not found + */ + static GameEvent getSafe(@NotNull String namespace) { + return CONTAINER.getSafe(namespace); + } +} \ No newline at end of file diff --git a/src/main/java/net/minestom/server/gamedata/tags/Tag.java b/src/main/java/net/minestom/server/gamedata/tags/Tag.java index a6c321232..7783fef32 100644 --- a/src/main/java/net/minestom/server/gamedata/tags/Tag.java +++ b/src/main/java/net/minestom/server/gamedata/tags/Tag.java @@ -2,8 +2,8 @@ package net.minestom.server.gamedata.tags; import net.kyori.adventure.key.Key; import net.kyori.adventure.key.Keyed; -import net.minestom.server.MinecraftServer; import net.minestom.server.entity.EntityType; +import net.minestom.server.game.GameEvent; import net.minestom.server.instance.block.Block; import net.minestom.server.item.Material; import net.minestom.server.registry.*; @@ -14,10 +14,9 @@ import org.jetbrains.annotations.Nullable; import java.util.Collections; import java.util.HashSet; -import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.function.BiFunction; -import java.util.function.Function; /** * Represents a group of items, blocks, fluids, entity types or function. @@ -92,32 +91,35 @@ public final class Tag implements ProtocolObject, Keyed { public enum BasicType { BLOCKS("minecraft:block", Registry.Resource.BLOCK_TAGS, - (name, registries) -> Objects.requireNonNull(Block.fromNamespaceId(name)).id()), + (blockName, registries) -> Optional.ofNullable(Block.fromNamespaceId(blockName)).map(Block::id)), ITEMS("minecraft:item", Registry.Resource.ITEM_TAGS, - (name, registries) -> Objects.requireNonNull(Material.fromNamespaceId(name)).id()), + (itemName, registries) -> Optional.ofNullable(Material.fromNamespaceId(itemName)).map(Material::id)), FLUIDS("minecraft:fluid", Registry.Resource.FLUID_TAGS, - (name, registries) -> FluidRegistries.getFluid(name).ordinal()), + (name, registries) -> Optional.of(name).map(FluidRegistries::getFluid).map(Enum::ordinal)), ENTITY_TYPES("minecraft:entity_type", Registry.Resource.ENTITY_TYPE_TAGS, - (name, registries) -> Objects.requireNonNull(EntityType.fromNamespaceId(name)).id()), + (entityName, registries) -> Optional.ofNullable(EntityType.fromNamespaceId(entityName)).map(EntityType::id)), GAME_EVENTS("minecraft:game_event", Registry.Resource.GAMEPLAY_TAGS, - (name, registries) -> FluidRegistries.getFluid(name).ordinal()), + (eventName, registries) -> Optional.ofNullable(GameEvent.fromNamespaceId(eventName)).map(GameEvent::id)), SOUND_EVENTS("minecraft:sound_event", null, null), // Seems not to be included in server data POTION_EFFECTS("minecraft:potion_effect", null, null), // Seems not to be included in server data - //todo this is cursed. it does not update as the registry changes. Fix later. ENCHANTMENTS("minecraft:enchantment", Registry.Resource.ENCHANTMENT_TAGS, - (name, registries) -> registries.enchantment().getId(DynamicRegistry.Key.of(name))), + (name, registries) -> Optional.of(DynamicRegistry.Key.of(name)) + .map(DynamicRegistry.Key::namespace) + .map(registries.enchantment()::getId)), BIOMES("minecraft:worldgen/biome", Registry.Resource.BIOME_TAGS, - (name, registries) -> registries.biome().getId(DynamicRegistry.Key.of(name))); + (name, registries) -> Optional.of(DynamicRegistry.Key.of(name)) + .map(DynamicRegistry.Key::namespace) + .map(registries.biome()::getId)); - private final static BasicType[] VALUES = values(); + private static final BasicType[] VALUES = values(); private final String identifier; private final Registry.Resource resource; - private final BiFunction function; + private final BiFunction> function; BasicType(@NotNull String identifier, @Nullable Registry.Resource resource, - @Nullable BiFunction function) { + @Nullable BiFunction> function) { this.identifier = identifier; this.resource = resource; this.function = function; @@ -131,7 +133,7 @@ public final class Tag implements ProtocolObject, Keyed { return resource; } - public BiFunction getFunction() { + public BiFunction> getFunction() { return function; } diff --git a/src/main/java/net/minestom/server/gamedata/tags/TagManager.java b/src/main/java/net/minestom/server/gamedata/tags/TagManager.java index 81b0ba01c..f5f9025db 100644 --- a/src/main/java/net/minestom/server/gamedata/tags/TagManager.java +++ b/src/main/java/net/minestom/server/gamedata/tags/TagManager.java @@ -30,8 +30,8 @@ public final class TagManager { public @Nullable Tag getTag(Tag.BasicType type, String namespace) { final var tags = tagMap.get(type); - for (var tag : tags) { - if (tag.getName().asString().equals(namespace)) + for (final var tag : tags) { + if (tag.name().equals(namespace)) return tag; } return null; @@ -46,10 +46,10 @@ public final class TagManager { for (Map.Entry> entry : tagMap.entrySet()) { final Tag.BasicType type = entry.getKey(); final String registry = type.getIdentifier(); - List tags = new ArrayList<>(); - for (Tag tag : entry.getValue()) { - final String identifier = tag.getName().asString(); - final int[] values = tag.getValues().stream().mapToInt(value -> type.getFunction().apply(value.asString(), registries)).toArray(); + final List tags = new ArrayList<>(); + for (final Tag tag : entry.getValue()) { + final String identifier = tag.name(); + final int[] values = tag.getValues().stream().mapToInt(value -> type.getFunction().apply(value.asString(), registries).orElse(null)).filter(Objects::nonNull).toArray(); tags.add(new TagsPacket.Tag(identifier, values)); } registryList.add(new TagsPacket.Registry(registry, tags)); diff --git a/src/main/java/net/minestom/server/registry/Registry.java b/src/main/java/net/minestom/server/registry/Registry.java index f413861fa..431db24d1 100644 --- a/src/main/java/net/minestom/server/registry/Registry.java +++ b/src/main/java/net/minestom/server/registry/Registry.java @@ -137,6 +137,10 @@ public final class Registry { return new JukeboxSongEntry(namespace, main, null); } + public static GameEventEntry gameEventEntry(String namespace, Properties properties) { + return new GameEventEntry(namespace, properties, null); + } + public static @NotNull InputStream loadRegistryFile(@NotNull Resource resource) throws IOException { // 1. Try to load from jar resources InputStream resourceStream = Registry.class.getClassLoader().getResourceAsStream(resource.name); @@ -245,6 +249,7 @@ public final class Registry { ENTITY_TYPE_TAGS("tags/entity_type.json"), FLUID_TAGS("tags/fluid.json"), GAMEPLAY_TAGS("tags/game_event.json"), + GAME_EVENTS("game_events.json"), ITEM_TAGS("tags/item.json"), ENCHANTMENT_TAGS("tags/enchantment.json"), BIOME_TAGS("tags/biome.json"), @@ -270,6 +275,12 @@ public final class Registry { } } + public record GameEventEntry(NamespaceID namespace, Properties main, Properties custom) implements Entry { + public GameEventEntry(String namespace, Properties main, Properties custom) { + this(NamespaceID.from(namespace), main, custom); + } + } + public static final class BlockEntry implements Entry { private final NamespaceID namespace; private final int id;