Extended collision boxes actually work

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>
This commit is contained in:
Joshua Castle 2023-03-12 18:53:10 -07:00
parent 550a4725ef
commit 7f85e909b8
No known key found for this signature in database
GPG key ID: F674F38216C35D5D
9 changed files with 168 additions and 76 deletions

View file

@ -51,13 +51,6 @@ public interface CustomBlockComponents {
*/
BoxComponent collisionBox();
/**
* Gets the extended collision box
* Places an invisible collision block above the block to prevent players from jumping on top of it, if defined
* @return The extended collision box.
*/
BoxComponent extendedCollisionBox();
/**
* Gets the display name component
* Equivalent to "minecraft:display_name"
@ -160,8 +153,6 @@ public interface CustomBlockComponents {
Builder collisionBox(BoxComponent collisionBox);
Builder extendedCollisionBox(BoxComponent extendedCollisionBox);
Builder displayName(String displayName);
Builder geometry(String geometry);

View file

@ -42,7 +42,6 @@ public final class Constants {
static final String SAVED_REFRESH_TOKEN_FILE = "saved-refresh-tokens.json";
public static final String GEYSER_CUSTOM_NAMESPACE = "geyser_custom";
public static final String GEYSER_NAMESPACE = "geyser";
public static final String MINECRAFT_SKIN_SERVER_URL = "https://textures.minecraft.net/texture/";

View file

@ -47,7 +47,6 @@ import java.util.Set;
public class GeyserCustomBlockComponents implements CustomBlockComponents {
BoxComponent selectionBox;
BoxComponent collisionBox;
BoxComponent extendedCollisionBox;
String displayName;
String geometry;
Map<String, MaterialInstance> materialInstances;
@ -64,7 +63,6 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents {
private GeyserCustomBlockComponents(CustomBlockComponentsBuilder builder) {
this.selectionBox = builder.selectionBox;
this.collisionBox = builder.collisionBox;
this.extendedCollisionBox = builder.extendedCollisionBox;
this.displayName = builder.displayName;
this.geometry = builder.geometry;
if (builder.materialInstances.isEmpty()) {
@ -97,11 +95,6 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents {
return collisionBox;
}
@Override
public BoxComponent extendedCollisionBox() {
return extendedCollisionBox;
}
@Override
public String displayName() {
return displayName;
@ -165,7 +158,6 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents {
public static class CustomBlockComponentsBuilder implements Builder {
protected BoxComponent selectionBox;
protected BoxComponent collisionBox;
protected BoxComponent extendedCollisionBox;
protected String displayName;
protected String geometry;
protected final Object2ObjectMap<String, MaterialInstance> materialInstances = new Object2ObjectOpenHashMap<>();
@ -211,13 +203,6 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents {
return this;
}
@Override
public Builder extendedCollisionBox(BoxComponent extendedCollisionBox) {
validateBox(extendedCollisionBox);
this.extendedCollisionBox = extendedCollisionBox;
return this;
}
@Override
public Builder displayName(String displayName) {
this.displayName = displayName;

View file

@ -0,0 +1,33 @@
/*
* 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.registry.mappings.util;
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;
public record CustomBlockComponentsMapping(@NonNull CustomBlockComponents components, BoxComponent extendedCollisionBox) {
}

View file

@ -29,12 +29,11 @@ import java.util.Map;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.api.block.custom.CustomBlockData;
import org.geysermc.geyser.api.block.custom.CustomBlockState;
/**
* This class is used to store a custom block mappings, which contain all of the
* data required to register a custom block that overrides a group of java block
* states.
*/
public record CustomBlockMapping(@NonNull CustomBlockData data, @NonNull Map<String, CustomBlockState> states, @NonNull String javaIdentifier, boolean overrideItem) {
public record CustomBlockMapping(@NonNull CustomBlockData data, @NonNull Map<String, CustomBlockStateMapping> states, @NonNull String javaIdentifier, boolean overrideItem) {
}

View file

@ -0,0 +1,35 @@
/*
* 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.registry.mappings.util;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.api.block.custom.CustomBlockState;
import org.geysermc.geyser.api.block.custom.component.BoxComponent;
import java.util.function.Function;
public record CustomBlockStateBuilderMapping(@NonNull Function<CustomBlockState.Builder, CustomBlockState> builder, BoxComponent extendedCollisionBox) {
}

View file

@ -0,0 +1,33 @@
/*
* 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.registry.mappings.util;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.api.block.custom.CustomBlockState;
import org.geysermc.geyser.api.block.custom.component.BoxComponent;
public record CustomBlockStateMapping(@NonNull CustomBlockState state, BoxComponent extendedCollisionBox) {
}

View file

@ -44,7 +44,10 @@ import org.geysermc.geyser.level.block.GeyserCustomBlockComponents.CustomBlockCo
import org.geysermc.geyser.level.block.GeyserCustomBlockData.CustomBlockDataBuilder;
import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.mappings.util.CustomBlockComponentsMapping;
import org.geysermc.geyser.registry.mappings.util.CustomBlockMapping;
import org.geysermc.geyser.registry.mappings.util.CustomBlockStateBuilderMapping;
import org.geysermc.geyser.registry.mappings.util.CustomBlockStateMapping;
import org.geysermc.geyser.translator.collision.BlockCollision;
import org.geysermc.geyser.util.BlockUtils;
import org.geysermc.geyser.util.MathUtils;
@ -194,13 +197,14 @@ public class MappingsReader_v1 extends MappingsReader {
if (BlockRegistries.JAVA_IDENTIFIERS.get().containsKey(identifier)) {
// There is only one Java block state to override
CustomBlockComponentsMapping componentsMapping = createCustomBlockComponentsMapping(node, identifier, name);
CustomBlockData blockData = customBlockDataBuilder
.components(createCustomBlockComponents(node, identifier, name))
.components(componentsMapping.components())
.build();
return new CustomBlockMapping(blockData, Map.of(identifier, blockData.defaultBlockState()), identifier, !onlyOverrideStates);
return new CustomBlockMapping(blockData, Map.of(identifier, new CustomBlockStateMapping(blockData.defaultBlockState(), componentsMapping.extendedCollisionBox())), identifier, !onlyOverrideStates);
}
Map<String, CustomBlockComponents> componentsMap = new LinkedHashMap<>();
Map<String, CustomBlockComponentsMapping> componentsMap = new LinkedHashMap<>();
JsonNode stateOverrides = node.get("state_overrides");
if (stateOverrides != null && stateOverrides.isObject()) {
@ -212,7 +216,7 @@ public class MappingsReader_v1 extends MappingsReader {
if (!BlockRegistries.JAVA_IDENTIFIERS.get().containsKey(state)) {
throw new InvalidCustomMappingsFileException("Unknown Java block state: " + state + " for state_overrides.");
}
componentsMap.put(state, createCustomBlockComponents(overrideEntry.getValue(), state, name));
componentsMap.put(state, createCustomBlockComponentsMapping(overrideEntry.getValue(), state, name));
}
}
if (componentsMap.isEmpty() && onlyOverrideStates) {
@ -225,7 +229,7 @@ public class MappingsReader_v1 extends MappingsReader {
.stream()
.filter(s -> s.startsWith(identifier + "["))
.filter(Predicate.not(componentsMap::containsKey))
.forEach(state -> componentsMap.put(state, createCustomBlockComponents(null, state, name)));
.forEach(state -> componentsMap.put(state, createCustomBlockComponentsMapping(null, state, name)));
}
if (componentsMap.isEmpty()) {
@ -235,20 +239,21 @@ public class MappingsReader_v1 extends MappingsReader {
// We pass in the first state and just use the hitbox from that as the default
// Each state will have its own so this is fine
String firstState = componentsMap.keySet().iterator().next();
customBlockDataBuilder.components(createCustomBlockComponents(node, firstState, name));
CustomBlockComponentsMapping firstComponentsMapping = createCustomBlockComponentsMapping(node, firstState, name);
customBlockDataBuilder.components(firstComponentsMapping.components());
return createCustomBlockMapping(customBlockDataBuilder, componentsMap, identifier, !onlyOverrideStates);
}
private CustomBlockMapping createCustomBlockMapping(CustomBlockData.Builder customBlockDataBuilder, Map<String, CustomBlockComponents> componentsMap, String identifier, boolean overrideItem) {
private CustomBlockMapping createCustomBlockMapping(CustomBlockData.Builder customBlockDataBuilder, Map<String, CustomBlockComponentsMapping> componentsMap, String identifier, boolean overrideItem) {
Map<String, LinkedHashSet<String>> valuesMap = new Object2ObjectOpenHashMap<>();
List<CustomBlockPermutation> permutations = new ArrayList<>();
Map<String, Function<CustomBlockState.Builder, CustomBlockState>> blockStateBuilders = new Object2ObjectOpenHashMap<>();
Map<String, CustomBlockStateBuilderMapping> blockStateBuilders = new Object2ObjectOpenHashMap<>();
// For each Java block state, extract the property values, create a CustomBlockPermutation,
// and a CustomBlockState builder
for (Map.Entry<String, CustomBlockComponents> entry : componentsMap.entrySet()) {
for (Map.Entry<String, CustomBlockComponentsMapping> entry : componentsMap.entrySet()) {
String state = entry.getKey();
String[] pairs = splitStateString(state);
@ -267,8 +272,8 @@ public class MappingsReader_v1 extends MappingsReader {
blockStateBuilder = blockStateBuilder.andThen(builder -> builder.stringProperty(property, value));
}
permutations.add(new CustomBlockPermutation(entry.getValue(), String.join(" && ", conditions)));
blockStateBuilders.put(state, blockStateBuilder.andThen(CustomBlockState.Builder::build));
permutations.add(new CustomBlockPermutation(entry.getValue().components(), String.join(" && ", conditions)));
blockStateBuilders.put(state, new CustomBlockStateBuilderMapping(blockStateBuilder.andThen(CustomBlockState.Builder::build), entry.getValue().extendedCollisionBox()));
}
valuesMap.forEach((key, value) -> customBlockDataBuilder.stringProperty(key, new ArrayList<>(value)));
@ -277,8 +282,8 @@ public class MappingsReader_v1 extends MappingsReader {
.permutations(permutations)
.build();
// Build CustomBlockStates for each Java block state we wish to override
Map<String, CustomBlockState> states = blockStateBuilders.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().apply(customBlockData.blockStateBuilder())));
Map<String, CustomBlockStateMapping> states = blockStateBuilders.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> new CustomBlockStateMapping(e.getValue().builder().apply(customBlockData.blockStateBuilder()), e.getValue().extendedCollisionBox())));
return new CustomBlockMapping(customBlockData, states, identifier, overrideItem);
}
@ -290,19 +295,18 @@ public class MappingsReader_v1 extends MappingsReader {
* @param name the name of the custom block
* @return the {@link CustomBlockComponents} object
*/
private CustomBlockComponents createCustomBlockComponents(JsonNode node, String stateKey, String name) {
private CustomBlockComponentsMapping createCustomBlockComponentsMapping(JsonNode node, String stateKey, String name) {
// This is needed to find the correct selection box for the given block
int id = BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(stateKey, -1);
BoxComponent boxComponent = createBoxComponent(id, 0, 16, 0);
BoxComponent extendedBoxComponent = createBoxComponent(id, 16, 32, -16);
BoxComponent boxComponent = createBoxComponent(id);
BoxComponent extendedBoxComponent = createExtendedBoxComponent(id);
CustomBlockComponents.Builder builder = new CustomBlockComponentsBuilder()
.collisionBox(boxComponent)
.selectionBox(boxComponent)
.extendedCollisionBox(extendedBoxComponent);
.selectionBox(boxComponent);
if (node == null) {
// No other components were defined
return builder.build();
return new CustomBlockComponentsMapping(builder.build(), extendedBoxComponent);
}
BoxComponent selectionBox = createBoxComponent(node.get("selection_box"));
@ -315,7 +319,7 @@ public class MappingsReader_v1 extends MappingsReader {
}
BoxComponent extendedCollisionBox = createBoxComponent(node.get("extended_collision_box"));
if (extendedCollisionBox != null) {
builder.extendedCollisionBox(extendedCollisionBox);
extendedBoxComponent = extendedCollisionBox;
}
@ -404,11 +408,11 @@ public class MappingsReader_v1 extends MappingsReader {
builder.tags(tagsSet);
}
return builder.build();
return new CustomBlockComponentsMapping(builder.build(), extendedBoxComponent);
}
/**
* Creates a {@link BoxComponent} based on a Java block's collision
* Creates a {@link BoxComponent} based on a Java block's collision with provided bounds and offsets
* @param javaId the block's Java ID
* @param minHeight the minimum height of the box
* @param maxHeight the maximum height of the box
@ -428,11 +432,6 @@ public class MappingsReader_v1 extends MappingsReader {
float offsetY = (float) boundingBox.getSizeY() * 8;
float offsetZ = (float) boundingBox.getSizeZ() * 8;
// Unfortunately we need to clamp the values here to an effective size of one block
// This is quite a pain for anything like fences, as the player can just jump over them
// One possible solution would be to create invisible blocks that we use only for collision box
// These could be placed above the block when a custom block exceeds this limit
// I am hopeful this will be extended slightly since the geometry of blocks can be 1.875^3
float cornerX = MathUtils.clamp((float) boundingBox.getMiddleX() * 16 - 8 - offsetX, -8, 8);
float cornerY = MathUtils.clamp((float) boundingBox.getMiddleY() * 16 - offsetY, minHeight, maxHeight);
float cornerZ = MathUtils.clamp((float) boundingBox.getMiddleZ() * 16 - 8 - offsetZ, -8, 8);
@ -444,6 +443,35 @@ public class MappingsReader_v1 extends MappingsReader {
return new BoxComponent(cornerX, cornerY + heightTranslation, cornerZ, sizeX, sizeY + heightTranslation, sizeZ);
}
/**
* Creates a {@link BoxComponent} based on a Java block's collision
* @param javaId the block's Java ID
* @return the {@link BoxComponent}
*/
private BoxComponent createBoxComponent(int javaId) {
return createBoxComponent(javaId, 0, 16, 0);
}
/**
* Creates the {@link BoxComponent} for an extended collision box based on a Java block's collision
* @param javaId the block's Java ID
* @return the {@link BoxComponent} or null if the block's collision box would not exceed 16 y units
*/
private BoxComponent createExtendedBoxComponent(int javaId) {
BlockCollision blockCollision = BlockUtils.getCollision(javaId);
if (blockCollision == null) {
return null;
}
BoundingBox boundingBox = blockCollision.getBoundingBoxes()[0];
float offsetY = (float) boundingBox.getSizeY() * 8;
float cornerY = (float) boundingBox.getMiddleY() * 16 - offsetY;
float sizeY = (float) boundingBox.getSizeY() * 16;
if (cornerY > 16 || sizeY > 16) {
return createBoxComponent(javaId, 16, 32, -16);
}
return null;
}
/**
* Creates a {@link BoxComponent} from a JSON Node
* @param node the JSON node

View file

@ -48,9 +48,6 @@ public class CustomBlockRegistryPopulator {
Set<CustomBlockData> customBlocks = new ObjectOpenHashSet<>();
Int2ObjectMap<CustomBlockState> blockStateOverrides = new Int2ObjectOpenHashMap<>();
Map<String, CustomBlockData> customBlockItemOverrides = new HashMap<>();
Map<CustomBlockData, Set<Integer>> extendedCollisionBoxes = new HashMap<>();
Map<BoxComponent, CustomBlockData> extendedCollisionBoxSet = new HashMap<>();
int[] extendedCollisionIndex = {0};
GeyserImpl.getInstance().getEventBus().fire(new GeyserDefineCustomBlocksEvent() {
@Override
@ -77,20 +74,6 @@ public class CustomBlockRegistryPopulator {
throw new IllegalArgumentException("Custom block is unregistered. Name: " + customBlockState.name());
}
CustomBlockState oldBlockState = blockStateOverrides.put(id, customBlockState);
BoxComponent extendedCollisionBox = customBlockState.block().components().extendedCollisionBox();
if (extendedCollisionBox != null) {
CustomBlockData extendedCollisionBlock = extendedCollisionBoxSet.getOrDefault(extendedCollisionBox, null);
if (extendedCollisionBlock == null) {
extendedCollisionBlock = createExtendedCollisionBlock(extendedCollisionBox, extendedCollisionIndex[0]++);
extendedCollisionBoxes.put(extendedCollisionBlock, new HashSet<>(id));
customBlocks.add(extendedCollisionBlock);
extendedCollisionBoxSet.put(extendedCollisionBox, extendedCollisionBlock);
} else {
Set<Integer> existingJavaIds = extendedCollisionBoxes.getOrDefault(extendedCollisionBlock, new HashSet<>());
existingJavaIds.add(id);
extendedCollisionBoxes.put(extendedCollisionBlock, existingJavaIds);
}
}
if (oldBlockState != null) {
GeyserImpl.getInstance().getLogger().debug("Duplicate block state override for Java Identifier: " +
javaIdentifier + " Old override: " + oldBlockState.name() + " New override: " + customBlockState.name());
@ -110,6 +93,9 @@ public class CustomBlockRegistryPopulator {
customBlocks.add(customSkull.getCustomBlockData());
}
Map<CustomBlockData, Set<Integer>> extendedCollisionBoxes = new HashMap<>();
Map<BoxComponent, CustomBlockData> extendedCollisionBoxSet = new HashMap<>();
int[] extendedCollisionIndex = {0};
MappingsConfigReader mappingsConfigReader = new MappingsConfigReader();
mappingsConfigReader.loadBlockMappingsFromJson((key, block) -> {
customBlocks.add(block.data());
@ -118,13 +104,13 @@ public class CustomBlockRegistryPopulator {
}
block.states().forEach((javaIdentifier, customBlockState) -> {
int id = BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(javaIdentifier, -1);
blockStateOverrides.put(id, customBlockState);
BoxComponent extendedCollisionBox = customBlockState.block().components().extendedCollisionBox();
blockStateOverrides.put(id, customBlockState.state());
BoxComponent extendedCollisionBox = customBlockState.extendedCollisionBox();
if (extendedCollisionBox != null) {
CustomBlockData extendedCollisionBlock = extendedCollisionBoxSet.getOrDefault(extendedCollisionBox, null);
if (extendedCollisionBlock == null) {
extendedCollisionBlock = createExtendedCollisionBlock(extendedCollisionBox, extendedCollisionIndex[0]++);
extendedCollisionBoxes.put(extendedCollisionBlock, new HashSet<>(id));
extendedCollisionBoxes.computeIfAbsent(extendedCollisionBlock, k -> new HashSet<>()).add(id);
customBlocks.add(extendedCollisionBlock);
extendedCollisionBoxSet.put(extendedCollisionBox, extendedCollisionBlock);
} else {
@ -375,11 +361,14 @@ public class CustomBlockRegistryPopulator {
private static CustomBlockData createExtendedCollisionBlock(BoxComponent boxComponent, int extendedCollisionBlock) {
CustomBlockData customBlockData = new CustomBlockDataBuilder()
.name(Constants.GEYSER_NAMESPACE + ":extended_collision_" + extendedCollisionBlock)
.name("extended_collision_" + extendedCollisionBlock)
.components(
new CustomBlockComponentsBuilder()
.collisionBox(boxComponent)
.selectionBox(new BoxComponent(0, 0, 0, 0, 0, 0))
.selectionBox(BoxComponent.EMPTY_BOX)
.materialInstance("*", new MaterialInstance("glass", "alpha_test", false, false))
.lightDampening(0)
.geometry("geometry.invisible")
.build())
.build();
return customBlockData;