Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-12-26 16:12:46 +01:00
Optimizations and regression fix
Dieser Commit ist enthalten in:
Ursprung
8083f70435
Commit
b6113dfd31
@ -59,7 +59,7 @@ public class GeyserSpigotBlockPlaceListener implements Listener {
|
||||
event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ())));
|
||||
} else {
|
||||
String javaBlockId = event.getBlockPlaced().getBlockData().getAsString();
|
||||
placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIERS.get().getOrDefault(javaBlockId, BlockStateValues.JAVA_AIR_ID)));
|
||||
placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(javaBlockId, BlockStateValues.JAVA_AIR_ID)));
|
||||
}
|
||||
placeBlockSoundPacket.setIdentifier(":");
|
||||
session.sendUpstreamPacket(placeBlockSoundPacket);
|
||||
|
@ -82,9 +82,9 @@ public class GeyserSpigotWorldManager extends WorldManager {
|
||||
// Terrible behavior, but this is basically what's always been happening behind the scenes anyway.
|
||||
CompletableFuture<String> blockData = new CompletableFuture<>();
|
||||
Bukkit.getRegionScheduler().execute(this.plugin, block.getLocation(), () -> blockData.complete(block.getBlockData().getAsString()));
|
||||
return BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(blockData.join(), BlockStateValues.JAVA_AIR_ID);
|
||||
return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(blockData.join(), BlockStateValues.JAVA_AIR_ID);
|
||||
}
|
||||
return BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(block.getBlockData().getAsString(), BlockStateValues.JAVA_AIR_ID);
|
||||
return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(block.getBlockData().getAsString(), BlockStateValues.JAVA_AIR_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -31,7 +31,6 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.github.steveice10.packetlib.tcp.TcpSession;
|
||||
import io.netty.channel.epoll.Epoll;
|
||||
import io.netty.channel.kqueue.KQueue;
|
||||
import io.netty.util.NettyRuntime;
|
||||
import io.netty.util.concurrent.DefaultThreadFactory;
|
||||
import io.netty.util.internal.SystemPropertyUtil;
|
||||
@ -312,13 +311,13 @@ public class GeyserImpl implements GeyserApi {
|
||||
}
|
||||
|
||||
if (shouldStartListener) {
|
||||
try {
|
||||
this.geyserServer = new GeyserServer(this, bedrockThreadCount);
|
||||
this.geyserServer.bind(new InetSocketAddress(config.getBedrock().address(), config.getBedrock().port()));
|
||||
|
||||
this.geyserServer.bind(new InetSocketAddress(config.getBedrock().address(), config.getBedrock().port()))
|
||||
.whenComplete((avoid, throwable) -> {
|
||||
if (throwable == null) {
|
||||
logger.info(GeyserLocale.getLocaleStringLog("geyser.core.start", config.getBedrock().address(),
|
||||
String.valueOf(config.getBedrock().port())));
|
||||
} catch (Throwable t) {
|
||||
} else {
|
||||
String address = config.getBedrock().address();
|
||||
int port = config.getBedrock().port();
|
||||
logger.severe(GeyserLocale.getLocaleStringLog("geyser.core.fail", address, String.valueOf(port)));
|
||||
@ -327,6 +326,7 @@ public class GeyserImpl implements GeyserApi {
|
||||
logger.info(Component.text("Then, restart this server.", NamedTextColor.GREEN));
|
||||
}
|
||||
}
|
||||
}).join();
|
||||
}
|
||||
|
||||
if (config.getRemote().authType() == AuthType.FLOODGATE) {
|
||||
|
@ -56,7 +56,6 @@ import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.util.AttributeUtils;
|
||||
import org.geysermc.geyser.util.ChunkUtils;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
|
||||
import java.util.*;
|
||||
@ -127,17 +126,8 @@ public class LivingEntity extends Entity {
|
||||
if (optionalPos.isPresent()) {
|
||||
Vector3i bedPosition = optionalPos.get();
|
||||
dirtyMetadata.put(EntityDataTypes.BED_POSITION, bedPosition);
|
||||
int bed = session.getGeyser().getWorldManager().getBlockAt(session, bedPosition);
|
||||
// Bed has to be updated, or else player is floating in the air
|
||||
ChunkUtils.updateBlock(session, bed, bedPosition);
|
||||
// Indicate that the player should enter the sleep cycle
|
||||
// Has to be a byte or it does not work
|
||||
// (Bed position is what actually triggers sleep - "pose" is only optional)
|
||||
dirtyMetadata.put(EntityDataTypes.PLAYER_FLAGS, (byte) 2);
|
||||
return bedPosition;
|
||||
} else {
|
||||
// Player is no longer sleeping
|
||||
dirtyMetadata.put(EntityDataTypes.PLAYER_FLAGS, (byte) 0);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -27,14 +27,15 @@ package org.geysermc.geyser.entity.type.living.merchant;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData;
|
||||
import lombok.Getter;
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.registry.BlockRegistries;
|
||||
import org.geysermc.geyser.registry.type.BlockMapping;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
import java.util.Optional;
|
||||
@ -117,7 +118,7 @@ public class VillagerEntity extends AbstractMerchantEntity {
|
||||
|
||||
// The bed block
|
||||
int blockId = session.getGeyser().getWorldManager().getBlockAt(session, bedPosition);
|
||||
String fullIdentifier = BlockRegistries.JAVA_IDENTIFIERS.get().get(blockId);
|
||||
String fullIdentifier = BlockRegistries.JAVA_BLOCKS.getOrDefault(blockId, BlockMapping.AIR).getJavaIdentifier();
|
||||
|
||||
// Set the correct position offset and rotation when sleeping
|
||||
int bedRotation = 0;
|
||||
|
@ -38,20 +38,12 @@ import lombok.Setter;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
import org.cloudburstmc.protocol.bedrock.data.Ability;
|
||||
import org.cloudburstmc.protocol.bedrock.data.AbilityLayer;
|
||||
import org.cloudburstmc.protocol.bedrock.data.AttributeData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.GameType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.PlayerPermission;
|
||||
import org.cloudburstmc.protocol.bedrock.data.*;
|
||||
import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.AddPlayerPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.*;
|
||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
import org.geysermc.geyser.entity.type.LivingEntity;
|
||||
@ -62,6 +54,7 @@ import org.geysermc.geyser.scoreboard.Team;
|
||||
import org.geysermc.geyser.scoreboard.UpdateType;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.geyser.util.ChunkUtils;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collections;
|
||||
@ -248,8 +241,25 @@ public class PlayerEntity extends LivingEntity {
|
||||
@Override
|
||||
public Vector3i setBedPosition(EntityMetadata<Optional<Vector3i>, ?> entityMetadata) {
|
||||
bedPosition = super.setBedPosition(entityMetadata);
|
||||
if (bedPosition != null) {
|
||||
// Required to sync position of entity to bed
|
||||
// Fixes https://github.com/GeyserMC/Geyser/issues/3595 on vanilla 1.19.3 servers - did not happen on Paper
|
||||
entityMetadata.getValue().ifPresent(pos -> this.setPosition(pos.toFloat()));
|
||||
this.setPosition(bedPosition.toFloat());
|
||||
|
||||
// TODO evaluate if needed
|
||||
int bed = session.getGeyser().getWorldManager().getBlockAt(session, bedPosition);
|
||||
// Bed has to be updated, or else player is floating in the air
|
||||
ChunkUtils.updateBlock(session, bed, bedPosition);
|
||||
|
||||
// Indicate that the player should enter the sleep cycle
|
||||
// Has to be a byte or it does not work
|
||||
// (Bed position is what actually triggers sleep - "pose" is only optional)
|
||||
dirtyMetadata.put(EntityDataTypes.PLAYER_FLAGS, (byte) 2);
|
||||
} else {
|
||||
// Player is no longer sleeping
|
||||
dirtyMetadata.put(EntityDataTypes.PLAYER_FLAGS, (byte) 0);
|
||||
return null;
|
||||
}
|
||||
return bedPosition;
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@ import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.registry.BlockRegistries;
|
||||
import org.geysermc.geyser.registry.type.BlockMapping;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.geyser.util.BlockUtils;
|
||||
@ -57,7 +58,7 @@ public class BlockInventoryHolder extends InventoryHolder {
|
||||
private final Set<String> validBlocks;
|
||||
|
||||
public BlockInventoryHolder(String javaBlockIdentifier, ContainerType containerType, String... validBlocks) {
|
||||
this.defaultJavaBlockState = BlockRegistries.JAVA_IDENTIFIERS.get(javaBlockIdentifier);
|
||||
this.defaultJavaBlockState = BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getInt(javaBlockIdentifier);
|
||||
this.containerType = containerType;
|
||||
if (validBlocks != null) {
|
||||
Set<String> validBlocksTemp = new HashSet<>(validBlocks.length + 1);
|
||||
@ -77,7 +78,7 @@ public class BlockInventoryHolder extends InventoryHolder {
|
||||
if (checkInteractionPosition(session)) {
|
||||
// Then, check to see if the interacted block is valid for this inventory by ensuring the block state identifier is valid
|
||||
int javaBlockId = session.getGeyser().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition());
|
||||
String[] javaBlockString = BlockRegistries.JAVA_IDENTIFIERS.get().getOrDefault(javaBlockId, "minecraft:air").split("\\[");
|
||||
String[] javaBlockString = BlockRegistries.JAVA_BLOCKS.getOrDefault(javaBlockId, BlockMapping.AIR).getJavaIdentifier().split("\\[");
|
||||
if (isValidBlock(javaBlockString)) {
|
||||
// We can safely use this block
|
||||
inventory.setHolderPosition(session.getLastInteractionBlockPosition());
|
||||
|
@ -468,7 +468,7 @@ public final class BlockStateValues {
|
||||
*/
|
||||
public static double getWaterHeight(int state) {
|
||||
int waterLevel = BlockStateValues.getWaterLevel(state);
|
||||
if (BlockRegistries.WATERLOGGED.get().contains(state)) {
|
||||
if (BlockRegistries.WATERLOGGED.get().get(state)) {
|
||||
waterLevel = 0;
|
||||
}
|
||||
if (waterLevel >= 0) {
|
||||
|
@ -27,7 +27,6 @@ package org.geysermc.geyser.network.netty;
|
||||
|
||||
import com.github.steveice10.packetlib.helper.TransportHelper;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.epoll.Epoll;
|
||||
@ -54,7 +53,8 @@ import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.function.Function;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.IntFunction;
|
||||
|
||||
public final class GeyserServer {
|
||||
private static final boolean PRINT_DEBUG_PINGS = Boolean.parseBoolean(System.getProperty("Geyser.PrintPingsInDebugMode", "true"));
|
||||
@ -76,7 +76,6 @@ public final class GeyserServer {
|
||||
private final ServerBootstrap bootstrap;
|
||||
|
||||
private ChannelFuture future;
|
||||
private Channel channel;
|
||||
|
||||
public GeyserServer(GeyserImpl geyser, int threadCount) {
|
||||
this.geyser = geyser;
|
||||
@ -85,12 +84,19 @@ public final class GeyserServer {
|
||||
this.bootstrap = this.createBootstrap(this.group);
|
||||
}
|
||||
|
||||
public void bind(InetSocketAddress address) {
|
||||
this.future = this.bootstrap.bind(address).syncUninterruptibly();
|
||||
this.channel = this.future.channel();
|
||||
public CompletableFuture<Void> bind(InetSocketAddress address) {
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
this.future = this.bootstrap.bind(address).addListener(bindResult -> {
|
||||
if (bindResult.cause() != null) {
|
||||
future.completeExceptionally(bindResult.cause());
|
||||
return;
|
||||
}
|
||||
future.complete(null);
|
||||
});
|
||||
|
||||
// Add our ping handler
|
||||
this.channel.pipeline().addAfter(RakServerOfflineHandler.NAME, RakPingHandler.NAME, new RakPingHandler(this));
|
||||
this.future.channel().pipeline().addAfter(RakServerOfflineHandler.NAME, RakPingHandler.NAME, new RakPingHandler(this));
|
||||
return future;
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
@ -219,6 +225,6 @@ public final class GeyserServer {
|
||||
return new Transport(NioDatagramChannel.class, NioEventLoopGroup::new);
|
||||
}
|
||||
|
||||
private record Transport(Class<? extends DatagramChannel> datagramChannel, Function<Integer, EventLoopGroup> eventLoopGroupFactory) {
|
||||
private record Transport(Class<? extends DatagramChannel> datagramChannel, IntFunction<EventLoopGroup> eventLoopGroupFactory) {
|
||||
}
|
||||
}
|
||||
|
@ -26,14 +26,15 @@
|
||||
package org.geysermc.geyser.registry;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
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.Object2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import org.geysermc.geyser.registry.loader.RegistryLoaders;
|
||||
import org.geysermc.geyser.registry.populator.BlockRegistryPopulator;
|
||||
import org.geysermc.geyser.registry.type.BlockMapping;
|
||||
import org.geysermc.geyser.registry.type.BlockMappings;
|
||||
import org.geysermc.geyser.util.collection.Object2IntBiMap;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
/**
|
||||
* Holds all the block registries in Geyser.
|
||||
@ -54,33 +55,33 @@ public class BlockRegistries {
|
||||
* A registry which stores Java IDs to {@link BlockMapping}, containing miscellaneous information about
|
||||
* blocks and their behavior in many cases.
|
||||
*/
|
||||
public static final ArrayRegistry<BlockMapping> JAVA_BLOCKS = ArrayRegistry.create(RegistryLoaders.empty(() -> new BlockMapping[] {}));
|
||||
public static final ArrayRegistry<BlockMapping> JAVA_BLOCKS = ArrayRegistry.create(RegistryLoaders.uninitialized());
|
||||
|
||||
/**
|
||||
* A (bi)mapped registry containing the Java IDs to identifiers.
|
||||
* A mapped registry containing the Java identifiers to IDs.
|
||||
*/
|
||||
public static final MappedRegistry<String, Integer, Object2IntBiMap<String>> JAVA_IDENTIFIERS = MappedRegistry.create(RegistryLoaders.empty(Object2IntBiMap::new));
|
||||
public static final MappedRegistry<String, Integer, Object2IntMap<String>> JAVA_IDENTIFIER_TO_ID = MappedRegistry.create(RegistryLoaders.empty(Object2IntOpenHashMap::new));
|
||||
|
||||
/**
|
||||
* A registry which stores unique Java IDs to its clean identifier
|
||||
* This is used in the statistics form.
|
||||
*/
|
||||
public static final ArrayRegistry<String> CLEAN_JAVA_IDENTIFIERS = ArrayRegistry.create(RegistryLoaders.empty(() -> new String[] {}));
|
||||
public static final ArrayRegistry<String> CLEAN_JAVA_IDENTIFIERS = ArrayRegistry.create(RegistryLoaders.uninitialized());
|
||||
|
||||
/**
|
||||
* A registry containing all the waterlogged blockstates.
|
||||
*/
|
||||
public static final SimpleRegistry<IntSet> WATERLOGGED = SimpleRegistry.create(RegistryLoaders.empty(IntOpenHashSet::new));
|
||||
public static final SimpleRegistry<BitSet> WATERLOGGED = SimpleRegistry.create(RegistryLoaders.empty(BitSet::new));
|
||||
|
||||
/**
|
||||
* A registry containing all blockstates which are always interactive.
|
||||
*/
|
||||
public static final SimpleRegistry<IntSet> INTERACTIVE = SimpleRegistry.create(RegistryLoaders.empty(IntOpenHashSet::new));
|
||||
public static final SimpleRegistry<BitSet> INTERACTIVE = SimpleRegistry.create(RegistryLoaders.uninitialized());
|
||||
|
||||
/**
|
||||
* A registry containing all blockstates which are interactive if the player has the may build permission.
|
||||
*/
|
||||
public static final SimpleRegistry<IntSet> INTERACTIVE_MAY_BUILD = SimpleRegistry.create(RegistryLoaders.empty(IntOpenHashSet::new));
|
||||
public static final SimpleRegistry<BitSet> INTERACTIVE_MAY_BUILD = SimpleRegistry.create(RegistryLoaders.uninitialized());
|
||||
|
||||
static {
|
||||
BlockRegistryPopulator.populate();
|
||||
|
@ -25,12 +25,14 @@
|
||||
|
||||
package org.geysermc.geyser.registry.loader;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Holds common {@link RegistryLoader}s or utility methods surrounding them.
|
||||
*/
|
||||
public class RegistryLoaders {
|
||||
public final class RegistryLoaders {
|
||||
/**
|
||||
* The {@link RegistryLoader} responsible for loading NBT.
|
||||
*/
|
||||
@ -44,7 +46,18 @@ public class RegistryLoaders {
|
||||
* @param <V> the value
|
||||
* @return a RegistryLoader wrapping the given Supplier
|
||||
*/
|
||||
public static <V> RegistryLoader<Object, V> empty(Supplier<V> supplier) {
|
||||
public static <V> RegistryLoader<Object, V> empty(@NonNull Supplier<V> supplier) {
|
||||
return input -> supplier.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <V> the value
|
||||
* @return a RegistryLoader that is yet to contain a value.
|
||||
*/
|
||||
public static <V> RegistryLoader<Object, V> uninitialized() {
|
||||
return input -> null;
|
||||
}
|
||||
|
||||
private RegistryLoaders() {
|
||||
}
|
||||
}
|
@ -28,8 +28,6 @@ package org.geysermc.geyser.registry.populator;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import it.unimi.dsi.fastutil.objects.*;
|
||||
import org.cloudburstmc.nbt.*;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v544.Bedrock_v544;
|
||||
@ -160,7 +158,7 @@ public final class BlockRegistryPopulator {
|
||||
|
||||
if (waterlogged) {
|
||||
int finalJavaRuntimeId = javaRuntimeId;
|
||||
BlockRegistries.WATERLOGGED.register(set -> set.add(finalJavaRuntimeId));
|
||||
BlockRegistries.WATERLOGGED.register(set -> set.set(finalJavaRuntimeId));
|
||||
}
|
||||
|
||||
String cleanJavaIdentifier = BlockUtils.getCleanIdentifier(entry.getKey());
|
||||
@ -296,7 +294,7 @@ public final class BlockRegistryPopulator {
|
||||
builder.javaIdentifier(javaId);
|
||||
builder.javaBlockId(uniqueJavaId);
|
||||
|
||||
BlockRegistries.JAVA_IDENTIFIERS.register(javaId, javaRuntimeId);
|
||||
BlockRegistries.JAVA_IDENTIFIER_TO_ID.register(javaId, javaRuntimeId);
|
||||
BlockRegistries.JAVA_BLOCKS.register(javaRuntimeId, builder.build());
|
||||
|
||||
// Keeping this here since this is currently unchanged between versions
|
||||
@ -375,10 +373,10 @@ public final class BlockRegistryPopulator {
|
||||
BlockRegistries.INTERACTIVE_MAY_BUILD.set(toBlockStateSet((ArrayNode) blockInteractionsJson.get("requires_may_build")));
|
||||
}
|
||||
|
||||
private static IntSet toBlockStateSet(ArrayNode node) {
|
||||
IntSet blockStateSet = new IntOpenHashSet(node.size());
|
||||
private static BitSet toBlockStateSet(ArrayNode node) {
|
||||
BitSet blockStateSet = new BitSet(node.size());
|
||||
for (JsonNode javaIdentifier : node) {
|
||||
blockStateSet.add(BlockRegistries.JAVA_IDENTIFIERS.get().getInt(javaIdentifier.textValue()));
|
||||
blockStateSet.set(BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getInt(javaIdentifier.textValue()));
|
||||
}
|
||||
return blockStateSet;
|
||||
}
|
||||
@ -392,8 +390,9 @@ public final class BlockRegistryPopulator {
|
||||
NbtMapBuilder statesBuilder = NbtMap.builder();
|
||||
|
||||
// check for states
|
||||
if (node.has("bedrock_states")) {
|
||||
Iterator<Map.Entry<String, JsonNode>> statesIterator = node.get("bedrock_states").fields();
|
||||
JsonNode states = node.get("bedrock_states");
|
||||
if (states != null) {
|
||||
Iterator<Map.Entry<String, JsonNode>> statesIterator = states.fields();
|
||||
|
||||
while (statesIterator.hasNext()) {
|
||||
Map.Entry<String, JsonNode> stateEntry = statesIterator.next();
|
||||
|
@ -39,6 +39,7 @@ import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||
import org.geysermc.geyser.level.block.DoubleChestValue;
|
||||
import org.geysermc.geyser.registry.BlockRegistries;
|
||||
import org.geysermc.geyser.registry.type.BlockMapping;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.level.block.entity.DoubleChestBlockEntityTranslator;
|
||||
import org.geysermc.geyser.util.InventoryUtils;
|
||||
@ -48,7 +49,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
|
||||
|
||||
public DoubleChestInventoryTranslator(int size) {
|
||||
super(size, 54);
|
||||
this.defaultJavaBlockState = BlockRegistries.JAVA_IDENTIFIERS.get("minecraft:chest[facing=north,type=single,waterlogged=false]");
|
||||
this.defaultJavaBlockState = BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getInt("minecraft:chest[facing=north,type=single,waterlogged=false]");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -56,7 +57,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
|
||||
// See BlockInventoryHolder - same concept there except we're also dealing with a specific block state
|
||||
if (session.getLastInteractionPlayerPosition().equals(session.getPlayerEntity().getPosition())) {
|
||||
int javaBlockId = session.getGeyser().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition());
|
||||
String[] javaBlockString = BlockRegistries.JAVA_IDENTIFIERS.get().getOrDefault(javaBlockId, "minecraft:air").split("\\[");
|
||||
String[] javaBlockString = BlockRegistries.JAVA_BLOCKS.getOrDefault(javaBlockId, BlockMapping.AIR).getJavaIdentifier().split("\\[");
|
||||
if (javaBlockString.length > 1 && (javaBlockString[0].equals("minecraft:chest") || javaBlockString[0].equals("minecraft:trapped_chest"))
|
||||
&& !javaBlockString[1].contains("type=single")) {
|
||||
inventory.setHolderPosition(session.getLastInteractionBlockPosition());
|
||||
|
@ -32,15 +32,9 @@ import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemOnPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.*;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import org.cloudburstmc.math.vector.Vector3d;
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
@ -50,7 +44,6 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.InventoryActionData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.InventorySource;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.LegacySetItemSlotData;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventoryTransactionPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
|
||||
@ -506,7 +499,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
UpdateBlockPacket updateWaterPacket = new UpdateBlockPacket();
|
||||
updateWaterPacket.setDataLayer(1);
|
||||
updateWaterPacket.setBlockPosition(blockPos);
|
||||
updateWaterPacket.setDefinition(BlockRegistries.WATERLOGGED.get().contains(javaBlockState) ? session.getBlockMappings().getBedrockWater() : session.getBlockMappings().getBedrockAir());
|
||||
updateWaterPacket.setDefinition(BlockRegistries.WATERLOGGED.get().get(javaBlockState) ? session.getBlockMappings().getBedrockWater() : session.getBlockMappings().getBedrockAir());
|
||||
updateWaterPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
||||
session.sendUpstreamPacket(updateWaterPacket);
|
||||
|
||||
@ -553,12 +546,12 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
}
|
||||
// Check if the player is interacting with a block
|
||||
if (!session.isSneaking()) {
|
||||
if (BlockRegistries.INTERACTIVE.get().contains(blockState)) {
|
||||
if (BlockRegistries.INTERACTIVE.get().get(blockState)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean mayBuild = session.getGameMode() == GameMode.SURVIVAL || session.getGameMode() == GameMode.CREATIVE;
|
||||
if (mayBuild && BlockRegistries.INTERACTIVE_MAY_BUILD.get().contains(blockState)) {
|
||||
if (mayBuild && BlockRegistries.INTERACTIVE_MAY_BUILD.get().get(blockState)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ import org.geysermc.geyser.entity.type.ItemFrameEntity;
|
||||
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
|
||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||
import org.geysermc.geyser.registry.BlockRegistries;
|
||||
import org.geysermc.geyser.registry.type.BlockMapping;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
@ -163,7 +164,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
||||
// Account for fire - the client likes to hit the block behind.
|
||||
Vector3i fireBlockPos = BlockUtils.getBlockPosition(vector, packet.getFace());
|
||||
int blockUp = session.getGeyser().getWorldManager().getBlockAt(session, fireBlockPos);
|
||||
String identifier = BlockRegistries.JAVA_IDENTIFIERS.get().get(blockUp);
|
||||
String identifier = BlockRegistries.JAVA_BLOCKS.getOrDefault(blockUp, BlockMapping.AIR).getJavaIdentifier();
|
||||
if (identifier.startsWith("minecraft:fire") || identifier.startsWith("minecraft:soul_fire")) {
|
||||
ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING, fireBlockPos,
|
||||
Direction.VALUES[packet.getFace()], session.getWorldCache().nextPredictionSequence());
|
||||
|
@ -31,6 +31,7 @@ import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.geyser.registry.BlockRegistries;
|
||||
import org.geysermc.geyser.registry.type.BlockMapping;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
@ -99,7 +100,7 @@ public class JavaBlockUpdateTranslator extends PacketTranslator<ClientboundBlock
|
||||
|| lastInteractPos.getZ() != packet.getEntry().getPosition().getZ())) {
|
||||
return;
|
||||
}
|
||||
String identifier = BlockRegistries.JAVA_IDENTIFIERS.get().get(packet.getEntry().getBlock());
|
||||
String identifier = BlockRegistries.JAVA_BLOCKS.getOrDefault(packet.getEntry().getBlock(), BlockMapping.AIR).getJavaIdentifier();
|
||||
session.setInteracting(false);
|
||||
BlockSoundInteractionTranslator.handleBlockInteraction(session, lastInteractPos.toFloat(), identifier);
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
|
||||
int xzy = indexYZXtoXZY(yzx);
|
||||
section.getBlockStorageArray()[0].setFullBlock(xzy, bedrockId);
|
||||
|
||||
if (BlockRegistries.WATERLOGGED.get().contains(javaId)) {
|
||||
if (BlockRegistries.WATERLOGGED.get().get(javaId)) {
|
||||
section.getBlockStorageArray()[1].setFullBlock(xzy, session.getBlockMappings().getBedrockWater().getRuntimeId());
|
||||
}
|
||||
|
||||
@ -160,7 +160,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
|
||||
int bedrockId = session.getBlockMappings().getBedrockBlockId(javaId);
|
||||
BlockStorage blockStorage = new BlockStorage(SingletonBitArray.INSTANCE, IntLists.singleton(bedrockId));
|
||||
|
||||
if (BlockRegistries.WATERLOGGED.get().contains(javaId)) {
|
||||
if (BlockRegistries.WATERLOGGED.get().get(javaId)) {
|
||||
BlockStorage waterlogged = new BlockStorage(SingletonBitArray.INSTANCE, IntLists.singleton(session.getBlockMappings().getBedrockWater()));
|
||||
sections[bedrockSectionY] = new GeyserChunkSection(new BlockStorage[] {blockStorage, waterlogged});
|
||||
} else {
|
||||
@ -179,7 +179,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
|
||||
int javaId = javaPalette.idToState(i);
|
||||
bedrockPalette.add(session.getBlockMappings().getBedrockBlockId(javaId));
|
||||
|
||||
if (BlockRegistries.WATERLOGGED.get().contains(javaId)) {
|
||||
if (BlockRegistries.WATERLOGGED.get().get(javaId)) {
|
||||
waterloggedPaletteIds.set(i);
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ public class GrassPathInteractionTranslator implements BlockSoundInteractionTran
|
||||
levelSoundEventPacket.setRelativeVolumeDisabled(false);
|
||||
levelSoundEventPacket.setIdentifier(":");
|
||||
levelSoundEventPacket.setSound(SoundEvent.ITEM_USE_ON);
|
||||
levelSoundEventPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIERS.get(identifier)));
|
||||
levelSoundEventPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getInt(identifier)));
|
||||
session.sendUpstreamPacket(levelSoundEventPacket);
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ public class HoeInteractionTranslator implements BlockSoundInteractionTranslator
|
||||
levelSoundEventPacket.setRelativeVolumeDisabled(false);
|
||||
levelSoundEventPacket.setIdentifier(":");
|
||||
levelSoundEventPacket.setSound(SoundEvent.ITEM_USE_ON);
|
||||
levelSoundEventPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIERS.get(identifier)));
|
||||
levelSoundEventPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getInt(identifier)));
|
||||
session.sendUpstreamPacket(levelSoundEventPacket);
|
||||
}
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ public class ChunkUtils {
|
||||
UpdateBlockPacket waterPacket = new UpdateBlockPacket();
|
||||
waterPacket.setDataLayer(1);
|
||||
waterPacket.setBlockPosition(position);
|
||||
if (BlockRegistries.WATERLOGGED.get().contains(blockState)) {
|
||||
if (BlockRegistries.WATERLOGGED.get().get(blockState)) {
|
||||
waterPacket.setDefinition(session.getBlockMappings().getBedrockWater());
|
||||
} else {
|
||||
waterPacket.setDefinition(session.getBlockMappings().getBedrockAir());
|
||||
|
@ -154,7 +154,7 @@ public final class SoundUtils {
|
||||
soundPacket.setExtraData(soundMapping.getExtraData() + (int)(Math.round((Math.log10(pitch) / Math.log10(2)) * 12)) + 12);
|
||||
} else if (sound == SoundEvent.PLACE && soundMapping.getExtraData() == -1) {
|
||||
if (!soundMapping.getIdentifier().equals(":")) {
|
||||
int javaId = BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(soundMapping.getIdentifier(), BlockStateValues.JAVA_AIR_ID);
|
||||
int javaId = BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(soundMapping.getIdentifier(), BlockStateValues.JAVA_AIR_ID);
|
||||
soundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(javaId));
|
||||
} else {
|
||||
session.getGeyser().getLogger().debug("PLACE sound mapping identifier was invalid! Please report: " + soundMapping);
|
||||
|
@ -1,200 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2022 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.geyser.util.collection;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntCollection;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSets;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A primitive int BiMap implementation built around fastutil to
|
||||
* reduce boxing and the memory footprint. Protocol has a
|
||||
* {@link org.cloudburstmc.protocol.common.util.Int2ObjectBiMap} class, but it
|
||||
* does not extend the Map interface making it difficult to utilize
|
||||
* it in for loops and the registry system.
|
||||
*
|
||||
* @param <T> the value
|
||||
*/
|
||||
public class Object2IntBiMap<T> implements Object2IntMap<T> {
|
||||
private final Object2IntMap<T> forwards;
|
||||
private final Int2ObjectMap<T> backwards;
|
||||
|
||||
public Object2IntBiMap() {
|
||||
this(16);
|
||||
}
|
||||
|
||||
public Object2IntBiMap(int expected) {
|
||||
this(expected, 0.75F);
|
||||
}
|
||||
|
||||
public Object2IntBiMap(T defaultForwardsValue) {
|
||||
this(16, 0.75F, defaultForwardsValue, -1);
|
||||
}
|
||||
|
||||
public Object2IntBiMap(int expected, float loadFactor) {
|
||||
this(expected, loadFactor, -1);
|
||||
}
|
||||
|
||||
public Object2IntBiMap(int expected, float loadFactor, int defaultBackwardsValue) {
|
||||
this(expected, loadFactor, null, defaultBackwardsValue);
|
||||
}
|
||||
|
||||
public Object2IntBiMap(int expected, float loadFactor, T defaultForwardsValue, int defaultBackwardsValue) {
|
||||
this.forwards = new Object2IntOpenHashMap<>(expected, loadFactor);
|
||||
this.backwards = new Int2ObjectOpenHashMap<>(expected, loadFactor);
|
||||
this.forwards.defaultReturnValue(defaultBackwardsValue);
|
||||
this.backwards.defaultReturnValue(defaultForwardsValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.forwards.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.forwards.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(Object o) {
|
||||
return this.forwards.getInt(o);
|
||||
}
|
||||
|
||||
public T get(int key) {
|
||||
return this.backwards.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrDefault(Object key, int defaultValue) {
|
||||
return this.forwards.getOrDefault(key, defaultValue);
|
||||
}
|
||||
|
||||
public T getOrDefault(int key, T defaultValue) {
|
||||
return this.backwards.getOrDefault(key, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defaultReturnValue(int i) {
|
||||
this.forwards.defaultReturnValue(i);
|
||||
}
|
||||
|
||||
public void defaultReturnValue(T v) {
|
||||
this.backwards.defaultReturnValue(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int defaultReturnValue() {
|
||||
return this.forwards.defaultReturnValue();
|
||||
}
|
||||
|
||||
public T backwardsDefaultReturnValue() {
|
||||
return this.backwards.defaultReturnValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectSet<Entry<T>> object2IntEntrySet() {
|
||||
return ObjectSets.unmodifiable(this.forwards.object2IntEntrySet());
|
||||
}
|
||||
|
||||
public ObjectSet<Int2ObjectMap.Entry<T>> int2ObjectEntrySet() {
|
||||
return ObjectSets.unmodifiable(this.backwards.int2ObjectEntrySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectSet<T> keySet() {
|
||||
return this.forwards.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntCollection values() {
|
||||
return this.forwards.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object o) {
|
||||
return this.forwards.containsKey(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(int i) {
|
||||
return this.backwards.containsKey(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int put(T key, int value) {
|
||||
this.backwards.put(value, key);
|
||||
return this.forwards.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(@NotNull Map<? extends T, ? extends Integer> m) {
|
||||
this.forwards.putAll(m);
|
||||
for (Map.Entry<? extends T, ? extends Integer> entry : m.entrySet()) {
|
||||
this.backwards.put((int) entry.getValue(), entry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int removeInt(Object key) {
|
||||
if (!this.forwards.containsKey(key)) {
|
||||
return this.defaultReturnValue();
|
||||
}
|
||||
|
||||
int value = this.forwards.getInt(key);
|
||||
if (!this.backwards.containsKey(value)) {
|
||||
return this.defaultReturnValue();
|
||||
};
|
||||
this.backwards.remove(value);
|
||||
return this.forwards.removeInt(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.forwards.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.forwards.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Object2IntBiMap<?> that = (Object2IntBiMap<?>) o;
|
||||
return Objects.equals(this.forwards, that.forwards) && Objects.equals(this.backwards, that.backwards);
|
||||
}
|
||||
}
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren