net.minestom.server.registry.DynamicRegistry Maven / Gradle / Ivy
Show all versions of minestom-snapshots Show documentation
package net.minestom.server.registry;
import net.kyori.adventure.key.Keyed;
import net.minestom.server.entity.Player;
import net.minestom.server.gamedata.DataPack;
import net.minestom.server.network.packet.server.SendablePacket;
import net.minestom.server.utils.NamespaceID;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Comparator;
import java.util.List;
/**
* Holds registry data for any of the registries controlled by the server. Entries in registries should be referenced
* using a {@link Key} object as opposed to the record type. For example, a biome should be stored as
* `DynamicRegistry.Key Biome`, as opposed to `Biome` directly.
*
* Builtin registries should be accessed via a {@link Registries} instance (currently implemented by
* {@link net.minestom.server.ServerProcess}, or from {@link net.minestom.server.MinecraftServer} static methods.
*
* @param The type of the registry entries
*
* @see Registries
*/
public sealed interface DynamicRegistry permits DynamicRegistryImpl {
/**
* A key for a {@link ProtocolObject} in a {@link DynamicRegistry}.
*
* @param Unused, except to provide compile-time safety and self documentation.
*/
sealed interface Key extends Keyed permits DynamicRegistryImpl.KeyImpl {
static @NotNull Key of(@NotNull String namespace) {
return new DynamicRegistryImpl.KeyImpl<>(NamespaceID.from(namespace));
}
static @NotNull Key of(@NotNull NamespaceID namespace) {
return new DynamicRegistryImpl.KeyImpl<>(namespace);
}
@Contract(pure = true)
@NotNull NamespaceID namespace();
@Contract(pure = true)
default @NotNull String name() {
return namespace().asString();
}
@Override
@Contract(pure = true)
default @NotNull net.kyori.adventure.key.Key key() {
return namespace();
}
}
@ApiStatus.Internal
static @NotNull DynamicRegistry create(@NotNull String id) {
return new DynamicRegistryImpl<>(id, null);
}
/**
* Creates a new empty registry of the given type. Should only be used internally.
*
* @see Registries
*/
@ApiStatus.Internal
static @NotNull DynamicRegistry create(
@NotNull String id, @NotNull BinaryTagSerializer nbtType) {
return new DynamicRegistryImpl<>(id, nbtType);
}
/**
* Creates a new empty registry of the given type. Should only be used internally.
*
* @see Registries
*/
@ApiStatus.Internal
static @NotNull DynamicRegistry create(
@NotNull String id, @NotNull BinaryTagSerializer nbtType,
@NotNull Registry.Resource resource, @NotNull Registry.Container.Loader loader) {
return create(id, nbtType, resource, loader, null);
}
/**
* Creates a new empty registry of the given type. Should only be used internally.
*
* @see Registries
*/
@ApiStatus.Internal
static @NotNull DynamicRegistry create(
@NotNull String id, @NotNull BinaryTagSerializer nbtType,
@NotNull Registry.Resource resource, @NotNull Registry.Container.Loader loader,
@Nullable Comparator idComparator) {
final DynamicRegistry registry = new DynamicRegistryImpl<>(id, nbtType);
DynamicRegistryImpl.loadStaticRegistry(registry, resource, loader, idComparator);
return registry;
}
/**
* Creates a new empty registry of the given type. Should only be used internally.
*
* @see Registries
*/
@ApiStatus.Internal
static @NotNull DynamicRegistry create(
@NotNull String id, @NotNull BinaryTagSerializer nbtType,
@NotNull Registries registries, @NotNull Registry.Resource resource) {
final DynamicRegistryImpl registry = new DynamicRegistryImpl<>(id, nbtType);
DynamicRegistryImpl.loadStaticSnbtRegistry(registries, registry, resource);
return registry;
}
@NotNull String id();
@Nullable T get(int id);
@Nullable T get(@NotNull NamespaceID namespace);
default @Nullable T get(@NotNull Key key) {
return get(key.namespace());
}
@Nullable Key getKey(int id);
@Nullable Key getKey(@NotNull T value);
@Nullable NamespaceID getName(int id);
@Nullable DataPack getPack(int id);
default @Nullable DataPack getPack(@NotNull Key key) {
final int id = getId(key);
return id == -1 ? null : getPack(id);
}
/**
* Returns the protocol ID associated with the given {@link NamespaceID}, or -1 if none is registered.
*
* @see #register(NamespaceID, T)
*/
int getId(@NotNull NamespaceID id);
/**
* Returns the protocol ID associated with the given {@link Key}, or -1 if none is registered.
*
* @see #register(NamespaceID, T)
*/
default int getId(@NotNull Key key) {
return getId(key.namespace());
}
/**
* Returns the entries in this registry as an immutable list. The indices in the returned list correspond
* to the protocol ID of each entry.
*
* Note: The returned list is not guaranteed to update with the registry,
* it should be fetched again for updated values.
*
* @return An immutable list of the entries in this registry.
*/
@NotNull List values();
/**
* Register an object to this registry, overwriting the previous entry if any is present.
*
* Note: the new registry will not be sent to existing players. They must be returned to
* the configuration phase to receive new registry data. See {@link Player#startConfigurationPhase()}.
*
* WARNING: Updating an existing entry is an inherently unsafe operation as it may cause desync with
* existing structures. This behavior is disabled by default, and must be enabled by setting the system
* property minestom.registry.unsafe-ops
to true
.
*
* @param object The entry to register
* @return The new ID of the registered object
*/
default @NotNull DynamicRegistry.Key register(@NotNull String id, @NotNull T object) {
return register(NamespaceID.from(id), object, null);
}
default @NotNull DynamicRegistry.Key register(@NotNull NamespaceID id, @NotNull T object) {
return register(id, object, null);
}
@ApiStatus.Internal
default @NotNull DynamicRegistry.Key register(@NotNull String id, @NotNull T object, @Nullable DataPack pack) {
return register(NamespaceID.from(id), object, pack);
}
@ApiStatus.Internal
default @NotNull DynamicRegistry.Key register(@NotNull NamespaceID id, @NotNull T object, @Nullable DataPack pack) {
return register(id, object);
}
/**
* Removes an object from this registry.
*
* WARNING: This operation will cause all subsequent IDs to be remapped, meaning that any loaded entry
* with existing IDs may be incorrect. For example, loading a world with 0=plains, 1=desert, 2=badlands would store
* those IDs in the palette. If you then deleted entry 1 (desert), any desert biomes in the loaded world would
* become badlands, and any badlands would become invalid. This behavior is disabled by default, and must be
* enabled by setting the system property minestom.registry.unsafe-ops
to true
.
*
* Note: the new registry will not be sent to existing players. They must be returned to
* the configuration phase to receive new registry data. See {@link Player#startConfigurationPhase()}.
*
* @param namespaceId The id of the entry to remove
* @return True if the object was removed, false if it was not present
* @throws UnsupportedOperationException If the system property minestom.registry.unsafe-remove
is not set to true
*/
boolean remove(@NotNull NamespaceID namespaceId) throws UnsupportedOperationException;
/**
* Returns a {@link SendablePacket} potentially excluding vanilla entries if possible. It is never possible to
* exclude vanilla entries if one has been overridden (e.g. via {@link #register(NamespaceID, T)}.
*
* @param excludeVanilla Whether to exclude vanilla entries
* @return A {@link SendablePacket} containing the registry data
*/
@ApiStatus.Internal
@NotNull SendablePacket registryDataPacket(boolean excludeVanilla);
}