Support tags for more SimpleRegistry (#11607)

This commit is contained in:
Jake Potrebic 2024-11-23 11:26:51 -08:00
parent 857931f5cc
commit 0dc6316e04
8 changed files with 155 additions and 75 deletions

View File

@ -206,6 +206,43 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
public static <T extends Keyed> Registry<T> getRegistry(@NotNull Class<T> tClass) { public static <T extends Keyed> Registry<T> getRegistry(@NotNull Class<T> tClass) {
return server.getRegistry(tClass); return server.getRegistry(tClass);
} }
diff --git a/src/main/java/org/bukkit/Particle.java b/src/main/java/org/bukkit/Particle.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/Particle.java
+++ b/src/main/java/org/bukkit/Particle.java
@@ -0,0 +0,0 @@ public enum Particle implements Keyed {
private final NamespacedKey key;
private final Class<?> dataType;
- final boolean register;
+ // Paper - all particles are registered
Particle(String key) {
this(key, Void.class);
}
- Particle(String key, boolean register) {
- this(key, Void.class, register);
- }
+ // Paper - all particles are registered
Particle(String key, /*@NotNull*/ Class<?> data) {
- this(key, data, true);
- }
-
- Particle(String key, /*@NotNull*/ Class<?> data, boolean register) {
+ // Paper - all particles are registered
if (key != null) {
this.key = NamespacedKey.minecraft(key);
} else {
this.key = null;
}
dataType = data;
- this.register = register;
+ // Paper - all particles are registered
}
/**
diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/Registry.java --- a/src/main/java/org/bukkit/Registry.java
@ -274,7 +311,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
/** /**
* Server entity types. * Server entity types.
* *
@@ -0,0 +0,0 @@ public interface Registry<T extends Keyed> extends Iterable<T> { * @see EntityType
*/
- Registry<EntityType> ENTITY_TYPE = new SimpleRegistry<>(EntityType.class, (entity) -> entity != EntityType.UNKNOWN);
+ Registry<EntityType> ENTITY_TYPE = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.ENTITY_TYPE); // Paper
/**
* Server instruments. * Server instruments.
* *
* @see MusicInstrument * @see MusicInstrument
@ -311,6 +352,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
/** /**
* Server particles. * Server particles.
* *
* @see Particle
*/
- Registry<Particle> PARTICLE_TYPE = new SimpleRegistry<>(Particle.class, (par) -> par.register);
+ Registry<Particle> PARTICLE_TYPE = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.PARTICLE_TYPE); // Paper
/**
* Server potions.
*
* @see PotionType
*/
- Registry<PotionType> POTION = new SimpleRegistry<>(PotionType.class);
+ Registry<PotionType> POTION = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.POTION); // Paper
/**
* Server statistics.
*
@@ -0,0 +0,0 @@ public interface Registry<T extends Keyed> extends Iterable<T> { @@ -0,0 +0,0 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
* Server structures. * Server structures.
* *
@ -428,6 +483,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
/** /**
* Get the object by its key. * Get the object by its key.
* *
@@ -0,0 +0,0 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
return (namespacedKey != null) ? get(namespacedKey) : null;
}
- static final class SimpleRegistry<T extends Enum<T> & Keyed> implements Registry<T> {
+ class SimpleRegistry<T extends Enum<T> & Keyed> implements Registry<T> { // Paper - remove final
private final Class<T> type;
private final Map<NamespacedKey, T> map;
diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/Server.java --- a/src/main/java/org/bukkit/Server.java

View File

@ -9,9 +9,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/org/bukkit/UnsafeValues.java --- a/src/main/java/org/bukkit/UnsafeValues.java
+++ b/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java
@@ -0,0 +0,0 @@ public interface UnsafeValues { @@ -0,0 +0,0 @@ public interface UnsafeValues {
@NotNull java.util.List<net.kyori.adventure.text.Component> computeTooltipLines(@NotNull ItemStack itemStack, @NotNull io.papermc.paper.inventory.tooltip.TooltipContext tooltipContext, @Nullable org.bukkit.entity.Player player); // Paper - expose itemstack tooltip lines // Paper end - lifecycle event API
<A extends Keyed, M> io.papermc.paper.registry.tag.@Nullable Tag<A> getTag(io.papermc.paper.registry.tag.@NotNull TagKey<A> tagKey); // Paper - hack to get tags for non-server backed registries @NotNull java.util.List<net.kyori.adventure.text.Component> computeTooltipLines(@NotNull ItemStack itemStack, @NotNull io.papermc.paper.inventory.tooltip.TooltipContext tooltipContext, @Nullable org.bukkit.entity.Player player); // Paper - expose itemstack tooltip lines
+ +
+ ItemStack createEmptyStack(); // Paper - proxy ItemStack + ItemStack createEmptyStack(); // Paper - proxy ItemStack
} }

View File

@ -875,38 +875,3 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
/** /**
* Get the object by its key. * Get the object by its key.
* *
@@ -0,0 +0,0 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
return value.getKey();
}
// Paper end - improve Registry
+
+ // Paper start - RegistrySet API
+ @SuppressWarnings("deprecation")
+ @Override
+ public boolean hasTag(final io.papermc.paper.registry.tag.@NotNull TagKey<T> key) {
+ return Bukkit.getUnsafe().getTag(key) != null;
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public io.papermc.paper.registry.tag.@NotNull Tag<T> getTag(final io.papermc.paper.registry.tag.@NotNull TagKey<T> key) {
+ final io.papermc.paper.registry.tag.Tag<T> tag = Bukkit.getUnsafe().getTag(key);
+ if (tag == null) {
+ throw new java.util.NoSuchElementException("No tag " + key + " found");
+ }
+ return tag;
+ }
+ // Paper end - RegistrySet API
}
}
diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/UnsafeValues.java
+++ b/src/main/java/org/bukkit/UnsafeValues.java
@@ -0,0 +0,0 @@ public interface UnsafeValues {
// Paper end - lifecycle event API
@NotNull java.util.List<net.kyori.adventure.text.Component> computeTooltipLines(@NotNull ItemStack itemStack, @NotNull io.papermc.paper.inventory.tooltip.TooltipContext tooltipContext, @Nullable org.bukkit.entity.Player player); // Paper - expose itemstack tooltip lines
+
+ <A extends Keyed, M> io.papermc.paper.registry.tag.@Nullable Tag<A> getTag(io.papermc.paper.registry.tag.@NotNull TagKey<A> tagKey); // Paper - hack to get tags for non-server backed registries
}

View File

@ -18,6 +18,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@ @@ -0,0 +0,0 @@
+package io.papermc.paper.registry; +package io.papermc.paper.registry;
+ +
+import com.google.common.base.Preconditions;
+import io.papermc.paper.adventure.PaperAdventure; +import io.papermc.paper.adventure.PaperAdventure;
+import io.papermc.paper.registry.entry.RegistryEntry; +import io.papermc.paper.registry.entry.RegistryEntry;
+import java.util.Collections; +import java.util.Collections;
@ -125,16 +126,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ entry(Registries.INSTRUMENT, RegistryKey.INSTRUMENT, MusicInstrument.class, CraftMusicInstrument::new).delayed(), + entry(Registries.INSTRUMENT, RegistryKey.INSTRUMENT, MusicInstrument.class, CraftMusicInstrument::new).delayed(),
+ +
+ // api-only + // api-only
+ apiOnly(Registries.ENTITY_TYPE, RegistryKey.ENTITY_TYPE, () -> org.bukkit.Registry.ENTITY_TYPE), + apiOnly(Registries.ENTITY_TYPE, RegistryKey.ENTITY_TYPE, PaperSimpleRegistry::entityType),
+ apiOnly(Registries.PARTICLE_TYPE, RegistryKey.PARTICLE_TYPE, () -> org.bukkit.Registry.PARTICLE_TYPE), + apiOnly(Registries.PARTICLE_TYPE, RegistryKey.PARTICLE_TYPE, PaperSimpleRegistry::particleType),
+ apiOnly(Registries.POTION, RegistryKey.POTION, () -> org.bukkit.Registry.POTION), + apiOnly(Registries.POTION, RegistryKey.POTION, PaperSimpleRegistry::potion),
+ apiOnly(Registries.MEMORY_MODULE_TYPE, RegistryKey.MEMORY_MODULE_TYPE, () -> (org.bukkit.Registry<MemoryKey<?>>) (org.bukkit.Registry) org.bukkit.Registry.MEMORY_MODULE_TYPE) + apiOnly(Registries.MEMORY_MODULE_TYPE, RegistryKey.MEMORY_MODULE_TYPE, () -> (org.bukkit.Registry<MemoryKey<?>>) (org.bukkit.Registry) org.bukkit.Registry.MEMORY_MODULE_TYPE)
+ ); + );
+ final Map<RegistryKey<?>, RegistryEntry<?, ?>> byRegistryKey = new IdentityHashMap<>(REGISTRY_ENTRIES.size()); + final Map<RegistryKey<?>, RegistryEntry<?, ?>> byRegistryKey = new IdentityHashMap<>(REGISTRY_ENTRIES.size());
+ final Map<ResourceKey<?>, RegistryEntry<?, ?>> byResourceKey = new IdentityHashMap<>(REGISTRY_ENTRIES.size()); + final Map<ResourceKey<?>, RegistryEntry<?, ?>> byResourceKey = new IdentityHashMap<>(REGISTRY_ENTRIES.size());
+ for (final RegistryEntry<?, ?> entry : REGISTRY_ENTRIES) { + for (final RegistryEntry<?, ?> entry : REGISTRY_ENTRIES) {
+ byRegistryKey.put(entry.apiKey(), entry); + Preconditions.checkState(byRegistryKey.put(entry.apiKey(), entry) == null, "Duplicate api registry key: %s", entry.apiKey());
+ byResourceKey.put(entry.mcKey(), entry); + Preconditions.checkState(byResourceKey.put(entry.mcKey(), entry) == null, "Duplicate mc registry key: %s", entry.mcKey());
+ } + }
+ BY_REGISTRY_KEY = Collections.unmodifiableMap(byRegistryKey); + BY_REGISTRY_KEY = Collections.unmodifiableMap(byRegistryKey);
+ BY_RESOURCE_KEY = Collections.unmodifiableMap(byResourceKey); + BY_RESOURCE_KEY = Collections.unmodifiableMap(byResourceKey);
@ -305,6 +306,50 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return (RegistryKey<T>) LegacyRegistryIdentifiers.CLASS_TO_KEY_MAP.get(type); + return (RegistryKey<T>) LegacyRegistryIdentifiers.CLASS_TO_KEY_MAP.get(type);
+ } + }
+} +}
diff --git a/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java b/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.registry;
+
+import java.util.function.Predicate;
+import net.minecraft.core.registries.BuiltInRegistries;
+import org.bukkit.Keyed;
+import org.bukkit.Particle;
+import org.bukkit.Registry;
+import org.bukkit.entity.EntityType;
+import org.bukkit.potion.PotionType;
+import org.jspecify.annotations.NullMarked;
+
+@NullMarked
+public class PaperSimpleRegistry<T extends Enum<T> & Keyed, M> extends Registry.SimpleRegistry<T> {
+
+ static Registry<EntityType> entityType() {
+ return new PaperSimpleRegistry<>(EntityType.class, entity -> entity != EntityType.UNKNOWN, BuiltInRegistries.ENTITY_TYPE);
+ }
+
+ static Registry<Particle> particleType() {
+ return new PaperSimpleRegistry<>(Particle.class, BuiltInRegistries.PARTICLE_TYPE);
+ }
+
+ static Registry<PotionType> potion() {
+ return new PaperSimpleRegistry<>(PotionType.class, BuiltInRegistries.POTION);
+ }
+
+ private final net.minecraft.core.Registry<M> nmsRegistry;
+
+ protected PaperSimpleRegistry(final Class<T> type, final net.minecraft.core.Registry<M> nmsRegistry) {
+ super(type);
+ this.nmsRegistry = nmsRegistry;
+ }
+
+ public PaperSimpleRegistry(final Class<T> type, final Predicate<T> predicate, final net.minecraft.core.Registry<M> nmsRegistry) {
+ super(type, predicate);
+ this.nmsRegistry = nmsRegistry;
+ }
+}
diff --git a/src/main/java/io/papermc/paper/registry/RegistryHolder.java b/src/main/java/io/papermc/paper/registry/RegistryHolder.java diff --git a/src/main/java/io/papermc/paper/registry/RegistryHolder.java b/src/main/java/io/papermc/paper/registry/RegistryHolder.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000

View File

@ -9,9 +9,9 @@ diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/src/
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java --- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java
+++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java +++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java
@@ -0,0 +0,0 @@ @@ -0,0 +0,0 @@ package io.papermc.paper.registry;
package io.papermc.paper.registry;
import com.google.common.base.Preconditions;
import io.papermc.paper.adventure.PaperAdventure; import io.papermc.paper.adventure.PaperAdventure;
+import io.papermc.paper.registry.data.PaperEnchantmentRegistryEntry; +import io.papermc.paper.registry.data.PaperEnchantmentRegistryEntry;
+import io.papermc.paper.registry.data.PaperGameEventRegistryEntry; +import io.papermc.paper.registry.data.PaperGameEventRegistryEntry;

View File

@ -3592,9 +3592,9 @@ diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/src/
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java --- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java
+++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java +++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java
@@ -0,0 +0,0 @@ @@ -0,0 +0,0 @@ package io.papermc.paper.registry;
package io.papermc.paper.registry;
import com.google.common.base.Preconditions;
import io.papermc.paper.adventure.PaperAdventure; import io.papermc.paper.adventure.PaperAdventure;
+import io.papermc.paper.datacomponent.DataComponentType; +import io.papermc.paper.datacomponent.DataComponentType;
+import io.papermc.paper.datacomponent.PaperComponentType; +import io.papermc.paper.datacomponent.PaperComponentType;

View File

@ -210,7 +210,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
@@ -0,0 +0,0 @@ public final class CraftMagicNumbers implements UnsafeValues { @@ -0,0 +0,0 @@ public final class CraftMagicNumbers implements UnsafeValues {
} }
// Paper end - hack to get tags for non server-backed registries // Paper end - lifecycle event API
+ // Paper start - proxy ItemStack + // Paper start - proxy ItemStack
+ @Override + @Override

View File

@ -15,7 +15,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java --- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java
+++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java +++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java
@@ -0,0 +0,0 @@ package io.papermc.paper.registry; @@ -0,0 +0,0 @@ package io.papermc.paper.registry;
import com.google.common.base.Preconditions;
import io.papermc.paper.adventure.PaperAdventure; import io.papermc.paper.adventure.PaperAdventure;
import io.papermc.paper.registry.entry.RegistryEntry; import io.papermc.paper.registry.entry.RegistryEntry;
+import io.papermc.paper.registry.tag.TagKey; +import io.papermc.paper.registry.tag.TagKey;
@ -286,6 +286,38 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return this.freezeEventTypes.getOrCreate(type.registryKey(), RegistryLifecycleEventType::new); + return this.freezeEventTypes.getOrCreate(type.registryKey(), RegistryLifecycleEventType::new);
+ } + }
+} +}
diff --git a/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java b/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java
+++ b/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java
@@ -0,0 +0,0 @@
package io.papermc.paper.registry;
+import io.papermc.paper.registry.set.NamedRegistryKeySetImpl;
+import io.papermc.paper.registry.tag.Tag;
+import io.papermc.paper.registry.tag.TagKey;
import java.util.function.Predicate;
+import net.minecraft.core.HolderSet;
import net.minecraft.core.registries.BuiltInRegistries;
import org.bukkit.Keyed;
import org.bukkit.Particle;
@@ -0,0 +0,0 @@ public class PaperSimpleRegistry<T extends Enum<T> & Keyed, M> extends Registry.
super(type, predicate);
this.nmsRegistry = nmsRegistry;
}
+
+ @Override
+ public boolean hasTag(final TagKey<T> key) {
+ final net.minecraft.tags.TagKey<M> nmsKey = PaperRegistries.toNms(key);
+ return this.nmsRegistry.get(nmsKey).isPresent();
+ }
+
+ @Override
+ public Tag<T> getTag(final TagKey<T> key) {
+ final HolderSet.Named<M> namedHolderSet = this.nmsRegistry.get(PaperRegistries.toNms(key)).orElseThrow();
+ return new NamedRegistryKeySetImpl<>(key, namedHolderSet);
+ }
}
diff --git a/src/main/java/io/papermc/paper/registry/WritableCraftRegistry.java b/src/main/java/io/papermc/paper/registry/WritableCraftRegistry.java diff --git a/src/main/java/io/papermc/paper/registry/WritableCraftRegistry.java b/src/main/java/io/papermc/paper/registry/WritableCraftRegistry.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
@ -1365,32 +1397,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ // Paper end - RegistrySet API + // Paper end - RegistrySet API
} }
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
@@ -0,0 +0,0 @@ public final class CraftMagicNumbers implements UnsafeValues {
}
// Paper end - lifecycle event API
+ // Paper start - hack to get tags for non server-backed registries
+ @Override
+ public <A extends Keyed, M> io.papermc.paper.registry.tag.Tag<A> getTag(final io.papermc.paper.registry.tag.TagKey<A> tagKey) { // TODO remove Keyed
+ if (tagKey.registryKey() != io.papermc.paper.registry.RegistryKey.ENTITY_TYPE && tagKey.registryKey() != io.papermc.paper.registry.RegistryKey.FLUID) {
+ throw new UnsupportedOperationException(tagKey.registryKey() + " doesn't have tags");
+ }
+ final net.minecraft.resources.ResourceKey<? extends net.minecraft.core.Registry<M>> nmsKey = io.papermc.paper.registry.PaperRegistries.registryToNms(tagKey.registryKey());
+ final net.minecraft.core.Registry<M> nmsRegistry = org.bukkit.craftbukkit.CraftRegistry.getMinecraftRegistry().lookupOrThrow(nmsKey);
+ return nmsRegistry
+ .get(io.papermc.paper.registry.PaperRegistries.toNms(tagKey))
+ .map(named -> new io.papermc.paper.registry.set.NamedRegistryKeySetImpl<>(tagKey, named))
+ .orElse(null);
+ }
+ // Paper end - hack to get tags for non server-backed registries
+
/**
* This helper class represents the different NBT Tags.
* <p>
diff --git a/src/main/resources/META-INF/services/io.papermc.paper.registry.event.RegistryEventTypeProvider b/src/main/resources/META-INF/services/io.papermc.paper.registry.event.RegistryEventTypeProvider diff --git a/src/main/resources/META-INF/services/io.papermc.paper.registry.event.RegistryEventTypeProvider b/src/main/resources/META-INF/services/io.papermc.paper.registry.event.RegistryEventTypeProvider
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000