Geyser/core/src/main/java/org/geysermc/geyser/registry/type/CustomSkull.java

167 lines
7.3 KiB
Java

/*
* 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.type;
import lombok.Data;
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.TransformationComponent;
import org.geysermc.geyser.level.block.GeyserCustomBlockComponents;
import org.geysermc.geyser.level.block.GeyserCustomBlockData;
import org.geysermc.geyser.level.block.GeyserGeometryComponent;
import org.geysermc.geyser.level.block.GeyserMaterialInstance;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
@Data
public class CustomSkull {
private final String skinHash;
private CustomBlockData customBlockData;
private static final String BITS_A_PROPERTY = "geyser_skull:bits_a";
private static final String BITS_B_PROPERTY = "geyser_skull:bits_b";
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.Builder()
.destructibleByMining(1.5f)
.materialInstance("*", new GeyserMaterialInstance.Builder()
.texture("geyser." + skinHash + "_player_skin")
.renderMethod("alpha_test")
.faceDimming(true)
.ambientOcclusion(true)
.build())
.lightDampening(0)
.placeAir(true)
.build();
List<CustomBlockPermutation> permutations = new ArrayList<>();
addDefaultPermutation(permutations);
addFloorPermutations(permutations);
addWallPermutations(permutations);
customBlockData = new GeyserCustomBlockData.Builder()
.name("player_skull_" + skinHash)
.components(components)
.intProperty(BITS_A_PROPERTY, IntStream.rangeClosed(0, 6).boxed().toList()) // This gives us exactly 21 block states
.intProperty(BITS_B_PROPERTY, IntStream.rangeClosed(0, 2).boxed().toList())
.permutations(permutations)
.build();
}
public CustomBlockState getWallBlockState(int wallDirection) {
wallDirection = switch (wallDirection) {
case 0 -> 2; // South
case 90 -> 3; // West
case 180 -> 0; // North
case 270 -> 1; // East
default -> throw new IllegalArgumentException("Unknown skull wall direction: " + wallDirection);
};
return customBlockData.blockStateBuilder()
.intProperty(BITS_A_PROPERTY, wallDirection + 1)
.intProperty(BITS_B_PROPERTY, 0)
.build();
}
public CustomBlockState getFloorBlockState(int floorRotation) {
return customBlockData.blockStateBuilder()
.intProperty(BITS_A_PROPERTY, (5 + floorRotation) % 7)
.intProperty(BITS_B_PROPERTY, (5 + floorRotation) / 7)
.build();
}
private void addDefaultPermutation(List<CustomBlockPermutation> permutations) {
CustomBlockComponents components = new GeyserCustomBlockComponents.Builder()
.geometry(new GeyserGeometryComponent.Builder()
.identifier("geometry.geyser.player_skull_hand")
.build())
.transformation(new TransformationComponent(0, 180, 0))
.build();
String condition = String.format("query.block_property('%s') == 0 && query.block_property('%s') == 0", BITS_A_PROPERTY, BITS_B_PROPERTY);
permutations.add(new CustomBlockPermutation(components, condition));
}
private void addFloorPermutations(List<CustomBlockPermutation> permutations) {
String[] quadrantNames = {"a", "b", "c", "d"};
for (int quadrant = 0; quadrant < 4; quadrant++) {
for (int i = 0; i < 4; i++) {
int floorRotation = 4 * quadrant + i;
CustomBlockComponents components = new GeyserCustomBlockComponents.Builder()
.selectionBox(FLOOR_BOX)
.collisionBox(FLOOR_BOX)
.geometry(new GeyserGeometryComponent.Builder()
.identifier("geometry.geyser.player_skull_floor_" + quadrantNames[i])
.build())
.transformation(new TransformationComponent(0, ROTATIONS[quadrant], 0))
.build();
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 CustomBlockPermutation(components, condition));
}
}
}
private void addWallPermutations(List<CustomBlockPermutation> permutations) {
for (int i = 0; i < 4; i++) {
CustomBlockComponents components = new GeyserCustomBlockComponents.Builder()
.selectionBox(WALL_BOX)
.collisionBox(WALL_BOX)
.geometry(new GeyserGeometryComponent.Builder()
.identifier("geometry.geyser.player_skull_wall")
.build())
.transformation(new TransformationComponent(0, ROTATIONS[i], 0))
.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));
}
}
}