mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Use an array for java blocks and replace rarely used map in BlockMappings
This commit is contained in:
parent
206368e448
commit
64b0788012
7 changed files with 185 additions and 26 deletions
|
@ -232,11 +232,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||||
if (packet.getActions().isEmpty()) {
|
if (packet.getActions().isEmpty()) {
|
||||||
if (session.getOpPermissionLevel() >= 2 && session.getGameMode() == GameMode.CREATIVE) {
|
if (session.getOpPermissionLevel() >= 2 && session.getGameMode() == GameMode.CREATIVE) {
|
||||||
// Otherwise insufficient permissions
|
// Otherwise insufficient permissions
|
||||||
int blockState = session.getBlockMappings().getJavaBlockState(packet.getBlockRuntimeId());
|
if (session.getBlockMappings().getJigsawStateIds().contains(packet.getBlockRuntimeId())) {
|
||||||
String blockName = BlockRegistries.JAVA_IDENTIFIERS.get().getOrDefault(blockState, "");
|
|
||||||
// In the future this can be used for structure blocks too, however not all elements
|
|
||||||
// are available in each GUI
|
|
||||||
if (blockName.contains("jigsaw")) {
|
|
||||||
ContainerOpenPacket openPacket = new ContainerOpenPacket();
|
ContainerOpenPacket openPacket = new ContainerOpenPacket();
|
||||||
openPacket.setBlockPosition(packet.getBlockPosition());
|
openPacket.setBlockPosition(packet.getBlockPosition());
|
||||||
openPacket.setId((byte) 1);
|
openPacket.setId((byte) 1);
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.connector.registry;
|
||||||
|
|
||||||
|
import org.geysermc.connector.registry.loader.RegistryLoader;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array registry that stores mappings as an array defined by {@link M}.
|
||||||
|
* The M represents the value that is to be stored as part of this array.
|
||||||
|
*
|
||||||
|
* @param <M> the mapping type
|
||||||
|
*/
|
||||||
|
public class ArrayRegistry<M> extends Registry<M[]> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new array registry of this class with the given input and
|
||||||
|
* {@link RegistryLoader}. The input specified is what the registry
|
||||||
|
* loader needs to take in.
|
||||||
|
*
|
||||||
|
* @param input the input
|
||||||
|
* @param registryLoader the registry loader
|
||||||
|
*/
|
||||||
|
protected <I> ArrayRegistry(I input, RegistryLoader<I, M[]> registryLoader) {
|
||||||
|
super(input, registryLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value registered by the given index.
|
||||||
|
*
|
||||||
|
* @param index the index
|
||||||
|
* @return the value registered by the given index.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public M get(int index) {
|
||||||
|
if (index >= this.mappings.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.mappings[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value registered by the given index or the default value
|
||||||
|
* specified if null.
|
||||||
|
*
|
||||||
|
* @param index the index
|
||||||
|
* @param defaultValue the default value
|
||||||
|
* @return the value registered by the given key or the default value
|
||||||
|
* specified if null.
|
||||||
|
*/
|
||||||
|
public M getOrDefault(int index, M defaultValue) {
|
||||||
|
M value = this.get(index);
|
||||||
|
if (value == null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a new value into this registry with the given index.
|
||||||
|
*
|
||||||
|
* @param index the index
|
||||||
|
* @param value the value
|
||||||
|
* @return a new value into this registry with the given index.
|
||||||
|
*/
|
||||||
|
public M register(int index, M value) {
|
||||||
|
return this.mappings[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new array registry with the given {@link RegistryLoader} supplier. The
|
||||||
|
* input type is not specified here, meaning the loader return type is either
|
||||||
|
* predefined, or the registry is populated at a later point.
|
||||||
|
*
|
||||||
|
* @param registryLoader the registry loader supplier
|
||||||
|
* @param <I> the input type
|
||||||
|
* @param <M> the returned mappings type
|
||||||
|
* @return a new registry with the given RegistryLoader supplier
|
||||||
|
*/
|
||||||
|
public static <I, M> ArrayRegistry<M> create(Supplier<RegistryLoader<I, M[]>> registryLoader) {
|
||||||
|
return new ArrayRegistry<>(null, registryLoader.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new array registry with the given {@link RegistryLoader} supplier
|
||||||
|
* and input.
|
||||||
|
*
|
||||||
|
* @param input the input
|
||||||
|
* @param registryLoader the registry loader supplier
|
||||||
|
* @param <I> the input type
|
||||||
|
* @param <M> the returned mappings type
|
||||||
|
* @return a new registry with the given RegistryLoader supplier
|
||||||
|
*/
|
||||||
|
public static <I, M> ArrayRegistry<M> create(I input, Supplier<RegistryLoader<I, M[]>> registryLoader) {
|
||||||
|
return new ArrayRegistry<>(input, registryLoader.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new array registry with the given {@link RegistryLoader}. The
|
||||||
|
* input type is not specified here, meaning the loader return type is either
|
||||||
|
* predefined, or the registry is populated at a later point.
|
||||||
|
*
|
||||||
|
* @param registryLoader the registry loader
|
||||||
|
* @param <I> the input type
|
||||||
|
* @param <M> the returned mappings type
|
||||||
|
* @return a new registry with the given RegistryLoader supplier
|
||||||
|
*/
|
||||||
|
public static <I, M> ArrayRegistry<M> create(RegistryLoader<I, M[]> registryLoader) {
|
||||||
|
return new ArrayRegistry<>(null, registryLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new array registry with the given {@link RegistryLoader} and input.
|
||||||
|
*
|
||||||
|
* @param input the input
|
||||||
|
* @param registryLoader the registry loader
|
||||||
|
* @param <I> the input type
|
||||||
|
* @param <M> the returned mappings type
|
||||||
|
* @return a new registry with the given RegistryLoader supplier
|
||||||
|
*/
|
||||||
|
public static <I, M> ArrayRegistry<M> create(I input, RegistryLoader<I, M[]> registryLoader) {
|
||||||
|
return new ArrayRegistry<>(input, registryLoader);
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,7 +25,6 @@
|
||||||
|
|
||||||
package org.geysermc.connector.registry;
|
package org.geysermc.connector.registry;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||||
|
@ -52,10 +51,10 @@ public class BlockRegistries {
|
||||||
public static final SimpleMappedRegistry<String, String> JAVA_TO_BEDROCK_IDENTIFIERS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new));
|
public static final SimpleMappedRegistry<String, String> JAVA_TO_BEDROCK_IDENTIFIERS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mapped registry which stores Java IDs to {@link BlockMapping}, containing miscellaneous information about
|
* A registry which stores Java IDs to {@link BlockMapping}, containing miscellaneous information about
|
||||||
* blocks and their behavior in many cases.
|
* blocks and their behavior in many cases.
|
||||||
*/
|
*/
|
||||||
public static final MappedRegistry<Integer, BlockMapping, Int2ObjectMap<BlockMapping>> JAVA_BLOCKS = MappedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new));
|
public static final ArrayRegistry<BlockMapping> JAVA_BLOCKS = ArrayRegistry.create(RegistryLoaders.empty(() -> new BlockMapping[] {}));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A (bi)mapped registry containing the Java IDs to identifiers.
|
* A (bi)mapped registry containing the Java IDs to identifiers.
|
||||||
|
|
|
@ -64,7 +64,7 @@ import java.util.function.Consumer;
|
||||||
* @param <M> the value being held by the registry
|
* @param <M> the value being held by the registry
|
||||||
*/
|
*/
|
||||||
public abstract class Registry<M> {
|
public abstract class Registry<M> {
|
||||||
protected final M mappings;
|
protected M mappings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of this class with the given input and
|
* Creates a new instance of this class with the given input and
|
||||||
|
@ -88,6 +88,17 @@ public abstract class Registry<M> {
|
||||||
return this.mappings;
|
return this.mappings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the underlying value held by this registry.
|
||||||
|
* Clears any existing data associated with the previous
|
||||||
|
* value.
|
||||||
|
*
|
||||||
|
* @param mappings the underlying value held by this registry
|
||||||
|
*/
|
||||||
|
public void set(M mappings) {
|
||||||
|
this.mappings = mappings;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers what is specified in the given
|
* Registers what is specified in the given
|
||||||
* {@link Consumer} into the underlying value.
|
* {@link Consumer} into the underlying value.
|
||||||
|
|
|
@ -75,12 +75,13 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String,
|
||||||
throw new AssertionError("Unable to load collision data", e);
|
throw new AssertionError("Unable to load collision data", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
Int2ObjectMap<BlockMapping> blockMap = BlockRegistries.JAVA_BLOCKS.get();
|
BlockMapping[] blockMappings = BlockRegistries.JAVA_BLOCKS.get();
|
||||||
|
|
||||||
// Map of unique collisions to its instance
|
// Map of unique collisions to its instance
|
||||||
Map<BlockCollision, BlockCollision> collisionInstances = new Object2ObjectOpenHashMap<>();
|
Map<BlockCollision, BlockCollision> collisionInstances = new Object2ObjectOpenHashMap<>();
|
||||||
for (Int2ObjectMap.Entry<BlockMapping> entry : blockMap.int2ObjectEntrySet()) {
|
for (int i = 0; i < blockMappings.length; i++) {
|
||||||
BlockCollision newCollision = instantiateCollision(entry.getValue(), annotationMap, collisionList);
|
BlockMapping blockMapping = blockMappings[i];
|
||||||
|
BlockCollision newCollision = instantiateCollision(blockMapping, annotationMap, collisionList);
|
||||||
|
|
||||||
if (newCollision != null) {
|
if (newCollision != null) {
|
||||||
// If there's an existing instance equal to this one, use that instead
|
// If there's an existing instance equal to this one, use that instead
|
||||||
|
@ -92,7 +93,7 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
collisions.put(entry.getIntKey(), newCollision);
|
collisions.put(i, newCollision);
|
||||||
}
|
}
|
||||||
return collisions;
|
return collisions;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,10 +30,10 @@ import com.google.common.collect.ImmutableMap;
|
||||||
import com.nukkitx.nbt.*;
|
import com.nukkitx.nbt.*;
|
||||||
import com.nukkitx.protocol.bedrock.v440.Bedrock_v440;
|
import com.nukkitx.protocol.bedrock.v440.Bedrock_v440;
|
||||||
import com.nukkitx.protocol.bedrock.v448.Bedrock_v448;
|
import com.nukkitx.protocol.bedrock.v448.Bedrock_v448;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
import it.unimi.dsi.fastutil.ints.IntList;
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||||
|
@ -140,11 +140,12 @@ public class BlockRegistryPopulator {
|
||||||
BiFunction<String, NbtMapBuilder, String> stateMapper = STATE_MAPPER.getOrDefault(palette.getKey(), (i, s) -> null);
|
BiFunction<String, NbtMapBuilder, String> stateMapper = STATE_MAPPER.getOrDefault(palette.getKey(), (i, s) -> null);
|
||||||
|
|
||||||
IntList javaToBedrockBlockMap = new IntArrayList();
|
IntList javaToBedrockBlockMap = new IntArrayList();
|
||||||
Int2IntMap bedrockToJavaBlockMap = new Int2IntOpenHashMap();
|
|
||||||
|
|
||||||
Map<String, NbtMap> flowerPotBlocks = new Object2ObjectOpenHashMap<>();
|
Map<String, NbtMap> flowerPotBlocks = new Object2ObjectOpenHashMap<>();
|
||||||
Object2IntMap<NbtMap> itemFrames = new Object2IntOpenHashMap<>();
|
Object2IntMap<NbtMap> itemFrames = new Object2IntOpenHashMap<>();
|
||||||
|
|
||||||
|
IntSet jigsawStateIds = new IntOpenHashSet();
|
||||||
|
|
||||||
BlockMappings.BlockMappingsBuilder builder = BlockMappings.builder();
|
BlockMappings.BlockMappingsBuilder builder = BlockMappings.builder();
|
||||||
while (blocksIterator.hasNext()) {
|
while (blocksIterator.hasNext()) {
|
||||||
javaRuntimeId++;
|
javaRuntimeId++;
|
||||||
|
@ -169,15 +170,16 @@ public class BlockRegistryPopulator {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (javaId.contains("jigsaw")) {
|
||||||
|
jigsawStateIds.add(bedrockRuntimeId);
|
||||||
|
}
|
||||||
|
|
||||||
boolean waterlogged = entry.getKey().contains("waterlogged=true")
|
boolean waterlogged = entry.getKey().contains("waterlogged=true")
|
||||||
|| javaId.contains("minecraft:bubble_column") || javaId.contains("minecraft:kelp") || javaId.contains("seagrass");
|
|| javaId.contains("minecraft:bubble_column") || javaId.contains("minecraft:kelp") || javaId.contains("seagrass");
|
||||||
|
|
||||||
if (waterlogged) {
|
if (waterlogged) {
|
||||||
bedrockToJavaBlockMap.putIfAbsent(bedrockRuntimeId | 1 << 31, javaRuntimeId);
|
|
||||||
int finalJavaRuntimeId = javaRuntimeId;
|
int finalJavaRuntimeId = javaRuntimeId;
|
||||||
BlockRegistries.WATERLOGGED.register(set -> set.add(finalJavaRuntimeId));
|
BlockRegistries.WATERLOGGED.register(set -> set.add(finalJavaRuntimeId));
|
||||||
} else {
|
|
||||||
bedrockToJavaBlockMap.putIfAbsent(bedrockRuntimeId, javaRuntimeId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String cleanJavaIdentifier = BlockUtils.getCleanIdentifier(entry.getKey());
|
String cleanJavaIdentifier = BlockUtils.getCleanIdentifier(entry.getKey());
|
||||||
|
@ -221,10 +223,10 @@ public class BlockRegistryPopulator {
|
||||||
BlockRegistries.BLOCKS.register(PALETTE_VERSIONS.getInt(palette.getKey()), builder.blockStateVersion(stateVersion)
|
BlockRegistries.BLOCKS.register(PALETTE_VERSIONS.getInt(palette.getKey()), builder.blockStateVersion(stateVersion)
|
||||||
.emptyChunkSection(new ChunkSection(new BlockStorage[]{new BlockStorage(airRuntimeId)}))
|
.emptyChunkSection(new ChunkSection(new BlockStorage[]{new BlockStorage(airRuntimeId)}))
|
||||||
.javaToBedrockBlockMap(javaToBedrockBlockMap.toIntArray())
|
.javaToBedrockBlockMap(javaToBedrockBlockMap.toIntArray())
|
||||||
.bedrockToJavaBlockMap(bedrockToJavaBlockMap)
|
|
||||||
.javaIdentifierToBedrockTag(javaIdentifierToBedrockTag)
|
.javaIdentifierToBedrockTag(javaIdentifierToBedrockTag)
|
||||||
.itemFrames(itemFrames)
|
.itemFrames(itemFrames)
|
||||||
.flowerPotBlocks(flowerPotBlocks)
|
.flowerPotBlocks(flowerPotBlocks)
|
||||||
|
.jigsawStateIds(jigsawStateIds)
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -239,6 +241,8 @@ public class BlockRegistryPopulator {
|
||||||
throw new AssertionError("Unable to load Java block mappings", e);
|
throw new AssertionError("Unable to load Java block mappings", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BlockRegistries.JAVA_BLOCKS.set(new BlockMapping[blocksJson.size()]); // Set array size to number of blockstates
|
||||||
|
|
||||||
Set<String> cleanIdentifiers = new HashSet<>();
|
Set<String> cleanIdentifiers = new HashSet<>();
|
||||||
|
|
||||||
int javaRuntimeId = -1;
|
int javaRuntimeId = -1;
|
||||||
|
|
|
@ -27,7 +27,7 @@ package org.geysermc.connector.registry.type;
|
||||||
|
|
||||||
import com.nukkitx.nbt.NbtList;
|
import com.nukkitx.nbt.NbtList;
|
||||||
import com.nukkitx.nbt.NbtMap;
|
import com.nukkitx.nbt.NbtMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
|
@ -46,7 +46,6 @@ public class BlockMappings {
|
||||||
ChunkSection emptyChunkSection;
|
ChunkSection emptyChunkSection;
|
||||||
|
|
||||||
int[] javaToBedrockBlockMap;
|
int[] javaToBedrockBlockMap;
|
||||||
Int2IntMap bedrockToJavaBlockMap;
|
|
||||||
|
|
||||||
NbtList<NbtMap> bedrockBlockStates;
|
NbtList<NbtMap> bedrockBlockStates;
|
||||||
|
|
||||||
|
@ -61,6 +60,8 @@ public class BlockMappings {
|
||||||
Object2IntMap<NbtMap> itemFrames;
|
Object2IntMap<NbtMap> itemFrames;
|
||||||
Map<String, NbtMap> flowerPotBlocks;
|
Map<String, NbtMap> flowerPotBlocks;
|
||||||
|
|
||||||
|
IntSet jigsawStateIds;
|
||||||
|
|
||||||
public int getBedrockBlockId(int state) {
|
public int getBedrockBlockId(int state) {
|
||||||
if (state >= this.javaToBedrockBlockMap.length) {
|
if (state >= this.javaToBedrockBlockMap.length) {
|
||||||
return bedrockAirId;
|
return bedrockAirId;
|
||||||
|
@ -68,10 +69,6 @@ public class BlockMappings {
|
||||||
return this.javaToBedrockBlockMap[state];
|
return this.javaToBedrockBlockMap[state];
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getJavaBlockState(int bedrockId) {
|
|
||||||
return this.bedrockToJavaBlockMap.get(bedrockId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getItemFrame(NbtMap tag) {
|
public int getItemFrame(NbtMap tag) {
|
||||||
return this.itemFrames.getOrDefault(tag, -1);
|
return this.itemFrames.getOrDefault(tag, -1);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue