diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/component/CustomBlockComponents.java b/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/component/CustomBlockComponents.java index 4786bccbe..847205c6a 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/component/CustomBlockComponents.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/component/CustomBlockComponents.java @@ -33,13 +33,14 @@ public interface CustomBlockComponents { BoxComponent selectionBox(); BoxComponent collisionBox(); + String displayName(); String geometry(); @NonNull Map materialInstances(); - Float destroyTime(); + Float destructibleByMining(); Float friction(); @@ -62,7 +63,7 @@ public interface CustomBlockComponents { Builder materialInstance(@NonNull String name, @NonNull MaterialInstance materialInstance); - Builder destroyTime(Float destroyTime); + Builder destructibleByMining(Float destructibleByMining); Builder friction(Float friction); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/GeyserCustomBlockComponents.java b/core/src/main/java/org/geysermc/geyser/level/block/GeyserCustomBlockComponents.java index 42197a8cc..7af10c335 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/GeyserCustomBlockComponents.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/GeyserCustomBlockComponents.java @@ -25,12 +25,8 @@ package org.geysermc.geyser.level.block; -import com.google.common.collect.ImmutableSet; -import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import lombok.Value; +import java.util.Map; + import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.api.block.custom.component.BoxComponent; import org.geysermc.geyser.api.block.custom.component.CustomBlockComponents; @@ -38,8 +34,11 @@ import org.geysermc.geyser.api.block.custom.component.MaterialInstance; import org.geysermc.geyser.api.block.custom.component.RotationComponent; import org.jetbrains.annotations.NotNull; -import java.util.Map; -import java.util.Set; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import lombok.Value; @Value public class GeyserCustomBlockComponents implements CustomBlockComponents { @@ -48,7 +47,7 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents { String displayName; String geometry; Map materialInstances; - Float destroyTime; + Float destructibleByMining; Float friction; Integer lightEmission; Integer lightDampening; @@ -65,7 +64,7 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents { } else { this.materialInstances = Object2ObjectMaps.unmodifiable(new Object2ObjectArrayMap<>(builder.materialInstances)); } - this.destroyTime = builder.destroyTime; + this.destructibleByMining = builder.destructibleByMining; this.friction = builder.friction; this.lightEmission = builder.lightEmission; this.lightDampening = builder.lightDampening; @@ -99,8 +98,8 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents { } @Override - public Float destroyTime() { - return destroyTime; + public Float destructibleByMining() { + return destructibleByMining; } @Override @@ -134,7 +133,7 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents { protected String displayName; protected String geometry; protected final Object2ObjectMap materialInstances = new Object2ObjectOpenHashMap<>(); - protected Float destroyTime; + protected Float destructibleByMining; protected Float friction; protected Integer lightEmission; protected Integer lightDampening; @@ -192,11 +191,11 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents { } @Override - public Builder destroyTime(Float destroyTime) { - if (destroyTime != null && destroyTime < 0) { - throw new IllegalArgumentException("Destroy time must be non-negative"); + public Builder destructibleByMining(Float destructibleByMining) { + if (destructibleByMining != null && destructibleByMining < 0) { + throw new IllegalArgumentException("Destructible by mining must be non-negative"); } - this.destroyTime = destroyTime; + this.destructibleByMining = destructibleByMining; return this; } diff --git a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java index 0103e1762..1de8772de 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.registry; +import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; @@ -32,12 +33,15 @@ import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.api.block.custom.CustomBlockState; +import org.geysermc.geyser.registry.loader.CollisionRegistryLoader; import org.geysermc.geyser.registry.loader.RegistryLoaders; import org.geysermc.geyser.registry.populator.BlockRegistryPopulator; +import org.geysermc.geyser.registry.populator.CustomBlockRegistryPopulator; import org.geysermc.geyser.registry.populator.CustomSkullRegistryPopulator; import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.registry.type.BlockMappings; import org.geysermc.geyser.registry.type.CustomSkull; +import org.geysermc.geyser.translator.collision.BlockCollision; import org.geysermc.geyser.util.collection.Object2IntBiMap; /** @@ -61,6 +65,11 @@ public class BlockRegistries { */ public static final ArrayRegistry JAVA_BLOCKS = ArrayRegistry.create(RegistryLoaders.empty(() -> new BlockMapping[] {})); + /** + * A mapped registry containing which holds block IDs to its {@link BlockCollision}. + */ + public static final IntMappedRegistry COLLISIONS; + /** * A (bi)mapped registry containing the Java IDs to identifiers. */ @@ -105,9 +114,13 @@ public class BlockRegistries { static { CustomSkullRegistryPopulator.populate(); BlockRegistryPopulator.populate(); + COLLISIONS = IntMappedRegistry.create(Pair.of("org.geysermc.geyser.translator.collision.CollisionRemapper", "mappings/collision.json"), CollisionRegistryLoader::new); + CustomBlockRegistryPopulator.registerCustomBedrockBlocks(); + BlockRegistryPopulator.registerBedrockBlocks(); } public static void init() { // no-op } + } \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/registry/Registries.java b/core/src/main/java/org/geysermc/geyser/registry/Registries.java index 2a1b595d8..e1b23e371 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -36,7 +36,7 @@ import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.protocol.bedrock.BedrockPacket; import com.nukkitx.protocol.bedrock.data.inventory.CraftingData; import com.nukkitx.protocol.bedrock.data.inventory.PotionMixData; -import it.unimi.dsi.fastutil.Pair; + import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; @@ -53,7 +53,6 @@ import org.geysermc.geyser.registry.type.EnchantmentData; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.registry.type.ParticleMapping; import org.geysermc.geyser.registry.type.SoundMapping; -import org.geysermc.geyser.translator.collision.BlockCollision; import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.translator.level.event.LevelEventTranslator; import org.geysermc.geyser.translator.sound.SoundInteractionTranslator; @@ -96,11 +95,6 @@ public final class Registries { */ public static final SimpleMappedRegistry BLOCK_ENTITIES = SimpleMappedRegistry.create("org.geysermc.geyser.translator.level.block.entity.BlockEntity", BlockEntityRegistryLoader::new); - /** - * A mapped registry containing which holds block IDs to its {@link BlockCollision}. - */ - public static final IntMappedRegistry COLLISIONS = IntMappedRegistry.create(Pair.of("org.geysermc.geyser.translator.collision.CollisionRemapper", "mappings/collision.json"), CollisionRegistryLoader::new); - /** * A versioned registry which holds a {@link RecipeType} to a corresponding list of {@link CraftingData}. */ diff --git a/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v1.java b/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v1.java index b78649ba8..d7d49ee81 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v1.java +++ b/core/src/main/java/org/geysermc/geyser/registry/mappings/versions/MappingsReader_v1.java @@ -46,6 +46,7 @@ import org.geysermc.geyser.level.block.GeyserCustomBlockData.CustomBlockDataBuil import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.mappings.util.BlockPropertyTypeMaps; +import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.util.BlockUtils; import java.nio.file.Path; @@ -203,11 +204,11 @@ public class MappingsReader_v1 extends MappingsReader { .stream() .filter(s -> s.startsWith(identifier + "[")) .collect(Collectors.toList()); - if (defaultStates.isEmpty()) defaultStates.add(""); + if (defaultStates.isEmpty()) defaultStates.add(identifier); CustomBlockDataBuilder customBlockDataBuilder = new CustomBlockDataBuilder(); customBlockDataBuilder.name(name) - .components(createCustomBlockComponents(node, defaultStates.get(0), identifier, name)) + .components(createCustomBlockComponents(node, defaultStates.get(0), name)) .permutations(createCustomBlockPermutations(stateOverrides, identifier, name)) .booleanProperty("geyser_custom:default"); @@ -232,9 +233,7 @@ public class MappingsReader_v1 extends MappingsReader { String key = entry.getKey(); JsonNode value = entry.getValue(); if (value.isObject()) { - value.forEach(data -> { - permutations.add(new CustomBlockPermutation(createCustomBlockComponents(data, key, identifier, name), createCustomBlockPropertyQuery(key))); - }); + permutations.add(new CustomBlockPermutation(createCustomBlockComponents(value, (identifier + key), name), createCustomBlockPropertyQuery(key))); } }); } @@ -324,20 +323,22 @@ public class MappingsReader_v1 extends MappingsReader { return new BlockPropertyTypeMaps(stringValuesMap, stateKeyStrings, intValuesMap, stateKeyInts, booleanValuesSet, stateKeyBools); } - private CustomBlockComponents createCustomBlockComponents(JsonNode node, String state, String identifier, String name) { - String stateIdentifier = identifier + state; - int id = BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(stateIdentifier, -1); + private CustomBlockComponents createCustomBlockComponents(JsonNode node, String stateKey, String name) { + int id = BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(stateKey, -1); CustomBlockComponentsBuilder builder = new CustomBlockComponentsBuilder(); - // .destroyTime() // .friction() - // .placeAir() - BoundingBox boundingBox = BlockUtils.getCollision(id).getBoundingBoxes()[0]; - BoxComponent boxComponent = new BoxComponent( - (float) boundingBox.getMiddleX(), (float) boundingBox.getMiddleY(), (float) boundingBox.getMiddleZ(), - (float) boundingBox.getSizeX(), (float) boundingBox.getSizeY(), (float) boundingBox.getSizeZ()); + BoxComponent boxComponent = createBoxComponent(id); builder.selectionBox(boxComponent).collisionBox(boxComponent); + // Ideally we would just be able to calculate the right value for this, but it seems that hardness value on bedrock does not follow Java + // As such this might as well just be configured for now if people so choose + float destructibleByMining = BlockRegistries.JAVA_BLOCKS.getOrDefault(id, BlockMapping.AIR).getHardness() * 3.25F; + if (node.has("destructible_by_mining")) { + destructibleByMining = node.get("destructible_by_mining").floatValue(); + } + builder.destructibleByMining(destructibleByMining); + if (node.has("geometry")) { builder.geometry(node.get("geometry").asText()); } @@ -375,29 +376,8 @@ public class MappingsReader_v1 extends MappingsReader { String key = entry.getKey(); JsonNode value = entry.getValue(); if (value.isObject()) { - value.forEach(data -> { - String texture = name; - if (node.has("texture")) { - texture = data.get("texture").asText(); - } - - String renderMethod = data.get("render_method").asText(); - if (node.has("render_method")) { - renderMethod = data.get("render_method").asText(); - } - - boolean faceDimming = false; - if (node.has("face_dimming")) { - faceDimming = data.get("face_dimming").asBoolean(); - } - - boolean ambientOcclusion = false; - if (node.has("ambient_occlusion")) { - ambientOcclusion = data.get("ambient_occlusion").asBoolean(); - } - - builder.materialInstance(key, new MaterialInstance(texture, renderMethod, faceDimming, ambientOcclusion)); - }); + MaterialInstance materialInstance = createMaterialInstanceComponent(value, name); + builder.materialInstance(key, materialInstance); } }); } @@ -408,20 +388,65 @@ public class MappingsReader_v1 extends MappingsReader { return components; } + private BoxComponent createBoxComponent(int id) { + BoundingBox boundingBox = BlockUtils.getCollision(id).getBoundingBoxes()[0]; + + float offsetX = (float) boundingBox.getSizeX() * 8; + float offsetY = (float) boundingBox.getSizeY() * 8; + float offsetZ = (float) boundingBox.getSizeZ() * 8; + + float cornerX = clamp((float) boundingBox.getMiddleX() * 16 - 8 - offsetX, -8, 8); + float cornerY = clamp((float) boundingBox.getMiddleY() * 16 - offsetY, 0, 16); + float cornerZ = clamp((float) boundingBox.getMiddleZ() * 16 - 8 - offsetZ, -8, 8); + + float sizeX = clamp((float) boundingBox.getSizeX() * 16, -8, 8); + float sizeY = clamp((float) boundingBox.getSizeY() * 16, 0, 16); + float sizeZ = clamp((float) boundingBox.getSizeZ() * 16, -8, 8); + + BoxComponent boxComponent = new BoxComponent(cornerX, cornerY, cornerZ, sizeX, sizeY, sizeZ); + + return boxComponent; + } + + private MaterialInstance createMaterialInstanceComponent(JsonNode node, String name) { + String texture = name; + if (node.has("texture")) { + texture = node.get("texture").asText(); + } + + String renderMethod = "alpha_test"; + if (node.has("render_method")) { + renderMethod = node.get("render_method").asText(); + } + + boolean faceDimming = false; + if (node.has("face_dimming")) { + faceDimming = node.get("face_dimming").asBoolean(); + } + + boolean ambientOcclusion = false; + if (node.has("ambient_occlusion")) { + ambientOcclusion = node.get("ambient_occlusion").asBoolean(); + } + + return new MaterialInstance(texture, renderMethod, faceDimming, ambientOcclusion); + } + private String createCustomBlockPropertyQuery(String state) { String[] conditions = splitStateString(state); String[] queries = new String[conditions.length]; for (int i = 0; i < conditions.length; i++) { String[] keyval = conditions[i].split("=", 2); + if (keyval[1].equals("true")) { - queries[i] = String.format("q.block_property('%s') == %b", keyval[0], 1); + queries[i] = String.format("q.block_property('%1$s') == %2$s", keyval[0], 1); } else if (keyval[1].equals("false")) { - queries[i] = String.format("q.block_property('%s') == %b", keyval[0], 0); - } else if (keyval[1].matches("-?\\d+")) { - queries[i] = String.format("q.block_property('%s') == %b", keyval[0], Integer.parseInt(keyval[1])); + queries[i] = String.format("q.block_property('%1$s') == %2$s", keyval[0], 0); + } else if (CharMatcher.inRange('0', '9').matchesAllOf(keyval[1])) { + queries[i] = String.format("q.block_property('%1$s') == %2$s", keyval[0], Integer.parseInt(keyval[1])); } else { - queries[i] = String.format("q.block_property('%s') == '%b'", keyval[0], keyval[1]); + queries[i] = String.format("q.block_property('%1$s') == '%2$s'", keyval[0], keyval[1]); } } @@ -441,4 +466,8 @@ public class MappingsReader_v1 extends MappingsReader { return pairs; } + public float clamp(float value, float min, float max) { + return Math.max(min, Math.min(value, max)); + } + } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index c007a17e3..366e06556 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -78,13 +78,13 @@ public final class BlockRegistryPopulator { public static void populate() { registerJavaBlocks(); - CustomBlockRegistryPopulator.registerCustomBedrockBlocks(); - registerBedrockBlocks(); + // CustomBlockRegistryPopulator.registerCustomBedrockBlocks() and registerBedrockBlocks() moved to BlockRegistries to ensure correct load order - BLOCKS_JSON = null; + // Needs to be placed somewhere at some point + //BLOCKS_JSON = null; } - private static void registerBedrockBlocks() { + public static void registerBedrockBlocks() { BiFunction emptyMapper = (bedrockIdentifier, statesBuilder) -> null; ImmutableMap, BiFunction> blockMappers = ImmutableMap., BiFunction>builder() .put(ObjectIntPair.of("1_19_20", Bedrock_v544.V544_CODEC.getProtocolVersion()), emptyMapper) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java index 1833c4dff..a180935d6 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java @@ -32,7 +32,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; public class CustomBlockRegistryPopulator { - static void registerCustomBedrockBlocks() { + public static void registerCustomBedrockBlocks() { if (!GeyserImpl.getInstance().getConfig().isAddCustomBlocks()) { return; } @@ -81,7 +81,6 @@ public class CustomBlockRegistryPopulator { customBlocks.add(block.data()); block.states().forEach((javaIdentifier, customBlockState) -> { int id = BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(javaIdentifier, -1); - GeyserImpl.getInstance().getLogger().info("CUSTOM RUNTIME ID: " + id + " for " + javaIdentifier); blockStateOverrides.put(id, customBlockState); }); }); @@ -188,9 +187,9 @@ public class CustomBlockRegistryPopulator { .putCompound("materials", materialsBuilder.build()) .build()); } - if (components.destroyTime() != null) { + if (components.destructibleByMining() != null) { builder.putCompound("minecraft:destructible_by_mining", NbtMap.builder() - .putFloat("value", components.destroyTime()) + .putFloat("value", components.destructibleByMining()) .build()); } if (components.friction() != null) { diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/CustomSkull.java b/core/src/main/java/org/geysermc/geyser/registry/type/CustomSkull.java index 658dbf044..08c0b80a4 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/CustomSkull.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/CustomSkull.java @@ -65,7 +65,7 @@ public class CustomSkull { this.skinHash = skinHash; CustomBlockComponents components = new GeyserCustomBlockComponents.CustomBlockComponentsBuilder() - .destroyTime(1.5f) + .destructibleByMining(1.5f) .materialInstance("*", new MaterialInstance("geyser." + skinHash + "_player_skin", "alpha_test", true, true)) .lightDampening(0) .placeAir(true) diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java index c52689014..591737b58 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java @@ -43,7 +43,7 @@ import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.level.physics.CollisionManager; import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.network.GameProtocol; -import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.PistonCache; import org.geysermc.geyser.translator.collision.BlockCollision; @@ -96,7 +96,7 @@ public class PistonBlockEntity { static { // Create a ~1 x ~0.5 x ~1 bounding box above the honey block - BlockCollision blockCollision = Registries.COLLISIONS.get(BlockStateValues.JAVA_HONEY_BLOCK_ID); + BlockCollision blockCollision = BlockRegistries.COLLISIONS.get(BlockStateValues.JAVA_HONEY_BLOCK_ID); if (blockCollision == null) { throw new RuntimeException("Failed to find honey block collision"); } @@ -486,7 +486,7 @@ public class PistonBlockEntity { pistonCache.displacePlayer(movement.mul(delta)); } else { // Move the player out of collision - BlockCollision blockCollision = Registries.COLLISIONS.get(javaId); + BlockCollision blockCollision = BlockRegistries.COLLISIONS.get(javaId); if (blockCollision != null) { Vector3d extend = movement.mul(Math.min(1 - blockMovement, 0.5)); Direction movementDirection = orientation; diff --git a/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java b/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java index c0d484919..6450ed161 100644 --- a/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java @@ -30,7 +30,7 @@ import com.nukkitx.math.vector.Vector3i; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; @@ -219,7 +219,7 @@ public final class BlockUtils { } public static BlockCollision getCollision(int blockId) { - return Registries.COLLISIONS.get(blockId); + return BlockRegistries.COLLISIONS.get(blockId); } public static BlockCollision getCollisionAt(GeyserSession session, Vector3i blockPos) {