Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-12-26 08:10:11 +01:00
Replace BiMap with an Object2IntBiMap
Dieser Commit ist enthalten in:
Ursprung
fde36a2234
Commit
b4921132e1
@ -114,7 +114,7 @@ public class VillagerEntity extends AbstractMerchantEntity {
|
|||||||
if (bedPosition != null) {
|
if (bedPosition != null) {
|
||||||
bedId = session.getConnector().getWorldManager().getBlockAt(session, bedPosition);
|
bedId = session.getConnector().getWorldManager().getBlockAt(session, bedPosition);
|
||||||
}
|
}
|
||||||
String bedRotationZ = BlockRegistries.JAVA_IDENTIFIERS.get().inverse().get(bedId);
|
String bedRotationZ = BlockRegistries.JAVA_IDENTIFIERS.get().get(bedId);
|
||||||
setRotation(rotation);
|
setRotation(rotation);
|
||||||
setOnGround(isOnGround);
|
setOnGround(isOnGround);
|
||||||
this.position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ);
|
this.position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ);
|
||||||
|
@ -232,7 +232,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||||||
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());
|
int blockState = session.getBlockMappings().getJavaBlockState(packet.getBlockRuntimeId());
|
||||||
String blockName = BlockRegistries.JAVA_IDENTIFIERS.get().inverse().getOrDefault(blockState, "");
|
String blockName = BlockRegistries.JAVA_IDENTIFIERS.get().getOrDefault(blockState, "");
|
||||||
// In the future this can be used for structure blocks too, however not all elements
|
// In the future this can be used for structure blocks too, however not all elements
|
||||||
// are available in each GUI
|
// are available in each GUI
|
||||||
if (blockName.contains("jigsaw")) {
|
if (blockName.contains("jigsaw")) {
|
||||||
|
@ -178,7 +178,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
|||||||
// Account for fire - the client likes to hit the block behind.
|
// Account for fire - the client likes to hit the block behind.
|
||||||
Vector3i fireBlockPos = BlockUtils.getBlockPosition(packet.getBlockPosition(), packet.getFace());
|
Vector3i fireBlockPos = BlockUtils.getBlockPosition(packet.getBlockPosition(), packet.getFace());
|
||||||
int blockUp = session.getConnector().getWorldManager().getBlockAt(session, fireBlockPos);
|
int blockUp = session.getConnector().getWorldManager().getBlockAt(session, fireBlockPos);
|
||||||
String identifier = BlockRegistries.JAVA_IDENTIFIERS.get().inverse().get(blockUp);
|
String identifier = BlockRegistries.JAVA_IDENTIFIERS.get().get(blockUp);
|
||||||
if (identifier.startsWith("minecraft:fire") || identifier.startsWith("minecraft:soul_fire")) {
|
if (identifier.startsWith("minecraft:fire") || identifier.startsWith("minecraft:soul_fire")) {
|
||||||
ClientPlayerActionPacket startBreakingPacket = new ClientPlayerActionPacket(PlayerAction.START_DIGGING, new Position(fireBlockPos.getX(),
|
ClientPlayerActionPacket startBreakingPacket = new ClientPlayerActionPacket(PlayerAction.START_DIGGING, new Position(fireBlockPos.getX(),
|
||||||
fireBlockPos.getY(), fireBlockPos.getZ()), BlockFace.values()[packet.getFace()]);
|
fireBlockPos.getY(), fireBlockPos.getZ()), BlockFace.values()[packet.getFace()]);
|
||||||
|
@ -77,7 +77,7 @@ public class BlockInventoryHolder extends InventoryHolder {
|
|||||||
if (checkInteractionPosition(session)) {
|
if (checkInteractionPosition(session)) {
|
||||||
// Then, check to see if the interacted block is valid for this inventory by ensuring the block state identifier is valid
|
// Then, check to see if the interacted block is valid for this inventory by ensuring the block state identifier is valid
|
||||||
int javaBlockId = session.getConnector().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition());
|
int javaBlockId = session.getConnector().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition());
|
||||||
String[] javaBlockString = BlockRegistries.JAVA_IDENTIFIERS.get().inverse().getOrDefault(javaBlockId, "minecraft:air").split("\\[");
|
String[] javaBlockString = BlockRegistries.JAVA_IDENTIFIERS.get().getOrDefault(javaBlockId, "minecraft:air").split("\\[");
|
||||||
if (isValidBlock(javaBlockString)) {
|
if (isValidBlock(javaBlockString)) {
|
||||||
// We can safely use this block
|
// We can safely use this block
|
||||||
inventory.setHolderPosition(session.getLastInteractionBlockPosition());
|
inventory.setHolderPosition(session.getLastInteractionBlockPosition());
|
||||||
|
@ -54,7 +54,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
|
|||||||
// See BlockInventoryHolder - same concept there except we're also dealing with a specific block state
|
// See BlockInventoryHolder - same concept there except we're also dealing with a specific block state
|
||||||
if (session.getLastInteractionPlayerPosition().equals(session.getPlayerEntity().getPosition())) {
|
if (session.getLastInteractionPlayerPosition().equals(session.getPlayerEntity().getPosition())) {
|
||||||
int javaBlockId = session.getConnector().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition());
|
int javaBlockId = session.getConnector().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition());
|
||||||
String[] javaBlockString = BlockRegistries.JAVA_IDENTIFIERS.get().inverse().getOrDefault(javaBlockId, "minecraft:air").split("\\[");
|
String[] javaBlockString = BlockRegistries.JAVA_IDENTIFIERS.get().getOrDefault(javaBlockId, "minecraft:air").split("\\[");
|
||||||
if (javaBlockString.length > 1 && (javaBlockString[0].equals("minecraft:chest") || javaBlockString[0].equals("minecraft:trapped_chest"))
|
if (javaBlockString.length > 1 && (javaBlockString[0].equals("minecraft:chest") || javaBlockString[0].equals("minecraft:trapped_chest"))
|
||||||
&& !javaBlockString[1].contains("type=single")) {
|
&& !javaBlockString[1].contains("type=single")) {
|
||||||
inventory.setHolderPosition(session.getLastInteractionBlockPosition());
|
inventory.setHolderPosition(session.getLastInteractionBlockPosition());
|
||||||
|
@ -101,7 +101,7 @@ public class JavaBlockChangeTranslator extends PacketTranslator<ServerBlockChang
|
|||||||
|| lastInteractPos.getZ() != packet.getRecord().getPosition().getZ())) {
|
|| lastInteractPos.getZ() != packet.getRecord().getPosition().getZ())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String identifier = BlockRegistries.JAVA_IDENTIFIERS.get().inverse().get(packet.getRecord().getBlock());
|
String identifier = BlockRegistries.JAVA_IDENTIFIERS.get().get(packet.getRecord().getBlock());
|
||||||
session.setInteracting(false);
|
session.setInteracting(false);
|
||||||
BlockSoundInteractionHandler.handleBlockInteraction(session, lastInteractPos.toFloat(), identifier);
|
BlockSoundInteractionHandler.handleBlockInteraction(session, lastInteractPos.toFloat(), identifier);
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,6 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.registry;
|
package org.geysermc.connector.registry;
|
||||||
|
|
||||||
import com.google.common.collect.BiMap;
|
|
||||||
import com.google.common.collect.HashBiMap;
|
|
||||||
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;
|
||||||
@ -35,6 +33,7 @@ import org.geysermc.connector.registry.loader.RegistryLoaders;
|
|||||||
import org.geysermc.connector.registry.populator.BlockRegistryPopulator;
|
import org.geysermc.connector.registry.populator.BlockRegistryPopulator;
|
||||||
import org.geysermc.connector.registry.type.BlockMapping;
|
import org.geysermc.connector.registry.type.BlockMapping;
|
||||||
import org.geysermc.connector.registry.type.BlockMappings;
|
import org.geysermc.connector.registry.type.BlockMappings;
|
||||||
|
import org.geysermc.connector.utils.Object2IntBiMap;
|
||||||
|
|
||||||
public class BlockRegistries {
|
public class BlockRegistries {
|
||||||
public static final VersionedRegistry<BlockMappings> BLOCKS = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new));
|
public static final VersionedRegistry<BlockMappings> BLOCKS = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new));
|
||||||
@ -43,7 +42,7 @@ public class BlockRegistries {
|
|||||||
|
|
||||||
public static final SimpleMappedRegistry<Integer, BlockMapping> JAVA_BLOCKS = SimpleMappedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new));
|
public static final SimpleMappedRegistry<Integer, BlockMapping> JAVA_BLOCKS = SimpleMappedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new));
|
||||||
|
|
||||||
public static final MappedRegistry<String, Integer, BiMap<String, Integer>> JAVA_IDENTIFIERS = MappedRegistry.create(RegistryLoaders.empty(HashBiMap::create));
|
public static final MappedRegistry<String, Integer, Object2IntBiMap<String>> JAVA_IDENTIFIERS = MappedRegistry.create(RegistryLoaders.empty(Object2IntBiMap::new));
|
||||||
|
|
||||||
public static final SimpleMappedRegistry<Integer, String> JAVA_CLEAN_IDENTIFIERS = SimpleMappedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new));
|
public static final SimpleMappedRegistry<Integer, String> JAVA_CLEAN_IDENTIFIERS = SimpleMappedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new));
|
||||||
|
|
||||||
|
@ -26,10 +26,10 @@
|
|||||||
package org.geysermc.connector.registry.loader;
|
package org.geysermc.connector.registry.loader;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||||
import com.google.common.collect.BiMap;
|
|
||||||
import it.unimi.dsi.fastutil.Pair;
|
import it.unimi.dsi.fastutil.Pair;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
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.objects.Object2IntMap;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
||||||
@ -40,6 +40,7 @@ import org.geysermc.connector.network.translators.collision.translators.OtherCol
|
|||||||
import org.geysermc.connector.network.translators.collision.translators.SolidCollision;
|
import org.geysermc.connector.network.translators.collision.translators.SolidCollision;
|
||||||
import org.geysermc.connector.registry.BlockRegistries;
|
import org.geysermc.connector.registry.BlockRegistries;
|
||||||
import org.geysermc.connector.utils.FileUtils;
|
import org.geysermc.connector.utils.FileUtils;
|
||||||
|
import org.geysermc.connector.utils.Object2IntBiMap;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
@ -71,16 +72,16 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String,
|
|||||||
throw new AssertionError("Unable to load collision data", e);
|
throw new AssertionError("Unable to load collision data", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
BiMap<String, Integer> javaIdBlockMap = BlockRegistries.JAVA_IDENTIFIERS.get();
|
Object2IntBiMap<String> javaIdBlockMap = BlockRegistries.JAVA_IDENTIFIERS.get();
|
||||||
|
|
||||||
// Map of classes that don't change based on parameters that have already been created
|
// Map of classes that don't change based on parameters that have already been created
|
||||||
Map<Class<?>, BlockCollision> instantiatedCollision = new HashMap<>();
|
Map<Class<?>, BlockCollision> instantiatedCollision = new HashMap<>();
|
||||||
for (Map.Entry<String, Integer> entry : javaIdBlockMap.entrySet()) {
|
for (Object2IntMap.Entry<String> entry : javaIdBlockMap.object2IntEntrySet()) {
|
||||||
BlockCollision newCollision = instantiateCollision(entry.getKey(), entry.getValue(), annotationMap, instantiatedCollision, collisionList);
|
BlockCollision newCollision = instantiateCollision(entry.getKey(), entry.getIntValue(), annotationMap, instantiatedCollision, collisionList);
|
||||||
if (newCollision != null) {
|
if (newCollision != null) {
|
||||||
instantiatedCollision.put(newCollision.getClass(), newCollision);
|
instantiatedCollision.put(newCollision.getClass(), newCollision);
|
||||||
}
|
}
|
||||||
collisions.put(entry.getValue().intValue(), newCollision);
|
collisions.put(entry.getIntValue(), newCollision);
|
||||||
}
|
}
|
||||||
return collisions;
|
return collisions;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
* 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.utils;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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