Block mappings mostly done

This commit is contained in:
Joshua Castle 2023-01-02 02:14:55 -08:00
parent f4071f4945
commit fb15b94b7b
No known key found for this signature in database
GPG key ID: F674F38216C35D5D
10 changed files with 117 additions and 82 deletions

View file

@ -33,13 +33,14 @@ public interface CustomBlockComponents {
BoxComponent selectionBox();
BoxComponent collisionBox();
String displayName();
String geometry();
@NonNull Map<String, MaterialInstance> materialInstances();
Float destroyTime();
Float destructibleByMining();
Float friction();
@ -62,7 +63,7 @@ public interface CustomBlockComponents {
Builder materialInstance(@NonNull String name, @NonNull MaterialInstance materialInstance);
Builder destroyTime(Float destroyTime);
Builder destructibleByMining(Float destructibleByMining);
Builder friction(Float friction);

View file

@ -25,12 +25,8 @@
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;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import lombok.Value;
import java.util.Map;
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;
@ -38,8 +34,11 @@ 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;
import java.util.Set;
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 lombok.Value;
@Value
public class GeyserCustomBlockComponents implements CustomBlockComponents {
@ -48,7 +47,7 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents {
String displayName;
String geometry;
Map<String, MaterialInstance> materialInstances;
Float destroyTime;
Float destructibleByMining;
Float friction;
Integer lightEmission;
Integer lightDampening;
@ -65,7 +64,7 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents {
} else {
this.materialInstances = Object2ObjectMaps.unmodifiable(new Object2ObjectArrayMap<>(builder.materialInstances));
}
this.destroyTime = builder.destroyTime;
this.destructibleByMining = builder.destructibleByMining;
this.friction = builder.friction;
this.lightEmission = builder.lightEmission;
this.lightDampening = builder.lightDampening;
@ -99,8 +98,8 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents {
}
@Override
public Float destroyTime() {
return destroyTime;
public Float destructibleByMining() {
return destructibleByMining;
}
@Override
@ -134,7 +133,7 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents {
protected String displayName;
protected String geometry;
protected final Object2ObjectMap<String, MaterialInstance> materialInstances = new Object2ObjectOpenHashMap<>();
protected Float destroyTime;
protected Float destructibleByMining;
protected Float friction;
protected Integer lightEmission;
protected Integer lightDampening;
@ -192,11 +191,11 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents {
}
@Override
public Builder destroyTime(Float destroyTime) {
if (destroyTime != null && destroyTime < 0) {
throw new IllegalArgumentException("Destroy time must be non-negative");
public Builder destructibleByMining(Float destructibleByMining) {
if (destructibleByMining != null && destructibleByMining < 0) {
throw new IllegalArgumentException("Destructible by mining must be non-negative");
}
this.destroyTime = destroyTime;
this.destructibleByMining = destructibleByMining;
return this;
}

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.registry;
import it.unimi.dsi.fastutil.Pair;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
@ -32,12 +33,15 @@ import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import org.geysermc.geyser.api.block.custom.CustomBlockData;
import org.geysermc.geyser.api.block.custom.CustomBlockState;
import org.geysermc.geyser.registry.loader.CollisionRegistryLoader;
import org.geysermc.geyser.registry.loader.RegistryLoaders;
import org.geysermc.geyser.registry.populator.BlockRegistryPopulator;
import org.geysermc.geyser.registry.populator.CustomBlockRegistryPopulator;
import org.geysermc.geyser.registry.populator.CustomSkullRegistryPopulator;
import org.geysermc.geyser.registry.type.BlockMapping;
import org.geysermc.geyser.registry.type.BlockMappings;
import org.geysermc.geyser.registry.type.CustomSkull;
import org.geysermc.geyser.translator.collision.BlockCollision;
import org.geysermc.geyser.util.collection.Object2IntBiMap;
/**
@ -61,6 +65,11 @@ public class BlockRegistries {
*/
public static final ArrayRegistry<BlockMapping> JAVA_BLOCKS = ArrayRegistry.create(RegistryLoaders.empty(() -> new BlockMapping[] {}));
/**
* A mapped registry containing which holds block IDs to its {@link BlockCollision}.
*/
public static final IntMappedRegistry<BlockCollision> COLLISIONS;
/**
* A (bi)mapped registry containing the Java IDs to identifiers.
*/
@ -105,9 +114,13 @@ public class BlockRegistries {
static {
CustomSkullRegistryPopulator.populate();
BlockRegistryPopulator.populate();
COLLISIONS = IntMappedRegistry.create(Pair.of("org.geysermc.geyser.translator.collision.CollisionRemapper", "mappings/collision.json"), CollisionRegistryLoader::new);
CustomBlockRegistryPopulator.registerCustomBedrockBlocks();
BlockRegistryPopulator.registerBedrockBlocks();
}
public static void init() {
// no-op
}
}

View file

@ -36,7 +36,7 @@ import com.nukkitx.nbt.NbtMapBuilder;
import com.nukkitx.protocol.bedrock.BedrockPacket;
import com.nukkitx.protocol.bedrock.data.inventory.CraftingData;
import com.nukkitx.protocol.bedrock.data.inventory.PotionMixData;
import it.unimi.dsi.fastutil.Pair;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
@ -53,7 +53,6 @@ import org.geysermc.geyser.registry.type.EnchantmentData;
import org.geysermc.geyser.registry.type.ItemMappings;
import org.geysermc.geyser.registry.type.ParticleMapping;
import org.geysermc.geyser.registry.type.SoundMapping;
import org.geysermc.geyser.translator.collision.BlockCollision;
import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator;
import org.geysermc.geyser.translator.level.event.LevelEventTranslator;
import org.geysermc.geyser.translator.sound.SoundInteractionTranslator;
@ -96,11 +95,6 @@ public final class Registries {
*/
public static final SimpleMappedRegistry<BlockEntityType, BlockEntityTranslator> BLOCK_ENTITIES = SimpleMappedRegistry.create("org.geysermc.geyser.translator.level.block.entity.BlockEntity", BlockEntityRegistryLoader::new);
/**
* A mapped registry containing which holds block IDs to its {@link BlockCollision}.
*/
public static final IntMappedRegistry<BlockCollision> COLLISIONS = IntMappedRegistry.create(Pair.of("org.geysermc.geyser.translator.collision.CollisionRemapper", "mappings/collision.json"), CollisionRegistryLoader::new);
/**
* A versioned registry which holds a {@link RecipeType} to a corresponding list of {@link CraftingData}.
*/

View file

@ -46,6 +46,7 @@ import org.geysermc.geyser.level.block.GeyserCustomBlockData.CustomBlockDataBuil
import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.mappings.util.BlockPropertyTypeMaps;
import org.geysermc.geyser.registry.type.BlockMapping;
import org.geysermc.geyser.util.BlockUtils;
import java.nio.file.Path;
@ -203,11 +204,11 @@ public class MappingsReader_v1 extends MappingsReader {
.stream()
.filter(s -> s.startsWith(identifier + "["))
.collect(Collectors.toList());
if (defaultStates.isEmpty()) defaultStates.add("");
if (defaultStates.isEmpty()) defaultStates.add(identifier);
CustomBlockDataBuilder customBlockDataBuilder = new CustomBlockDataBuilder();
customBlockDataBuilder.name(name)
.components(createCustomBlockComponents(node, defaultStates.get(0), identifier, name))
.components(createCustomBlockComponents(node, defaultStates.get(0), name))
.permutations(createCustomBlockPermutations(stateOverrides, identifier, name))
.booleanProperty("geyser_custom:default");
@ -232,9 +233,7 @@ public class MappingsReader_v1 extends MappingsReader {
String key = entry.getKey();
JsonNode value = entry.getValue();
if (value.isObject()) {
value.forEach(data -> {
permutations.add(new CustomBlockPermutation(createCustomBlockComponents(data, key, identifier, name), createCustomBlockPropertyQuery(key)));
});
permutations.add(new CustomBlockPermutation(createCustomBlockComponents(value, (identifier + key), name), createCustomBlockPropertyQuery(key)));
}
});
}
@ -324,20 +323,22 @@ public class MappingsReader_v1 extends MappingsReader {
return new BlockPropertyTypeMaps(stringValuesMap, stateKeyStrings, intValuesMap, stateKeyInts, booleanValuesSet, stateKeyBools);
}
private CustomBlockComponents createCustomBlockComponents(JsonNode node, String state, String identifier, String name) {
String stateIdentifier = identifier + state;
int id = BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(stateIdentifier, -1);
private CustomBlockComponents createCustomBlockComponents(JsonNode node, String stateKey, String name) {
int id = BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(stateKey, -1);
CustomBlockComponentsBuilder builder = new CustomBlockComponentsBuilder();
// .destroyTime()
// .friction()
// .placeAir()
BoundingBox boundingBox = BlockUtils.getCollision(id).getBoundingBoxes()[0];
BoxComponent boxComponent = new BoxComponent(
(float) boundingBox.getMiddleX(), (float) boundingBox.getMiddleY(), (float) boundingBox.getMiddleZ(),
(float) boundingBox.getSizeX(), (float) boundingBox.getSizeY(), (float) boundingBox.getSizeZ());
BoxComponent boxComponent = createBoxComponent(id);
builder.selectionBox(boxComponent).collisionBox(boxComponent);
// 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
float destructibleByMining = BlockRegistries.JAVA_BLOCKS.getOrDefault(id, BlockMapping.AIR).getHardness() * 3.25F;
if (node.has("destructible_by_mining")) {
destructibleByMining = node.get("destructible_by_mining").floatValue();
}
builder.destructibleByMining(destructibleByMining);
if (node.has("geometry")) {
builder.geometry(node.get("geometry").asText());
}
@ -375,29 +376,8 @@ public class MappingsReader_v1 extends MappingsReader {
String key = entry.getKey();
JsonNode value = entry.getValue();
if (value.isObject()) {
value.forEach(data -> {
String texture = name;
if (node.has("texture")) {
texture = data.get("texture").asText();
}
String renderMethod = data.get("render_method").asText();
if (node.has("render_method")) {
renderMethod = data.get("render_method").asText();
}
boolean faceDimming = false;
if (node.has("face_dimming")) {
faceDimming = data.get("face_dimming").asBoolean();
}
boolean ambientOcclusion = false;
if (node.has("ambient_occlusion")) {
ambientOcclusion = data.get("ambient_occlusion").asBoolean();
}
builder.materialInstance(key, new MaterialInstance(texture, renderMethod, faceDimming, ambientOcclusion));
});
MaterialInstance materialInstance = createMaterialInstanceComponent(value, name);
builder.materialInstance(key, materialInstance);
}
});
}
@ -408,20 +388,65 @@ public class MappingsReader_v1 extends MappingsReader {
return components;
}
private BoxComponent createBoxComponent(int id) {
BoundingBox boundingBox = BlockUtils.getCollision(id).getBoundingBoxes()[0];
float offsetX = (float) boundingBox.getSizeX() * 8;
float offsetY = (float) boundingBox.getSizeY() * 8;
float offsetZ = (float) boundingBox.getSizeZ() * 8;
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 sizeX = clamp((float) boundingBox.getSizeX() * 16, -8, 8);
float sizeY = clamp((float) boundingBox.getSizeY() * 16, 0, 16);
float sizeZ = clamp((float) boundingBox.getSizeZ() * 16, -8, 8);
BoxComponent boxComponent = new BoxComponent(cornerX, cornerY, cornerZ, sizeX, sizeY, sizeZ);
return boxComponent;
}
private MaterialInstance createMaterialInstanceComponent(JsonNode node, String name) {
String texture = name;
if (node.has("texture")) {
texture = node.get("texture").asText();
}
String renderMethod = "alpha_test";
if (node.has("render_method")) {
renderMethod = node.get("render_method").asText();
}
boolean faceDimming = false;
if (node.has("face_dimming")) {
faceDimming = node.get("face_dimming").asBoolean();
}
boolean ambientOcclusion = false;
if (node.has("ambient_occlusion")) {
ambientOcclusion = node.get("ambient_occlusion").asBoolean();
}
return new MaterialInstance(texture, renderMethod, faceDimming, ambientOcclusion);
}
private String createCustomBlockPropertyQuery(String state) {
String[] conditions = splitStateString(state);
String[] queries = new String[conditions.length];
for (int i = 0; i < conditions.length; i++) {
String[] keyval = conditions[i].split("=", 2);
if (keyval[1].equals("true")) {
queries[i] = String.format("q.block_property('%s') == %b", keyval[0], 1);
queries[i] = String.format("q.block_property('%1$s') == %2$s", keyval[0], 1);
} else if (keyval[1].equals("false")) {
queries[i] = String.format("q.block_property('%s') == %b", keyval[0], 0);
} else if (keyval[1].matches("-?\\d+")) {
queries[i] = String.format("q.block_property('%s') == %b", keyval[0], Integer.parseInt(keyval[1]));
queries[i] = String.format("q.block_property('%1$s') == %2$s", keyval[0], 0);
} else if (CharMatcher.inRange('0', '9').matchesAllOf(keyval[1])) {
queries[i] = String.format("q.block_property('%1$s') == %2$s", keyval[0], Integer.parseInt(keyval[1]));
} else {
queries[i] = String.format("q.block_property('%s') == '%b'", keyval[0], keyval[1]);
queries[i] = String.format("q.block_property('%1$s') == '%2$s'", keyval[0], keyval[1]);
}
}
@ -441,4 +466,8 @@ public class MappingsReader_v1 extends MappingsReader {
return pairs;
}
public float clamp(float value, float min, float max) {
return Math.max(min, Math.min(value, max));
}
}

View file

@ -78,13 +78,13 @@ public final class BlockRegistryPopulator {
public static void populate() {
registerJavaBlocks();
CustomBlockRegistryPopulator.registerCustomBedrockBlocks();
registerBedrockBlocks();
// CustomBlockRegistryPopulator.registerCustomBedrockBlocks() and registerBedrockBlocks() moved to BlockRegistries to ensure correct load order
BLOCKS_JSON = null;
// Needs to be placed somewhere at some point
//BLOCKS_JSON = null;
}
private static void registerBedrockBlocks() {
public static void registerBedrockBlocks() {
BiFunction<String, NbtMapBuilder, String> emptyMapper = (bedrockIdentifier, statesBuilder) -> null;
ImmutableMap<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>> blockMappers = ImmutableMap.<ObjectIntPair<String>, BiFunction<String, NbtMapBuilder, String>>builder()
.put(ObjectIntPair.of("1_19_20", Bedrock_v544.V544_CODEC.getProtocolVersion()), emptyMapper)

View file

@ -32,7 +32,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class CustomBlockRegistryPopulator {
static void registerCustomBedrockBlocks() {
public static void registerCustomBedrockBlocks() {
if (!GeyserImpl.getInstance().getConfig().isAddCustomBlocks()) {
return;
}
@ -81,7 +81,6 @@ public class CustomBlockRegistryPopulator {
customBlocks.add(block.data());
block.states().forEach((javaIdentifier, customBlockState) -> {
int id = BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(javaIdentifier, -1);
GeyserImpl.getInstance().getLogger().info("CUSTOM RUNTIME ID: " + id + " for " + javaIdentifier);
blockStateOverrides.put(id, customBlockState);
});
});
@ -188,9 +187,9 @@ public class CustomBlockRegistryPopulator {
.putCompound("materials", materialsBuilder.build())
.build());
}
if (components.destroyTime() != null) {
if (components.destructibleByMining() != null) {
builder.putCompound("minecraft:destructible_by_mining", NbtMap.builder()
.putFloat("value", components.destroyTime())
.putFloat("value", components.destructibleByMining())
.build());
}
if (components.friction() != null) {

View file

@ -65,7 +65,7 @@ public class CustomSkull {
this.skinHash = skinHash;
CustomBlockComponents components = new GeyserCustomBlockComponents.CustomBlockComponentsBuilder()
.destroyTime(1.5f)
.destructibleByMining(1.5f)
.materialInstance("*", new MaterialInstance("geyser." + skinHash + "_player_skin", "alpha_test", true, true))
.lightDampening(0)
.placeAir(true)

View file

@ -43,7 +43,7 @@ import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.level.physics.CollisionManager;
import org.geysermc.geyser.level.physics.Direction;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.PistonCache;
import org.geysermc.geyser.translator.collision.BlockCollision;
@ -96,7 +96,7 @@ public class PistonBlockEntity {
static {
// Create a ~1 x ~0.5 x ~1 bounding box above the honey block
BlockCollision blockCollision = Registries.COLLISIONS.get(BlockStateValues.JAVA_HONEY_BLOCK_ID);
BlockCollision blockCollision = BlockRegistries.COLLISIONS.get(BlockStateValues.JAVA_HONEY_BLOCK_ID);
if (blockCollision == null) {
throw new RuntimeException("Failed to find honey block collision");
}
@ -486,7 +486,7 @@ public class PistonBlockEntity {
pistonCache.displacePlayer(movement.mul(delta));
} else {
// Move the player out of collision
BlockCollision blockCollision = Registries.COLLISIONS.get(javaId);
BlockCollision blockCollision = BlockRegistries.COLLISIONS.get(javaId);
if (blockCollision != null) {
Vector3d extend = movement.mul(Math.min(1 - blockMovement, 0.5));
Direction movementDirection = orientation;

View file

@ -30,7 +30,7 @@ import com.nukkitx.math.vector.Vector3i;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.inventory.PlayerInventory;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.type.BlockMapping;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
@ -219,7 +219,7 @@ public final class BlockUtils {
}
public static BlockCollision getCollision(int blockId) {
return Registries.COLLISIONS.get(blockId);
return BlockRegistries.COLLISIONS.get(blockId);
}
public static BlockCollision getCollisionAt(GeyserSession session, Vector3i blockPos) {