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 e1c63d753..d3c337ce5 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 @@ -63,7 +63,7 @@ public interface CustomBlockComponents { Builder lightEmission(Integer lightEmission); - Builder lightFilter(Integer lightFilter); + Builder lightDampening(Integer lightDampening); Builder rotation(RotationComponent rotation); 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 85795970a..1dbda3434 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,6 +25,7 @@ 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; @@ -38,6 +39,7 @@ import org.geysermc.geyser.api.block.custom.component.RotationComponent; import org.jetbrains.annotations.NotNull; import java.util.Map; +import java.util.Set; @Value public class GeyserCustomBlockComponents implements CustomBlockComponents { @@ -63,7 +65,7 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents { this.destroyTime = builder.destroyTime; this.friction = builder.friction; this.lightEmission = builder.lightEmission; - this.lightDampening = builder.lightFilter; + this.lightDampening = builder.lightDampening; this.rotation = builder.rotation; } @@ -115,22 +117,45 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents { public static class CustomBlockComponentsBuilder implements Builder { protected BoxComponent selectionBox; protected BoxComponent collisionBox; + protected String displayName; protected String geometry; protected final Object2ObjectMap materialInstances = new Object2ObjectOpenHashMap<>(); protected Float destroyTime; protected Float friction; protected Integer lightEmission; - protected Integer lightFilter; + protected Integer lightDampening; protected RotationComponent rotation; + private static final Set VALID_MATERIAL_INSTANCE_NAMES = ImmutableSet.of("*", "up", "down", "north", "south", "west", "east"); + + private void validateBox(BoxComponent box) { + if (box == null) { + return; + } + if (box.sizeX() < 0 || box.sizeY() < 0 || box.sizeZ() < 0) { + throw new IllegalArgumentException("Box size must be non-negative."); + } + float minX = box.originX() + 8; + float minY = box.originY(); + float minZ = box.originZ() + 8; + float maxX = minX + box.sizeX(); + float maxY = minY + box.sizeY(); + float maxZ = minZ + box.sizeZ(); + if (minX < 0 || minY < 0 || minZ < 0 || maxX > 16 || maxY > 16 || maxZ > 16) { + throw new IllegalArgumentException("Box bounds must be within (0, 0, 0) and (16, 16, 16)"); + } + } + @Override public Builder selectionBox(BoxComponent selectionBox) { + validateBox(selectionBox); this.selectionBox = selectionBox; return this; } @Override public Builder collisionBox(BoxComponent collisionBox) { + validateBox(collisionBox); this.collisionBox = collisionBox; return this; } @@ -143,36 +168,60 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents { @Override public Builder materialInstance(@NotNull String name, @NotNull MaterialInstance materialInstance) { + if (!VALID_MATERIAL_INSTANCE_NAMES.contains(name)) { + throw new IllegalArgumentException("Material instance name must be one of " + VALID_MATERIAL_INSTANCE_NAMES); + } this.materialInstances.put(name, materialInstance); return this; } @Override public Builder destroyTime(Float destroyTime) { + if (destroyTime != null && destroyTime < 0) { + throw new IllegalArgumentException("Destroy time must be non-negative"); + } this.destroyTime = destroyTime; return this; } @Override public Builder friction(Float friction) { + if (friction != null) { + if (friction < 0 || friction > 1) { + throw new IllegalArgumentException("Friction must be in the range 0-1"); + } + } this.friction = friction; return this; } @Override public Builder lightEmission(Integer lightEmission) { + if (lightEmission != null) { + if (lightEmission < 0 || lightEmission > 15) { + throw new IllegalArgumentException("Light emission must be in the range 0-15"); + } + } this.lightEmission = lightEmission; return this; } @Override - public Builder lightFilter(Integer lightFilter) { - this.lightFilter = lightFilter; + public Builder lightDampening(Integer lightDampening) { + if (lightDampening != null) { + if (lightDampening < 0 || lightDampening > 15) { + throw new IllegalArgumentException("Light dampening must be in the range 0-15"); + } + } + this.lightDampening = lightDampening; return this; } @Override public Builder rotation(RotationComponent rotation) { + if (rotation.x() % 90 != 0 || rotation.y() % 90 != 0 || rotation.z() % 90 != 0) { + throw new IllegalArgumentException("Rotation must be a multiple of 90 degrees."); + } this.rotation = rotation; return this; } 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 b73ec8c27..f5027d9ca 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 @@ -250,14 +250,6 @@ public final class BlockRegistryPopulator { } } - static NbtMap convertBox(BoxComponent boxComponent) { - return NbtMap.builder() - .putBoolean("enabled", !boxComponent.isEmpty()) - .putList("origin", NbtType.FLOAT, boxComponent.originX(), boxComponent.originY(), boxComponent.originZ()) - .putList("size", NbtType.FLOAT, boxComponent.sizeX(), boxComponent.sizeY(), boxComponent.sizeZ()) - .build(); - } - private static void registerJavaBlocks() { JsonNode blocksJson; try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResource("mappings/blocks.json")) { 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 227c9b6dd..db59fc3a1 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 @@ -1,16 +1,17 @@ package org.geysermc.geyser.registry.populator; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.api.block.custom.CustomBlockPermutation; import org.geysermc.geyser.api.block.custom.CustomBlockState; +import org.geysermc.geyser.api.block.custom.component.BoxComponent; import org.geysermc.geyser.api.block.custom.component.CustomBlockComponents; import org.geysermc.geyser.api.block.custom.component.MaterialInstance; import org.geysermc.geyser.api.block.custom.property.CustomBlockProperty; @@ -34,17 +35,21 @@ public class CustomBlockRegistryPopulator { if (!GeyserImpl.getInstance().getConfig().isAddCustomBlocks()) { return; } - Set customBlockNames = new HashSet<>(); - Set customBlocks = new HashSet<>(); + Set customBlockNames = new ObjectOpenHashSet<>(); + Set customBlocks = new ObjectOpenHashSet<>(); Int2ObjectMap blockStateOverrides = new Int2ObjectOpenHashMap<>(); GeyserImpl.getInstance().getEventBus().fire(new GeyserDefineCustomBlocksEvent() { @Override public void registerCustomBlock(@NonNull CustomBlockData customBlockData) { + if (customBlockData.name().length() == 0) { + throw new IllegalArgumentException("Custom block name must have at least 1 character."); + } if (!customBlockNames.add(customBlockData.name())) { throw new IllegalArgumentException("Another custom block was already registered under the name: " + customBlockData.name()); } - // TODO validate collision+selection box bounds - // TODO validate names + if (Character.isDigit(customBlockData.name().charAt(0))) { + throw new IllegalArgumentException("Custom block can not start with a digit. Name: " + customBlockData.name()); + } customBlocks.add(customBlockData); } @@ -146,10 +151,10 @@ public class CustomBlockRegistryPopulator { } NbtMapBuilder builder = NbtMap.builder(); if (components.selectionBox() != null) { - builder.putCompound("minecraft:selection_box", BlockRegistryPopulator.convertBox(components.selectionBox())); + builder.putCompound("minecraft:selection_box", convertBox(components.selectionBox())); } if (components.collisionBox() != null) { - builder.putCompound("minecraft:collision_box", BlockRegistryPopulator.convertBox(components.collisionBox())); + builder.putCompound("minecraft:collision_box", convertBox(components.collisionBox())); } if (components.geometry() != null) { builder.putCompound("minecraft:geometry", NbtMap.builder() @@ -201,5 +206,12 @@ public class CustomBlockRegistryPopulator { } return builder.build(); } - + + private static NbtMap convertBox(BoxComponent boxComponent) { + return NbtMap.builder() + .putBoolean("enabled", !boxComponent.isEmpty()) + .putList("origin", NbtType.FLOAT, boxComponent.originX(), boxComponent.originY(), boxComponent.originZ()) + .putList("size", NbtType.FLOAT, boxComponent.sizeX(), boxComponent.sizeY(), boxComponent.sizeZ()) + .build(); + } } 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 1f5c62b35..9f54b23c0 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 @@ -67,7 +67,7 @@ public class CustomSkull { CustomBlockComponents components = new GeyserCustomBlockComponents.CustomBlockComponentsBuilder() .destroyTime(1.5f) .materialInstance("*", new MaterialInstance("geyser." + skinHash + "_player_skin", "alpha_test", true, true)) - .lightFilter(0) + .lightDampening(0) .build(); List permutations = new ArrayList<>();