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 1c284b38c..a903d1676 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 @@ -26,8 +26,8 @@ package org.geysermc.geyser.api.block.custom.component; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.geyser.api.block.custom.component.placementfilter.PlacementFilter; +import java.util.List; import java.util.Map; import java.util.Set; @@ -78,11 +78,11 @@ public interface CustomBlockComponents { /** * Gets the placement filter component - * Equivalent to "minecraft:material_instances" + * Equivalent to "minecraft:placement_filter" * * @return The placement filter. */ - PlacementFilter placementFilter(); + List placementFilter(); /** * Gets the destructible by mining component @@ -159,7 +159,7 @@ public interface CustomBlockComponents { Builder materialInstance(@NonNull String name, @NonNull MaterialInstance materialInstance); - Builder placementFilter(PlacementFilter placementFilter); + Builder placementFilter(List placementConditions); Builder destructibleByMining(Float destructibleByMining); diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/component/placementfilter/Conditions.java b/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/component/PlacementConditions.java similarity index 82% rename from api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/component/placementfilter/Conditions.java rename to api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/component/PlacementConditions.java index b12238584..3b102987a 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/component/placementfilter/Conditions.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/component/PlacementConditions.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.api.block.custom.component.placementfilter; +package org.geysermc.geyser.api.block.custom.component; import java.util.LinkedHashMap; import java.util.Set; @@ -33,7 +33,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; /* * This class is used to store conditions for a placement filter for a custom block. */ -public record Conditions(@NonNull Set allowedFaces, @NonNull LinkedHashMap blockFilters) { +public record PlacementConditions(@NonNull Set allowedFaces, @NonNull LinkedHashMap blockFilters) { public enum Face { DOWN(1), UP(2), @@ -42,14 +42,8 @@ public record Conditions(@NonNull Set allowedFaces, @NonNull LinkedHashMap WEST(16), EAST(32); - private final byte value; - Face(int value) { - this.value = (byte) value; - } - - public byte getValue() { - return value; + value = (byte) value; } } public enum BlockFilterType { diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/component/placementfilter/PlacementFilter.java b/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/component/placementfilter/PlacementFilter.java deleted file mode 100644 index 77e40bac4..000000000 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/component/placementfilter/PlacementFilter.java +++ /dev/null @@ -1,36 +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.api.block.custom.component.placementfilter; - -import java.util.List; - -import org.checkerframework.checker.nullness.qual.NonNull; - -/* - * This class is used to store a placement filter for a custom block. - */ -public record PlacementFilter(@NonNull List conditions) { -} diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/property/PropertyType.java b/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/property/PropertyType.java index 18afe9629..6fbbe9340 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/property/PropertyType.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/block/custom/property/PropertyType.java @@ -35,7 +35,7 @@ public class PropertyType { private final Class typeClass; - public Class getTypeClass() { + public Class typeClass() { return typeClass; } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCustomSkullsEvent.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCustomSkullsEvent.java index e568f5c31..bdb7db6c3 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCustomSkullsEvent.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCustomSkullsEvent.java @@ -1,6 +1,6 @@ package org.geysermc.geyser.api.event.lifecycle; -import lombok.NonNull; +import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.event.Event; /** diff --git a/core/src/main/java/org/geysermc/geyser/Constants.java b/core/src/main/java/org/geysermc/geyser/Constants.java index 588a8ad51..040d408c5 100644 --- a/core/src/main/java/org/geysermc/geyser/Constants.java +++ b/core/src/main/java/org/geysermc/geyser/Constants.java @@ -43,7 +43,7 @@ public final class Constants { public static final String GEYSER_NAMESPACE = "geyser_custom"; - public static final String MINECRAFT_SKIN_SERVER_URL = "http://textures.minecraft.net/texture/"; + public static final String MINECRAFT_SKIN_SERVER_URL = "https://textures.minecraft.net/texture/"; static { URI wsUri = null; 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 cbe60eb47..ef4679a4f 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 @@ -34,11 +34,12 @@ 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.PlacementConditions; import org.geysermc.geyser.api.block.custom.component.RotationComponent; -import org.geysermc.geyser.api.block.custom.component.placementfilter.PlacementFilter; import org.jetbrains.annotations.NotNull; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -49,7 +50,7 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents { String displayName; String geometry; Map materialInstances; - PlacementFilter placementFilter; + List placementFilter; Float destructibleByMining; Float friction; Integer lightEmission; @@ -110,7 +111,7 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents { } @Override - public PlacementFilter placementFilter() { + public List placementFilter() { return placementFilter; } @@ -160,7 +161,7 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents { protected String displayName; protected String geometry; protected final Object2ObjectMap materialInstances = new Object2ObjectOpenHashMap<>(); - protected PlacementFilter placementFilter; + protected List placementFilter; protected Float destructibleByMining; protected Float friction; protected Integer lightEmission; @@ -221,7 +222,7 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents { } @Override - public Builder placementFilter(PlacementFilter placementFilter) { + public Builder placementFilter(List placementFilter) { this.placementFilter = placementFilter; return this; } 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 5e06a7f3f..c0199ad52 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 @@ -35,13 +35,12 @@ 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.PlacementConditions; 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.geysermc.geyser.api.block.custom.component.placementfilter.Conditions; -import org.geysermc.geyser.api.block.custom.component.placementfilter.PlacementFilter; -import org.geysermc.geyser.api.block.custom.component.placementfilter.Conditions.BlockFilterType; -import org.geysermc.geyser.api.block.custom.component.placementfilter.Conditions.Face; +import org.geysermc.geyser.api.block.custom.component.PlacementConditions.BlockFilterType; +import org.geysermc.geyser.api.block.custom.component.PlacementConditions.Face; import org.geysermc.geyser.api.item.custom.CustomItemData; import org.geysermc.geyser.api.item.custom.CustomItemOptions; import org.geysermc.geyser.item.exception.InvalidCustomMappingsFileException; @@ -53,7 +52,9 @@ import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.mappings.util.BlockPropertyTypeMaps; import org.geysermc.geyser.registry.mappings.util.CustomBlockMapping; import org.geysermc.geyser.registry.type.BlockMapping; +import org.geysermc.geyser.translator.collision.BlockCollision; import org.geysermc.geyser.util.BlockUtils; +import org.geysermc.geyser.util.MathUtils; import java.nio.file.Path; import java.util.ArrayList; @@ -419,10 +420,50 @@ public class MappingsReader_v1 extends MappingsReader { private CustomBlockComponents createCustomBlockComponents(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); - CustomBlockComponentsBuilder builder = new CustomBlockComponentsBuilder(); BoxComponent boxComponent = createBoxComponent(id); - builder.selectionBox(boxComponent).collisionBox(boxComponent); + + BoxComponent selectionBox = boxComponent; + if (node.has("selection_box")) { + JsonNode selectionBoxNode = node.get("selection_box"); + if (selectionBoxNode.isObject()) { + if (selectionBoxNode.has("origin") && selectionBoxNode.has("size")) { + JsonNode origin = selectionBoxNode.get("origin"); + int originX = origin.get(0).intValue(); + int originY = origin.get(1).intValue(); + int originZ = origin.get(2).intValue(); + + JsonNode size = selectionBoxNode.get("size"); + int sizeX = size.get(0).intValue(); + int sizeY = size.get(1).intValue(); + int sizeZ = size.get(2).intValue(); + + selectionBox = new BoxComponent(originX, originY, originZ, sizeX, sizeY, sizeZ); + } + } + } + builder.selectionBox(selectionBox); + + BoxComponent collisionBox = boxComponent; + if (node.has("collision_box")) { + JsonNode collisionBoxNode = node.get("collision_box"); + if (collisionBoxNode.isObject()) { + if (collisionBoxNode.has("origin") && collisionBoxNode.has("size")) { + JsonNode origin = collisionBoxNode.get("origin"); + int originX = origin.get(0).intValue(); + int originY = origin.get(1).intValue(); + int originZ = origin.get(2).intValue(); + + JsonNode size = collisionBoxNode.get("size"); + int sizeX = size.get(0).intValue(); + int sizeY = size.get(1).intValue(); + int sizeZ = size.get(2).intValue(); + + collisionBox = new BoxComponent(originX, originY, originZ, sizeX, sizeY, sizeZ); + } + } + } + builder.collisionBox(collisionBox); // 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 @@ -492,7 +533,7 @@ public class MappingsReader_v1 extends MappingsReader { if (placementFilter.has("conditions")) { JsonNode conditions = placementFilter.get("conditions"); if (conditions.isArray()) { - PlacementFilter filter = createPlacementFilterComponent(conditions); + List filter = createPlacementFilterComponent(conditions); builder.placementFilter(filter); } } @@ -525,7 +566,13 @@ public class MappingsReader_v1 extends MappingsReader { * @return the {@link BoxComponent} */ private BoxComponent createBoxComponent(int id) { - BoundingBox boundingBox = BlockUtils.getCollision(id).getBoundingBoxes()[0]; + // Some blocks (e.g. plants) have no collision box + BlockCollision blockCollision = BlockUtils.getCollision(id); + if (blockCollision == null) { + return new BoxComponent(0, 0, 0, 0, 0, 0); + } + + BoundingBox boundingBox = blockCollision.getBoundingBoxes()[0]; float offsetX = (float) boundingBox.getSizeX() * 8; float offsetY = (float) boundingBox.getSizeY() * 8; @@ -536,13 +583,13 @@ public class MappingsReader_v1 extends MappingsReader { // 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 = 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 cornerX = MathUtils.clamp((float) boundingBox.getMiddleX() * 16 - 8 - offsetX, -8, 8); + float cornerY = MathUtils.clamp((float) boundingBox.getMiddleY() * 16 - offsetY, 0, 16); + float cornerZ = MathUtils.clamp((float) boundingBox.getMiddleZ() * 16 - 8 - offsetZ, -8, 8); - float sizeX = clamp((float) boundingBox.getSizeX() * 16, 0, 16); - float sizeY = clamp((float) boundingBox.getSizeY() * 16, 0, 16); - float sizeZ = clamp((float) boundingBox.getSizeZ() * 16, 0, 16); + float sizeX = MathUtils.clamp((float) boundingBox.getSizeX() * 16, 0, 16); + float sizeY = MathUtils.clamp((float) boundingBox.getSizeY() * 16, 0, 16); + float sizeZ = MathUtils.clamp((float) boundingBox.getSizeZ() * 16, 0, 16); BoxComponent boxComponent = new BoxComponent(cornerX, cornerY, cornerZ, sizeX, sizeY, sizeZ); @@ -563,17 +610,17 @@ public class MappingsReader_v1 extends MappingsReader { texture = node.get("texture").asText(); } - String renderMethod = "alpha_test"; + String renderMethod = "opaque"; if (node.has("render_method")) { renderMethod = node.get("render_method").asText(); } - boolean faceDimming = false; + boolean faceDimming = true; if (node.has("face_dimming")) { faceDimming = node.get("face_dimming").asBoolean(); } - boolean ambientOcclusion = false; + boolean ambientOcclusion = true; if (node.has("ambient_occlusion")) { ambientOcclusion = node.get("ambient_occlusion").asBoolean(); } @@ -582,12 +629,12 @@ public class MappingsReader_v1 extends MappingsReader { } /** - * Creates the {@link PlacementFilter} for the passed conditions node + * Creates the list of {@link PlacementConditions} for the passed conditions node * @param node the conditions node - * @return the {@link PlacementFilter} + * @return the list of {@link PlacementConditions} */ - private PlacementFilter createPlacementFilterComponent(JsonNode node) { - List conditions = new ArrayList<>(); + private List createPlacementFilterComponent(JsonNode node) { + List conditions = new ArrayList<>(); // The structure of the placement filter component is the most complex of the current components // Each condition effectively seperated into an two arrays: one of allowed faces, and one of blocks/block molang queries @@ -619,10 +666,10 @@ public class MappingsReader_v1 extends MappingsReader { } } - conditions.add(new Conditions(faces, blockFilters)); + conditions.add(new PlacementConditions(faces, blockFilters)); }); - return new PlacementFilter(conditions); + return conditions; } /** @@ -672,15 +719,4 @@ public class MappingsReader_v1 extends MappingsReader { return pairs; } - /** - * Clamps the given value between the given min and max - * @param value the value to clamp - * @param min the minimum value - * @param max the maximum value - * @return the clamped value - */ - private float clamp(float value, float min, float max) { - return Math.max(min, Math.min(max, value)); - } - } 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 fae38cd19..3df84799d 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 @@ -15,8 +15,8 @@ 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.component.placementfilter.Conditions.Face; -import org.geysermc.geyser.api.block.custom.component.placementfilter.PlacementFilter; +import org.geysermc.geyser.api.block.custom.component.PlacementConditions; +import org.geysermc.geyser.api.block.custom.component.PlacementConditions.Face; import org.geysermc.geyser.api.block.custom.property.CustomBlockProperty; import org.geysermc.geyser.api.block.custom.property.PropertyType; import org.geysermc.geyser.api.event.lifecycle.GeyserDefineCustomBlocksEvent; @@ -304,15 +304,15 @@ public class CustomBlockRegistryPopulator { * @param placementFilter the placement filter to convert * @return the NBT representation of the provided placement filter */ - private static List convertPlacementFilter(PlacementFilter placementFilter) { + private static List convertPlacementFilter(List placementFilter) { List conditions = new ArrayList<>(); - placementFilter.conditions().forEach((condition) -> { + placementFilter.forEach((condition) -> { NbtMapBuilder conditionBuilder = NbtMap.builder(); // allowed_faces on the network is represented by 6 bits for the 6 possible faces // the enum has the proper values for that face only, so we just bitwise OR them together byte allowedFaces = 0; - for (Face face : condition.allowedFaces()) { allowedFaces |= face.getValue(); } + for (Face face : condition.allowedFaces()) { allowedFaces |= (1 << face.ordinal()); } conditionBuilder.putByte("allowed_faces", allowedFaces); // block_filters is a list of either blocks or queries for block tags