diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/CustomBlockData.java b/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/CustomBlockData.java index 8e2a7886f..6d4d7b662 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/CustomBlockData.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/CustomBlockData.java @@ -46,7 +46,7 @@ public interface CustomBlockData { @NonNull List permutations(); - CustomBlockState.Builder blockStateBuilder(); + CustomBlockState.@NonNull Builder blockStateBuilder(); interface Builder { Builder name(@NonNull String name); diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/CustomBlockPermutation.java b/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/CustomBlockPermutation.java index 5766565d2..dfaf626f3 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/CustomBlockPermutation.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/CustomBlockPermutation.java @@ -28,16 +28,5 @@ package org.geysermc.geyser.api.block.custom; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.api.block.custom.component.CustomBlockComponents; -public interface CustomBlockPermutation { - @NonNull String condition(); - - CustomBlockComponents components(); - - interface Builder { - Builder condition(@NonNull String condition); - - Builder components(CustomBlockComponents components); - - CustomBlockPermutation build(); - } +public record CustomBlockPermutation(@NonNull CustomBlockComponents components, @NonNull String condition) { } 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 f18440b33..e1c63d753 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 @@ -25,6 +25,8 @@ package org.geysermc.geyser.api.block.custom.component; +import org.checkerframework.checker.nullness.qual.NonNull; + import java.util.Map; public interface CustomBlockComponents { @@ -34,7 +36,7 @@ public interface CustomBlockComponents { String geometry(); - Map materialInstances(); + @NonNull Map materialInstances(); Float destroyTime(); @@ -53,7 +55,7 @@ public interface CustomBlockComponents { Builder geometry(String geometry); - Builder materialInstances(Map materialInstances); + Builder materialInstance(@NonNull String name, @NonNull MaterialInstance materialInstance); Builder destroyTime(Float destroyTime); 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 5ac7e2613..6a9faeb5c 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,10 +25,16 @@ package org.geysermc.geyser.level.block; +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 org.checkerframework.checker.nullness.qual.NonNull; 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.component.RotationComponent; +import org.jetbrains.annotations.NotNull; import java.util.Map; @@ -47,7 +53,11 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents { this.selectionBox = builder.selectionBox; this.collisionBox = builder.collisionBox; this.geometry = builder.geometry; - this.materialInstances = builder.materialInstances; + if (builder.materialInstances.isEmpty()) { + this.materialInstances = Object2ObjectMaps.emptyMap(); + } else { + this.materialInstances = Object2ObjectMaps.unmodifiable(new Object2ObjectArrayMap<>(builder.materialInstances)); + } this.destroyTime = builder.destroyTime; this.friction = builder.friction; this.lightEmission = builder.lightEmission; @@ -71,7 +81,7 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents { } @Override - public Map materialInstances() { + public @NonNull Map materialInstances() { return materialInstances; } @@ -104,7 +114,7 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents { protected BoxComponent selectionBox; protected BoxComponent collisionBox; protected String geometry; - protected Map materialInstances; + protected final Object2ObjectMap materialInstances = new Object2ObjectOpenHashMap<>(); protected Float destroyTime; protected Float friction; protected Integer lightEmission; @@ -130,8 +140,8 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents { } @Override - public Builder materialInstances(Map materialInstances) { - this.materialInstances = materialInstances; + public Builder materialInstance(@NotNull String name, @NotNull MaterialInstance materialInstance) { + this.materialInstances.put(name, materialInstance); return this; } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/GeyserCustomBlockData.java b/core/src/main/java/org/geysermc/geyser/level/block/GeyserCustomBlockData.java index 5cb3221e5..6cf4bf860 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/GeyserCustomBlockData.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/GeyserCustomBlockData.java @@ -25,9 +25,7 @@ package org.geysermc.geyser.level.block; -import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectLists; +import it.unimi.dsi.fastutil.objects.*; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Value; @@ -39,6 +37,7 @@ import org.geysermc.geyser.api.block.custom.CustomBlockState; import org.geysermc.geyser.api.block.custom.component.CustomBlockComponents; import org.geysermc.geyser.api.block.custom.property.CustomBlockProperty; import org.geysermc.geyser.api.block.custom.property.PropertyType; +import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.Map; @@ -78,15 +77,15 @@ public class GeyserCustomBlockData implements CustomBlockData { } @Override - public CustomBlockState.Builder blockStateBuilder() { + public CustomBlockState.@NotNull Builder blockStateBuilder() { return new GeyserCustomBlockState.CustomBlockStateBuilder(this); } public static class CustomBlockDataBuilder implements Builder { private String name; private CustomBlockComponents components; - private Map> properties = new Object2ObjectOpenHashMap<>(); - private List permutations; + private final Object2ObjectMap> properties = new Object2ObjectOpenHashMap<>(); + private List permutations = ObjectLists.emptyList(); @Override public Builder name(@NonNull String name) { @@ -127,23 +126,27 @@ public class GeyserCustomBlockData implements CustomBlockData { @Override public CustomBlockData build() { if (name == null) { - throw new IllegalArgumentException("Name must be set"); + throw new IllegalStateException("Name must be set"); } - if (properties == null) { - properties = Object2ObjectMaps.emptyMap(); - } else { + + Object2ObjectMap> properties = Object2ObjectMaps.emptyMap(); + if (!this.properties.isEmpty()) { + properties = Object2ObjectMaps.unmodifiable(new Object2ObjectArrayMap<>(this.properties)); for (CustomBlockProperty property : properties.values()) { if (property.values().isEmpty() || property.values().size() > 16) { - throw new IllegalArgumentException(property.name() + " must contain 1 to 16 values."); + throw new IllegalStateException(property.name() + " must contain 1 to 16 values."); } if (property.values().stream().distinct().count() != property.values().size()) { - throw new IllegalArgumentException(property.name() + " has duplicate values."); + throw new IllegalStateException(property.name() + " has duplicate values."); } } } - if (permutations == null) { - permutations = ObjectLists.emptyList(); + + List permutations = ObjectLists.emptyList(); + if (!this.permutations.isEmpty()) { + permutations = ObjectLists.unmodifiable(new ObjectArrayList<>(this.permutations)); } + return new GeyserCustomBlockData(name, components, properties, permutations); } } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/GeyserCustomBlockPermutation.java b/core/src/main/java/org/geysermc/geyser/level/block/GeyserCustomBlockPermutation.java deleted file mode 100644 index 22e03c99a..000000000 --- a/core/src/main/java/org/geysermc/geyser/level/block/GeyserCustomBlockPermutation.java +++ /dev/null @@ -1,76 +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.level.block; - -import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.api.block.custom.CustomBlockPermutation; -import org.geysermc.geyser.api.block.custom.component.CustomBlockComponents; - - -public class GeyserCustomBlockPermutation implements CustomBlockPermutation { - private final String condition; - private final CustomBlockComponents components; - - public GeyserCustomBlockPermutation(String condition, CustomBlockComponents components) { - this.condition = condition; - this.components = components; - } - - @Override - public @NonNull String condition() { - return condition; - } - - @Override - public CustomBlockComponents components() { - return components; - } - - public static class CustomBlockPermutationBuilder implements Builder { - private String condition; - private CustomBlockComponents components; - - @Override - public Builder condition(@NonNull String condition) { - this.condition = condition; - return this; - } - - @Override - public Builder components(CustomBlockComponents components) { - this.components = components; - return this; - } - - @Override - public CustomBlockPermutation build() { - if (condition == null) { - throw new IllegalArgumentException("Condition must be set"); - } - return new GeyserCustomBlockPermutation(condition, components); - } - } -} diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java index 5e97ccf68..1c31901ff 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java @@ -26,7 +26,6 @@ package org.geysermc.geyser.registry.loader; import org.geysermc.geyser.api.block.custom.CustomBlockData; -import org.geysermc.geyser.api.block.custom.CustomBlockPermutation; import org.geysermc.geyser.api.block.custom.component.CustomBlockComponents; import org.geysermc.geyser.api.command.Command; import org.geysermc.geyser.api.command.CommandSource; @@ -39,7 +38,6 @@ import org.geysermc.geyser.item.GeyserCustomItemOptions; import org.geysermc.geyser.item.GeyserNonVanillaCustomItemData; import org.geysermc.geyser.level.block.GeyserCustomBlockComponents; import org.geysermc.geyser.level.block.GeyserCustomBlockData; -import org.geysermc.geyser.level.block.GeyserCustomBlockPermutation; import org.geysermc.geyser.registry.provider.ProviderSupplier; import java.util.Map; @@ -56,7 +54,6 @@ public class ProviderRegistryLoader implements RegistryLoader, Prov providers.put(CustomBlockComponents.Builder.class, args -> new GeyserCustomBlockComponents.CustomBlockComponentsBuilder()); providers.put(CustomBlockData.Builder.class, args -> new GeyserCustomBlockData.CustomBlockDataBuilder()); - providers.put(CustomBlockPermutation.Builder.class, args -> new GeyserCustomBlockPermutation.CustomBlockPermutationBuilder()); providers.put(CustomItemData.Builder.class, args -> new GeyserCustomItemData.CustomItemDataBuilder()); providers.put(CustomItemOptions.Builder.class, args -> new GeyserCustomItemOptions.CustomItemOptionsBuilder()); 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 c3b8beb8e..390e3a8d9 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 @@ -35,11 +35,9 @@ import org.geysermc.geyser.api.block.custom.component.MaterialInstance; import org.geysermc.geyser.api.block.custom.component.RotationComponent; import org.geysermc.geyser.level.block.GeyserCustomBlockComponents; import org.geysermc.geyser.level.block.GeyserCustomBlockData; -import org.geysermc.geyser.level.block.GeyserCustomBlockPermutation; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.stream.IntStream; @Data @@ -53,12 +51,22 @@ public class CustomSkull { private static final int[] ROTATIONS = {0, -90, 180, 90}; + private static final BoxComponent FLOOR_BOX = new BoxComponent( + -4, 0, -4, + 8, 8, 8 + ); + + private static final BoxComponent WALL_BOX = new BoxComponent( + -4, 4, 0, + 8, 8, 8 + ); + public CustomSkull(String skinHash) { this.skinHash = skinHash; CustomBlockComponents components = new GeyserCustomBlockComponents.CustomBlockComponentsBuilder() .destroyTime(1.5f) - .materialInstances(Map.of("*", new MaterialInstance("geyser." + skinHash + "_player_skin", "alpha_test", true, true))) + .materialInstance("*", new MaterialInstance("geyser." + skinHash + "_player_skin", "alpha_test", true, true)) .lightFilter(0) .build(); @@ -112,18 +120,10 @@ public class CustomSkull { .build(); String condition = String.format("query.block_property('%s') == 0 && query.block_property('%s') == 0", BITS_A_PROPERTY, BITS_B_PROPERTY); - permutations.add(new GeyserCustomBlockPermutation.CustomBlockPermutationBuilder() - .condition(condition) - .components(components) - .build()); + permutations.add(new CustomBlockPermutation(components, condition)); } private void addFloorPermutations(List permutations) { - BoxComponent box = new BoxComponent( - -4, 0, -4, - 8, 8, 8 - ); - String[] quadrantNames = {"a", "b", "c", "d"}; for (int quadrant = 0; quadrant < 4; quadrant++) { @@ -131,8 +131,8 @@ public class CustomSkull { for (int i = 0; i < 4; i++) { int floorRotation = 4 * quadrant + i; CustomBlockComponents components = new GeyserCustomBlockComponents.CustomBlockComponentsBuilder() - .selectionBox(box) - .collisionBox(box) + .selectionBox(FLOOR_BOX) + .collisionBox(FLOOR_BOX) .geometry("geometry.geyser.player_skull_floor_" + quadrantNames[i]) .rotation(rotation) .build(); @@ -140,35 +140,23 @@ public class CustomSkull { int bitsA = (5 + floorRotation) % 7; int bitsB = (5 + floorRotation) / 7; String condition = String.format("query.block_property('%s') == %d && query.block_property('%s') == %d", BITS_A_PROPERTY, bitsA, BITS_B_PROPERTY, bitsB); - permutations.add(new GeyserCustomBlockPermutation.CustomBlockPermutationBuilder() - .condition(condition) - .components(components) - .build()); + permutations.add(new CustomBlockPermutation(components, condition)); } } } private void addWallPermutations(List permutations) { - BoxComponent box = new BoxComponent( - -4, 4, 0, - 8, 8, 8 - ); - for (int i = 0; i < 4; i++) { RotationComponent rotation = new RotationComponent(0, ROTATIONS[i], 0); - String condition = String.format("query.block_property('%s') == %d && query.block_property('%s') == %d", BITS_A_PROPERTY, i + 1, BITS_B_PROPERTY, 0); - CustomBlockComponents components = new GeyserCustomBlockComponents.CustomBlockComponentsBuilder() - .selectionBox(box) - .collisionBox(box) + .selectionBox(WALL_BOX) + .collisionBox(WALL_BOX) .geometry("geometry.geyser.player_skull_wall") .rotation(rotation) .build(); - permutations.add(new GeyserCustomBlockPermutation.CustomBlockPermutationBuilder() - .condition(condition) - .components(components) - .build()); + String condition = String.format("query.block_property('%s') == %d && query.block_property('%s') == %d", BITS_A_PROPERTY, i + 1, BITS_B_PROPERTY, 0); + permutations.add(new CustomBlockPermutation(components, condition)); } } }