mirror of
https://github.com/Minestom/Minestom.git
synced 2025-02-14 19:32:17 +01:00
Do not cache registry (#651)
This commit is contained in:
parent
6716b21a4a
commit
0743759eed
@ -44,7 +44,7 @@ import java.util.function.BiFunction;
|
||||
|
||||
record EntityTypeImpl(Registry.EntityEntry registry) implements EntityType {
|
||||
private static final Registry.Container<EntityType> CONTAINER = Registry.createContainer(Registry.Resource.ENTITIES,
|
||||
(namespace, object) -> new EntityTypeImpl(Registry.entity(namespace, object, null)));
|
||||
(namespace, properties) -> new EntityTypeImpl(Registry.entity(namespace, properties)));
|
||||
static final Map<String, BiFunction<Entity, Metadata, EntityMeta>> ENTITY_META_SUPPLIER = createMetaMap();
|
||||
|
||||
static EntityType get(@NotNull String namespace) {
|
||||
|
@ -9,6 +9,7 @@ import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.utils.ArrayUtils;
|
||||
import net.minestom.server.utils.ObjectArray;
|
||||
import net.minestom.server.utils.block.BlockUtils;
|
||||
import net.minestom.server.utils.collection.MergedMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Unmodifiable;
|
||||
@ -20,7 +21,7 @@ import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
record BlockImpl(@NotNull Registry.BlockEntry registry,
|
||||
@NotNull int[] propertiesArray,
|
||||
int @NotNull [] propertiesArray,
|
||||
@Nullable NBTCompound nbt,
|
||||
@Nullable BlockHandler handler) implements Block {
|
||||
// Block state -> block object
|
||||
@ -32,20 +33,21 @@ record BlockImpl(@NotNull Registry.BlockEntry registry,
|
||||
// Block id -> Map<PropertiesValues, Block>
|
||||
private static final ObjectArray<Map<PropertiesHolder, BlockImpl>> POSSIBLE_STATES = new ObjectArray<>();
|
||||
private static final Registry.Container<Block> CONTAINER = Registry.createContainer(Registry.Resource.BLOCKS,
|
||||
(namespace, object) -> {
|
||||
final int blockId = ((Number) object.get("id")).intValue();
|
||||
final var stateObject = (Map<String, Object>) object.get("states");
|
||||
(namespace, properties) -> {
|
||||
final int blockId = properties.getInt("id");
|
||||
final Registry.Properties stateObject = properties.section("states");
|
||||
|
||||
// Retrieve properties
|
||||
String[] keys = new String[0];
|
||||
String[][] values = new String[0][];
|
||||
{
|
||||
var properties = (Map<String, Object>) object.get("properties");
|
||||
if (properties != null) {
|
||||
keys = new String[properties.size()];
|
||||
values = new String[properties.size()][];
|
||||
Registry.Properties stateProperties = properties.section("properties");
|
||||
if (stateProperties != null) {
|
||||
final int stateCount = stateProperties.size();
|
||||
keys = new String[stateCount];
|
||||
values = new String[stateCount][];
|
||||
int i = 0;
|
||||
for (var entry : properties.entrySet()) {
|
||||
for (var entry : stateProperties) {
|
||||
final int entryIndex = i++;
|
||||
keys[entryIndex] = entry.getKey();
|
||||
|
||||
@ -59,12 +61,11 @@ record BlockImpl(@NotNull Registry.BlockEntry registry,
|
||||
|
||||
// Retrieve block states
|
||||
{
|
||||
final var stateEntries = stateObject.entrySet();
|
||||
final int propertiesCount = stateEntries.size();
|
||||
final int propertiesCount = stateObject.size();
|
||||
PropertiesHolder[] propertiesKeys = new PropertiesHolder[propertiesCount];
|
||||
BlockImpl[] blocksValues = new BlockImpl[propertiesCount];
|
||||
int propertiesOffset = 0;
|
||||
for (var stateEntry : stateEntries) {
|
||||
for (var stateEntry : stateObject) {
|
||||
final String query = stateEntry.getKey();
|
||||
final var stateOverride = (Map<String, Object>) stateEntry.getValue();
|
||||
final var propertyMap = BlockUtils.parseProperties(query);
|
||||
@ -82,7 +83,8 @@ record BlockImpl(@NotNull Registry.BlockEntry registry,
|
||||
propertiesArray[keyIndex] = valueIndex;
|
||||
}
|
||||
|
||||
final BlockImpl block = new BlockImpl(Registry.block(namespace, object, stateOverride),
|
||||
var mainProperties = Registry.Properties.fromMap(new MergedMap<>(properties.asMap(), stateOverride));
|
||||
final BlockImpl block = new BlockImpl(Registry.block(namespace, mainProperties),
|
||||
propertiesArray, null, null);
|
||||
BLOCK_STATE_MAP.set(block.stateId(), block);
|
||||
propertiesKeys[propertiesOffset] = new PropertiesHolder(propertiesArray);
|
||||
@ -91,7 +93,7 @@ record BlockImpl(@NotNull Registry.BlockEntry registry,
|
||||
POSSIBLE_STATES.set(blockId, ArrayUtils.toMap(propertiesKeys, blocksValues, propertiesOffset));
|
||||
}
|
||||
// Register default state
|
||||
final int defaultState = ((Number) object.get("defaultStateId")).intValue();
|
||||
final int defaultState = properties.getInt("defaultStateId");
|
||||
return getState(defaultState);
|
||||
});
|
||||
private static final Cache<NBTCompound, NBTCompound> NBT_CACHE = Caffeine.newBuilder()
|
||||
|
@ -7,7 +7,7 @@ import java.util.Collection;
|
||||
|
||||
record EnchantmentImpl(Registry.EnchantmentEntry registry) implements Enchantment {
|
||||
private static final Registry.Container<Enchantment> CONTAINER = Registry.createContainer(Registry.Resource.ENCHANTMENTS,
|
||||
(namespace, object) -> new EnchantmentImpl(Registry.enchantment(namespace, object, null)));
|
||||
(namespace, properties) -> new EnchantmentImpl(Registry.enchantment(namespace, properties)));
|
||||
|
||||
static Enchantment get(@NotNull String namespace) {
|
||||
return CONTAINER.get(namespace);
|
||||
|
@ -7,7 +7,7 @@ import java.util.Collection;
|
||||
|
||||
record MaterialImpl(Registry.MaterialEntry registry) implements Material {
|
||||
private static final Registry.Container<Material> CONTAINER = Registry.createContainer(Registry.Resource.ITEMS,
|
||||
(namespace, object) -> new MaterialImpl(Registry.material(namespace, object, null)));
|
||||
(namespace, properties) -> new MaterialImpl(Registry.material(namespace, properties)));
|
||||
|
||||
static Material get(@NotNull String namespace) {
|
||||
return CONTAINER.get(namespace);
|
||||
|
@ -8,7 +8,7 @@ import java.util.Collection;
|
||||
|
||||
record ParticleImpl(NamespaceID namespace, int id) implements Particle {
|
||||
private static final Registry.Container<Particle> CONTAINER = Registry.createContainer(Registry.Resource.PARTICLES,
|
||||
(namespace, object) -> new ParticleImpl(NamespaceID.from(namespace), ((Number) object.get("id")).intValue()));
|
||||
(namespace, properties) -> new ParticleImpl(NamespaceID.from(namespace), properties.getInt("id")));
|
||||
|
||||
static Particle get(@NotNull String namespace) {
|
||||
return CONTAINER.get(namespace);
|
||||
|
@ -7,7 +7,7 @@ import java.util.Collection;
|
||||
|
||||
record PotionEffectImpl(Registry.PotionEffectEntry registry) implements PotionEffect {
|
||||
private static final Registry.Container<PotionEffect> CONTAINER = Registry.createContainer(Registry.Resource.POTION_EFFECTS,
|
||||
(namespace, object) -> new PotionEffectImpl(Registry.potionEffect(namespace, object, null)));
|
||||
(namespace, properties) -> new PotionEffectImpl(Registry.potionEffect(namespace, properties)));
|
||||
|
||||
static PotionEffect get(@NotNull String namespace) {
|
||||
return CONTAINER.get(namespace);
|
||||
|
@ -8,7 +8,7 @@ import java.util.Collection;
|
||||
|
||||
record PotionTypeImpl(NamespaceID namespace, int id) implements PotionType {
|
||||
private static final Registry.Container<PotionType> CONTAINER = Registry.createContainer(Registry.Resource.POTION_TYPES,
|
||||
(namespace, object) -> new PotionTypeImpl(NamespaceID.from(namespace), ((Number) object.get("id")).intValue()));
|
||||
(namespace, properties) -> new PotionTypeImpl(NamespaceID.from(namespace), properties.getInt("id")));
|
||||
|
||||
static PotionType get(@NotNull String namespace) {
|
||||
return CONTAINER.get(namespace);
|
||||
|
@ -26,28 +26,28 @@ import java.util.function.Supplier;
|
||||
*/
|
||||
public final class Registry {
|
||||
@ApiStatus.Internal
|
||||
public static BlockEntry block(String namespace, @NotNull Map<String, Object> jsonObject, Map<String, Object> override) {
|
||||
return new BlockEntry(namespace, jsonObject, override);
|
||||
public static BlockEntry block(String namespace, @NotNull Properties main) {
|
||||
return new BlockEntry(namespace, main, null);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static MaterialEntry material(String namespace, @NotNull Map<String, Object> jsonObject, Map<String, Object> override) {
|
||||
return new MaterialEntry(namespace, jsonObject, override);
|
||||
public static MaterialEntry material(String namespace, @NotNull Properties main) {
|
||||
return new MaterialEntry(namespace, main, null);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static EntityEntry entity(String namespace, @NotNull Map<String, Object> jsonObject, Map<String, Object> override) {
|
||||
return new EntityEntry(namespace, jsonObject, override);
|
||||
public static EntityEntry entity(String namespace, @NotNull Properties main) {
|
||||
return new EntityEntry(namespace, main, null);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static EnchantmentEntry enchantment(String namespace, @NotNull Map<String, Object> jsonObject, Map<String, Object> override) {
|
||||
return new EnchantmentEntry(namespace, jsonObject, override);
|
||||
public static EnchantmentEntry enchantment(String namespace, @NotNull Properties main) {
|
||||
return new EnchantmentEntry(namespace, main, null);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static PotionEffectEntry potionEffect(String namespace, @NotNull Map<String, Object> jsonObject, Map<String, Object> override) {
|
||||
return new PotionEffectEntry(namespace, jsonObject, override);
|
||||
public static PotionEffectEntry potionEffect(String namespace, @NotNull Properties main) {
|
||||
return new PotionEffectEntry(namespace, main, null);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
@ -73,8 +73,8 @@ public final class Registry {
|
||||
ObjectArray<T> ids = new ObjectArray<>(entries.size());
|
||||
for (var entry : entries.entrySet()) {
|
||||
final String namespace = entry.getKey();
|
||||
final Map<String, Object> object = entry.getValue();
|
||||
final T value = loader.get(namespace, object);
|
||||
final Properties properties = Properties.fromMap(entry.getValue());
|
||||
final T value = loader.get(namespace, properties);
|
||||
ids.set(value.id(), value);
|
||||
namespaces.put(value.name(), value);
|
||||
}
|
||||
@ -119,7 +119,7 @@ public final class Registry {
|
||||
}
|
||||
|
||||
public interface Loader<T extends ProtocolObject> {
|
||||
T get(String namespace, Map<String, Object> object);
|
||||
T get(String namespace, Properties properties);
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,7 +148,7 @@ public final class Registry {
|
||||
}
|
||||
}
|
||||
|
||||
public static class BlockEntry extends Entry {
|
||||
public static final class BlockEntry implements Entry {
|
||||
private final NamespaceID namespace;
|
||||
private final int id;
|
||||
private final int stateId;
|
||||
@ -164,33 +164,34 @@ public final class Registry {
|
||||
private final String blockEntity;
|
||||
private final int blockEntityId;
|
||||
private final Supplier<Material> materialSupplier;
|
||||
private final Properties custom;
|
||||
|
||||
private BlockEntry(String namespace, Map<String, Object> main, Map<String, Object> override) {
|
||||
super(main, override);
|
||||
private BlockEntry(String namespace, Properties main, Properties custom) {
|
||||
this.custom = custom;
|
||||
this.namespace = NamespaceID.from(namespace);
|
||||
this.id = getInt("id");
|
||||
this.stateId = getInt("stateId");
|
||||
this.translationKey = getString("translationKey");
|
||||
this.hardness = getDouble("hardness");
|
||||
this.explosionResistance = getDouble("explosionResistance");
|
||||
this.friction = getDouble("friction");
|
||||
this.speedFactor = getDouble("speedFactor", 1);
|
||||
this.jumpFactor = getDouble("jumpFactor", 1);
|
||||
this.air = getBoolean("air", false);
|
||||
this.solid = getBoolean("solid");
|
||||
this.liquid = getBoolean("liquid", false);
|
||||
this.id = main.getInt("id");
|
||||
this.stateId = main.getInt("stateId");
|
||||
this.translationKey = main.getString("translationKey");
|
||||
this.hardness = main.getDouble("hardness");
|
||||
this.explosionResistance = main.getDouble("explosionResistance");
|
||||
this.friction = main.getDouble("friction");
|
||||
this.speedFactor = main.getDouble("speedFactor", 1);
|
||||
this.jumpFactor = main.getDouble("jumpFactor", 1);
|
||||
this.air = main.getBoolean("air", false);
|
||||
this.solid = main.getBoolean("solid");
|
||||
this.liquid = main.getBoolean("liquid", false);
|
||||
{
|
||||
Map<String, Object> blockEntity = element("blockEntity");
|
||||
Properties blockEntity = main.section("blockEntity");
|
||||
if (blockEntity != null) {
|
||||
this.blockEntity = (String) blockEntity.get("namespace");
|
||||
this.blockEntityId = ((Number) blockEntity.get("id")).intValue();
|
||||
this.blockEntity = blockEntity.getString("namespace");
|
||||
this.blockEntityId = blockEntity.getInt("id");
|
||||
} else {
|
||||
this.blockEntity = null;
|
||||
this.blockEntityId = 0;
|
||||
}
|
||||
}
|
||||
{
|
||||
final String materialNamespace = getString("correspondingItem", null);
|
||||
final String materialNamespace = main.getString("correspondingItem", null);
|
||||
this.materialSupplier = materialNamespace != null ? () -> Material.fromNamespaceId(materialNamespace) : () -> null;
|
||||
}
|
||||
}
|
||||
@ -258,9 +259,14 @@ public final class Registry {
|
||||
public @Nullable Material material() {
|
||||
return materialSupplier.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties custom() {
|
||||
return custom;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MaterialEntry extends Entry {
|
||||
public static final class MaterialEntry implements Entry {
|
||||
private final NamespaceID namespace;
|
||||
private final int id;
|
||||
private final String translationKey;
|
||||
@ -269,25 +275,25 @@ public final class Registry {
|
||||
private final boolean isFood;
|
||||
private final Supplier<Block> blockSupplier;
|
||||
private final EquipmentSlot equipmentSlot;
|
||||
private final Properties custom;
|
||||
|
||||
private MaterialEntry(String namespace, Map<String, Object> main, Map<String, Object> override) {
|
||||
super(main, override);
|
||||
private MaterialEntry(String namespace, Properties main, Properties custom) {
|
||||
this.custom = custom;
|
||||
this.namespace = NamespaceID.from(namespace);
|
||||
this.id = getInt("id");
|
||||
this.translationKey = getString("translationKey");
|
||||
this.maxStackSize = getInt("maxStackSize", 64);
|
||||
this.maxDamage = getInt("maxDamage", 0);
|
||||
this.isFood = getBoolean("edible", false);
|
||||
this.id = main.getInt("id");
|
||||
this.translationKey = main.getString("translationKey");
|
||||
this.maxStackSize = main.getInt("maxStackSize", 64);
|
||||
this.maxDamage = main.getInt("maxDamage", 0);
|
||||
this.isFood = main.getBoolean("edible", false);
|
||||
{
|
||||
final String blockNamespace = getString("correspondingBlock", null);
|
||||
final String blockNamespace = main.getString("correspondingBlock", null);
|
||||
this.blockSupplier = blockNamespace != null ? () -> Block.fromNamespaceId(blockNamespace) : () -> null;
|
||||
}
|
||||
|
||||
{
|
||||
final Map<String, Object> armorProperties = element("armorProperties");
|
||||
final Properties armorProperties = main.section("armorProperties");
|
||||
if (armorProperties != null) {
|
||||
final String slot = (String) armorProperties.get("slot");
|
||||
switch (slot) {
|
||||
switch (armorProperties.getString("slot")) {
|
||||
case "feet" -> this.equipmentSlot = EquipmentSlot.BOOTS;
|
||||
case "legs" -> this.equipmentSlot = EquipmentSlot.LEGGINGS;
|
||||
case "chest" -> this.equipmentSlot = EquipmentSlot.CHESTPLATE;
|
||||
@ -335,206 +341,71 @@ public final class Registry {
|
||||
public @Nullable EquipmentSlot equipmentSlot() {
|
||||
return equipmentSlot;
|
||||
}
|
||||
}
|
||||
|
||||
public static class EntityEntry extends Entry {
|
||||
private final NamespaceID namespace;
|
||||
private final int id;
|
||||
private final String translationKey;
|
||||
private final double width;
|
||||
private final double height;
|
||||
private final double drag;
|
||||
private final double acceleration;
|
||||
private final EntitySpawnType spawnType;
|
||||
|
||||
private EntityEntry(String namespace, Map<String, Object> main, Map<String, Object> override) {
|
||||
super(main, override);
|
||||
this.namespace = NamespaceID.from(namespace);
|
||||
this.id = getInt("id");
|
||||
this.translationKey = getString("translationKey");
|
||||
this.width = getDouble("width");
|
||||
this.height = getDouble("height");
|
||||
this.drag = getDouble("drag", 0.02);
|
||||
this.acceleration = getDouble("acceleration", 0.08);
|
||||
this.spawnType = EntitySpawnType.valueOf(getString("packetType").toUpperCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
public @NotNull NamespaceID namespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
public int id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String translationKey() {
|
||||
return translationKey;
|
||||
}
|
||||
|
||||
public double width() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public double height() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public double drag() {
|
||||
return drag;
|
||||
}
|
||||
|
||||
public double acceleration() {
|
||||
return acceleration;
|
||||
}
|
||||
|
||||
public EntitySpawnType spawnType() {
|
||||
return spawnType;
|
||||
@Override
|
||||
public Properties custom() {
|
||||
return custom;
|
||||
}
|
||||
}
|
||||
|
||||
public static class EnchantmentEntry extends Entry {
|
||||
private final NamespaceID namespace;
|
||||
private final int id;
|
||||
private final String translationKey;
|
||||
private final double maxLevel;
|
||||
private final boolean isCursed;
|
||||
private final boolean isDiscoverable;
|
||||
private final boolean isTradeable;
|
||||
private final boolean isTreasureOnly;
|
||||
|
||||
private EnchantmentEntry(String namespace, Map<String, Object> main, Map<String, Object> override) {
|
||||
super(main, override);
|
||||
this.namespace = NamespaceID.from(namespace);
|
||||
this.id = getInt("id");
|
||||
this.translationKey = getString("translationKey");
|
||||
this.maxLevel = getDouble("maxLevel");
|
||||
this.isCursed = getBoolean("curse", false);
|
||||
this.isDiscoverable = getBoolean("discoverable", true);
|
||||
this.isTradeable = getBoolean("tradeable", true);
|
||||
this.isTreasureOnly = getBoolean("treasureOnly", false);
|
||||
}
|
||||
|
||||
public @NotNull NamespaceID namespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
public int id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String translationKey() {
|
||||
return translationKey;
|
||||
}
|
||||
|
||||
public double maxLevel() {
|
||||
return maxLevel;
|
||||
}
|
||||
|
||||
public boolean isCursed() {
|
||||
return isCursed;
|
||||
}
|
||||
|
||||
public boolean isDiscoverable() {
|
||||
return isDiscoverable;
|
||||
}
|
||||
|
||||
public boolean isTradeable() {
|
||||
return isTradeable;
|
||||
}
|
||||
|
||||
public boolean isTreasureOnly() {
|
||||
return isTreasureOnly;
|
||||
public record EntityEntry(NamespaceID namespace, int id,
|
||||
String translationKey,
|
||||
double width, double height,
|
||||
double drag, double acceleration,
|
||||
EntitySpawnType spawnType,
|
||||
Properties custom) implements Entry {
|
||||
public EntityEntry(String namespace, Properties main, Properties custom) {
|
||||
this(NamespaceID.from(namespace),
|
||||
main.getInt("id"),
|
||||
main.getString("translationKey"),
|
||||
main.getDouble("width"),
|
||||
main.getDouble("height"),
|
||||
main.getDouble("drag", 0.02),
|
||||
main.getDouble("acceleration", 0.08),
|
||||
EntitySpawnType.valueOf(main.getString("packetType").toUpperCase(Locale.ROOT)),
|
||||
custom);
|
||||
}
|
||||
}
|
||||
|
||||
public static class PotionEffectEntry extends Entry {
|
||||
private final NamespaceID namespace;
|
||||
private final int id;
|
||||
private final String translationKey;
|
||||
private final int color;
|
||||
private final boolean isInstantaneous;
|
||||
|
||||
private PotionEffectEntry(String namespace, Map<String, Object> main, Map<String, Object> override) {
|
||||
super(main, override);
|
||||
this.namespace = NamespaceID.from(namespace);
|
||||
this.id = getInt("id");
|
||||
this.translationKey = getString("translationKey");
|
||||
this.color = getInt("color");
|
||||
this.isInstantaneous = getBoolean("instantaneous");
|
||||
}
|
||||
|
||||
public @NotNull NamespaceID namespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
public int id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String translationKey() {
|
||||
return translationKey;
|
||||
}
|
||||
|
||||
public int color() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public boolean isInstantaneous() {
|
||||
return isInstantaneous;
|
||||
public record EnchantmentEntry(NamespaceID namespace, int id,
|
||||
String translationKey,
|
||||
double maxLevel,
|
||||
boolean isCursed,
|
||||
boolean isDiscoverable,
|
||||
boolean isTradeable,
|
||||
boolean isTreasureOnly,
|
||||
Properties custom) implements Entry {
|
||||
public EnchantmentEntry(String namespace, Properties main, Properties custom) {
|
||||
this(NamespaceID.from(namespace),
|
||||
main.getInt("id"),
|
||||
main.getString("translationKey"),
|
||||
main.getDouble("maxLevel"),
|
||||
main.getBoolean("isCursed", false),
|
||||
main.getBoolean("isDiscoverable", true),
|
||||
main.getBoolean("isTradeable", true),
|
||||
main.getBoolean("isTreasureOnly", false),
|
||||
custom);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Entry {
|
||||
private final Map<String, Object> main, override;
|
||||
|
||||
private Entry(Map<String, Object> main, Map<String, Object> override) {
|
||||
this.main = main;
|
||||
this.override = override;
|
||||
public record PotionEffectEntry(NamespaceID namespace, int id,
|
||||
String translationKey,
|
||||
int color,
|
||||
boolean isInstantaneous,
|
||||
Properties custom) implements Entry {
|
||||
public PotionEffectEntry(String namespace, Properties main, Properties custom) {
|
||||
this(NamespaceID.from(namespace),
|
||||
main.getInt("id"),
|
||||
main.getString("translationKey"),
|
||||
main.getInt("color"),
|
||||
main.getBoolean("instant"),
|
||||
custom);
|
||||
}
|
||||
}
|
||||
|
||||
public String getString(String name, String defaultValue) {
|
||||
var element = element(name);
|
||||
return element != null ? (String) element : defaultValue;
|
||||
}
|
||||
|
||||
public String getString(String name) {
|
||||
return element(name);
|
||||
}
|
||||
|
||||
public double getDouble(String name, double defaultValue) {
|
||||
var element = element(name);
|
||||
return element != null ? ((Number) element).doubleValue() : defaultValue;
|
||||
}
|
||||
|
||||
public double getDouble(String name) {
|
||||
return ((Number) element(name)).doubleValue();
|
||||
}
|
||||
|
||||
public int getInt(String name, int defaultValue) {
|
||||
var element = element(name);
|
||||
return element != null ? ((Number) element).intValue() : defaultValue;
|
||||
}
|
||||
|
||||
public int getInt(String name) {
|
||||
return ((Number) element(name)).intValue();
|
||||
}
|
||||
|
||||
public boolean getBoolean(String name, boolean defaultValue) {
|
||||
var element = element(name);
|
||||
return element != null ? (boolean) element : defaultValue;
|
||||
}
|
||||
|
||||
public boolean getBoolean(String name) {
|
||||
return element(name);
|
||||
}
|
||||
|
||||
protected <T> T element(String name) {
|
||||
Object result;
|
||||
if (override != null && (result = override.get(name)) != null) {
|
||||
return (T) result;
|
||||
}
|
||||
return (T) main.get(name);
|
||||
}
|
||||
public interface Entry {
|
||||
@ApiStatus.Experimental
|
||||
Properties custom();
|
||||
}
|
||||
|
||||
private static Object readObject(JsonReader reader) throws IOException {
|
||||
@ -544,19 +415,117 @@ public final class Registry {
|
||||
reader.beginArray();
|
||||
while (reader.hasNext()) list.add(readObject(reader));
|
||||
reader.endArray();
|
||||
yield List.copyOf(list);
|
||||
yield list;
|
||||
}
|
||||
case BEGIN_OBJECT -> {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
reader.beginObject();
|
||||
while (reader.hasNext()) map.put(reader.nextName().intern(), readObject(reader));
|
||||
while (reader.hasNext()) map.put(reader.nextName(), readObject(reader));
|
||||
reader.endObject();
|
||||
yield Map.copyOf(map);
|
||||
yield map;
|
||||
}
|
||||
case STRING -> reader.nextString().intern();
|
||||
case STRING -> reader.nextString();
|
||||
case NUMBER -> ToNumberPolicy.LONG_OR_DOUBLE.readNumber(reader);
|
||||
case BOOLEAN -> reader.nextBoolean();
|
||||
default -> throw new IllegalStateException("Invalid peek: " + reader.peek());
|
||||
};
|
||||
}
|
||||
|
||||
record PropertiesMap(Map<String, Object> map) implements Properties {
|
||||
@Override
|
||||
public String getString(String name, String defaultValue) {
|
||||
var element = element(name);
|
||||
return element != null ? (String) element : defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(String name) {
|
||||
return element(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble(String name, double defaultValue) {
|
||||
var element = element(name);
|
||||
return element != null ? ((Number) element).doubleValue() : defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble(String name) {
|
||||
return ((Number) element(name)).doubleValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(String name, int defaultValue) {
|
||||
var element = element(name);
|
||||
return element != null ? ((Number) element).intValue() : defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(String name) {
|
||||
return ((Number) element(name)).intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(String name, boolean defaultValue) {
|
||||
var element = element(name);
|
||||
return element != null ? (boolean) element : defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(String name) {
|
||||
return element(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties section(String name) {
|
||||
Map<String, Object> map = element(name);
|
||||
if (map == null) return null;
|
||||
return new PropertiesMap(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> asMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
private <T> T element(String name) {
|
||||
//noinspection unchecked
|
||||
return (T) map.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
public interface Properties extends Iterable<Map.Entry<String, Object>> {
|
||||
static Properties fromMap(Map<String, Object> map) {
|
||||
return new PropertiesMap(map);
|
||||
}
|
||||
|
||||
String getString(String name, String defaultValue);
|
||||
|
||||
String getString(String name);
|
||||
|
||||
double getDouble(String name, double defaultValue);
|
||||
|
||||
double getDouble(String name);
|
||||
|
||||
int getInt(String name, int defaultValue);
|
||||
|
||||
int getInt(String name);
|
||||
|
||||
boolean getBoolean(String name, boolean defaultValue);
|
||||
|
||||
boolean getBoolean(String name);
|
||||
|
||||
Properties section(String name);
|
||||
|
||||
Map<String, Object> asMap();
|
||||
|
||||
@Override
|
||||
default @NotNull Iterator<Map.Entry<String, Object>> iterator() {
|
||||
return asMap().entrySet().iterator();
|
||||
}
|
||||
|
||||
default int size() {
|
||||
return asMap().size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import java.util.Collection;
|
||||
|
||||
record SoundEventImpl(NamespaceID namespace, int id) implements SoundEvent {
|
||||
private static final Registry.Container<SoundEvent> CONTAINER = Registry.createContainer(Registry.Resource.SOUNDS,
|
||||
(namespace, object) -> new SoundEventImpl(NamespaceID.from(namespace), ((Number) object.get("id")).intValue()));
|
||||
(namespace, properties) -> new SoundEventImpl(NamespaceID.from(namespace), properties.getInt("id")));
|
||||
|
||||
static SoundEvent get(@NotNull String namespace) {
|
||||
return CONTAINER.get(namespace);
|
||||
|
@ -8,7 +8,7 @@ import java.util.Collection;
|
||||
|
||||
record StatisticTypeImpl(NamespaceID namespace, int id) implements StatisticType {
|
||||
private static final Registry.Container<StatisticType> CONTAINER = Registry.createContainer(Registry.Resource.STATISTICS,
|
||||
(namespace, object) -> new StatisticTypeImpl(NamespaceID.from(namespace), ((Number) object.get("id")).intValue()));
|
||||
(namespace, properties) -> new StatisticTypeImpl(NamespaceID.from(namespace), properties.getInt("id")));
|
||||
|
||||
static StatisticType get(@NotNull String namespace) {
|
||||
return CONTAINER.get(namespace);
|
||||
|
@ -0,0 +1,90 @@
|
||||
package net.minestom.server.utils.collection;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public final class MergedMap<K, V> extends AbstractMap<K, V> {
|
||||
private final Map<K, V> first, second;
|
||||
|
||||
public MergedMap(Map<K, V> first, Map<K, V> second) {
|
||||
this.first = Objects.requireNonNull(first);
|
||||
this.second = Objects.requireNonNull(second);
|
||||
}
|
||||
|
||||
// mandatory methods
|
||||
|
||||
final Set<Entry<K, V>> entrySet = new AbstractSet<>() {
|
||||
@Override
|
||||
public Iterator<Map.Entry<K, V>> iterator() {
|
||||
return stream().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return (int) stream().count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<Entry<K, V>> stream() {
|
||||
return Stream.concat(first.entrySet().stream(), secondStream())
|
||||
.map(e -> new AbstractMap.SimpleImmutableEntry<>(e.getKey(), e.getValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<Entry<K, V>> parallelStream() {
|
||||
return stream().parallel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spliterator<Entry<K, V>> spliterator() {
|
||||
return stream().spliterator();
|
||||
}
|
||||
};
|
||||
|
||||
Stream<Entry<K, V>> secondStream() {
|
||||
return second.entrySet().stream().filter(e -> !first.containsKey(e.getKey()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Map.Entry<K, V>> entrySet() {
|
||||
return entrySet;
|
||||
}
|
||||
|
||||
// optimizations
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return first.containsKey(key) || second.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return first.containsValue(value) ||
|
||||
secondStream().anyMatch(Predicate.isEqual(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
V v = first.get(key);
|
||||
return v != null ? v : second.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getOrDefault(Object key, V defaultValue) {
|
||||
V v = first.get(key);
|
||||
return v != null ? v : second.getOrDefault(key, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(BiConsumer<? super K, ? super V> action) {
|
||||
first.forEach(action);
|
||||
second.forEach((k, v) -> {
|
||||
if (!first.containsKey(k)) action.accept(k, v);
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user