3
0
Mirror von https://github.com/GeyserMC/Geyser.git synchronisiert 2024-11-19 22:40:18 +01:00

Extended collision boxes actually work

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>
Dieser Commit ist enthalten in:
Joshua Castle 2023-03-12 18:53:10 -07:00
Ursprung 550a4725ef
Commit 7f85e909b8
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: F674F38216C35D5D
9 geänderte Dateien mit 168 neuen und 76 gelöschten Zeilen

Datei anzeigen

@ -51,13 +51,6 @@ public interface CustomBlockComponents {
*/ */
BoxComponent collisionBox(); BoxComponent collisionBox();
/**
* Gets the extended collision box
* Places an invisible collision block above the block to prevent players from jumping on top of it, if defined
* @return The extended collision box.
*/
BoxComponent extendedCollisionBox();
/** /**
* Gets the display name component * Gets the display name component
* Equivalent to "minecraft:display_name" * Equivalent to "minecraft:display_name"
@ -160,8 +153,6 @@ public interface CustomBlockComponents {
Builder collisionBox(BoxComponent collisionBox); Builder collisionBox(BoxComponent collisionBox);
Builder extendedCollisionBox(BoxComponent extendedCollisionBox);
Builder displayName(String displayName); Builder displayName(String displayName);
Builder geometry(String geometry); Builder geometry(String geometry);

Datei anzeigen

@ -42,7 +42,6 @@ public final class Constants {
static final String SAVED_REFRESH_TOKEN_FILE = "saved-refresh-tokens.json"; static final String SAVED_REFRESH_TOKEN_FILE = "saved-refresh-tokens.json";
public static final String GEYSER_CUSTOM_NAMESPACE = "geyser_custom"; public static final String GEYSER_CUSTOM_NAMESPACE = "geyser_custom";
public static final String GEYSER_NAMESPACE = "geyser";
public static final String MINECRAFT_SKIN_SERVER_URL = "https://textures.minecraft.net/texture/"; public static final String MINECRAFT_SKIN_SERVER_URL = "https://textures.minecraft.net/texture/";

Datei anzeigen

@ -47,7 +47,6 @@ import java.util.Set;
public class GeyserCustomBlockComponents implements CustomBlockComponents { public class GeyserCustomBlockComponents implements CustomBlockComponents {
BoxComponent selectionBox; BoxComponent selectionBox;
BoxComponent collisionBox; BoxComponent collisionBox;
BoxComponent extendedCollisionBox;
String displayName; String displayName;
String geometry; String geometry;
Map<String, MaterialInstance> materialInstances; Map<String, MaterialInstance> materialInstances;
@ -64,7 +63,6 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents {
private GeyserCustomBlockComponents(CustomBlockComponentsBuilder builder) { private GeyserCustomBlockComponents(CustomBlockComponentsBuilder builder) {
this.selectionBox = builder.selectionBox; this.selectionBox = builder.selectionBox;
this.collisionBox = builder.collisionBox; this.collisionBox = builder.collisionBox;
this.extendedCollisionBox = builder.extendedCollisionBox;
this.displayName = builder.displayName; this.displayName = builder.displayName;
this.geometry = builder.geometry; this.geometry = builder.geometry;
if (builder.materialInstances.isEmpty()) { if (builder.materialInstances.isEmpty()) {
@ -97,11 +95,6 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents {
return collisionBox; return collisionBox;
} }
@Override
public BoxComponent extendedCollisionBox() {
return extendedCollisionBox;
}
@Override @Override
public String displayName() { public String displayName() {
return displayName; return displayName;
@ -165,7 +158,6 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents {
public static class CustomBlockComponentsBuilder implements Builder { public static class CustomBlockComponentsBuilder implements Builder {
protected BoxComponent selectionBox; protected BoxComponent selectionBox;
protected BoxComponent collisionBox; protected BoxComponent collisionBox;
protected BoxComponent extendedCollisionBox;
protected String displayName; protected String displayName;
protected String geometry; protected String geometry;
protected final Object2ObjectMap<String, MaterialInstance> materialInstances = new Object2ObjectOpenHashMap<>(); protected final Object2ObjectMap<String, MaterialInstance> materialInstances = new Object2ObjectOpenHashMap<>();
@ -211,13 +203,6 @@ public class GeyserCustomBlockComponents implements CustomBlockComponents {
return this; return this;
} }
@Override
public Builder extendedCollisionBox(BoxComponent extendedCollisionBox) {
validateBox(extendedCollisionBox);
this.extendedCollisionBox = extendedCollisionBox;
return this;
}
@Override @Override
public Builder displayName(String displayName) { public Builder displayName(String displayName) {
this.displayName = displayName; this.displayName = displayName;

Datei anzeigen

@ -0,0 +1,33 @@
/*
* 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.mappings.util;
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;
public record CustomBlockComponentsMapping(@NonNull CustomBlockComponents components, BoxComponent extendedCollisionBox) {
}

Datei anzeigen

@ -29,12 +29,11 @@ import java.util.Map;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.api.block.custom.CustomBlockData;
import org.geysermc.geyser.api.block.custom.CustomBlockState;
/** /**
* This class is used to store a custom block mappings, which contain all of the * This class is used to store a custom block mappings, which contain all of the
* data required to register a custom block that overrides a group of java block * data required to register a custom block that overrides a group of java block
* states. * states.
*/ */
public record CustomBlockMapping(@NonNull CustomBlockData data, @NonNull Map<String, CustomBlockState> states, @NonNull String javaIdentifier, boolean overrideItem) { public record CustomBlockMapping(@NonNull CustomBlockData data, @NonNull Map<String, CustomBlockStateMapping> states, @NonNull String javaIdentifier, boolean overrideItem) {
} }

Datei anzeigen

@ -0,0 +1,35 @@
/*
* 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.mappings.util;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.api.block.custom.CustomBlockState;
import org.geysermc.geyser.api.block.custom.component.BoxComponent;
import java.util.function.Function;
public record CustomBlockStateBuilderMapping(@NonNull Function<CustomBlockState.Builder, CustomBlockState> builder, BoxComponent extendedCollisionBox) {
}

Datei anzeigen

@ -0,0 +1,33 @@
/*
* 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.mappings.util;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.api.block.custom.CustomBlockState;
import org.geysermc.geyser.api.block.custom.component.BoxComponent;
public record CustomBlockStateMapping(@NonNull CustomBlockState state, BoxComponent extendedCollisionBox) {
}

Datei anzeigen

@ -44,7 +44,10 @@ import org.geysermc.geyser.level.block.GeyserCustomBlockComponents.CustomBlockCo
import org.geysermc.geyser.level.block.GeyserCustomBlockData.CustomBlockDataBuilder; import org.geysermc.geyser.level.block.GeyserCustomBlockData.CustomBlockDataBuilder;
import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.mappings.util.CustomBlockComponentsMapping;
import org.geysermc.geyser.registry.mappings.util.CustomBlockMapping; import org.geysermc.geyser.registry.mappings.util.CustomBlockMapping;
import org.geysermc.geyser.registry.mappings.util.CustomBlockStateBuilderMapping;
import org.geysermc.geyser.registry.mappings.util.CustomBlockStateMapping;
import org.geysermc.geyser.translator.collision.BlockCollision; import org.geysermc.geyser.translator.collision.BlockCollision;
import org.geysermc.geyser.util.BlockUtils; import org.geysermc.geyser.util.BlockUtils;
import org.geysermc.geyser.util.MathUtils; import org.geysermc.geyser.util.MathUtils;
@ -194,13 +197,14 @@ public class MappingsReader_v1 extends MappingsReader {
if (BlockRegistries.JAVA_IDENTIFIERS.get().containsKey(identifier)) { if (BlockRegistries.JAVA_IDENTIFIERS.get().containsKey(identifier)) {
// There is only one Java block state to override // There is only one Java block state to override
CustomBlockComponentsMapping componentsMapping = createCustomBlockComponentsMapping(node, identifier, name);
CustomBlockData blockData = customBlockDataBuilder CustomBlockData blockData = customBlockDataBuilder
.components(createCustomBlockComponents(node, identifier, name)) .components(componentsMapping.components())
.build(); .build();
return new CustomBlockMapping(blockData, Map.of(identifier, blockData.defaultBlockState()), identifier, !onlyOverrideStates); return new CustomBlockMapping(blockData, Map.of(identifier, new CustomBlockStateMapping(blockData.defaultBlockState(), componentsMapping.extendedCollisionBox())), identifier, !onlyOverrideStates);
} }
Map<String, CustomBlockComponents> componentsMap = new LinkedHashMap<>(); Map<String, CustomBlockComponentsMapping> componentsMap = new LinkedHashMap<>();
JsonNode stateOverrides = node.get("state_overrides"); JsonNode stateOverrides = node.get("state_overrides");
if (stateOverrides != null && stateOverrides.isObject()) { if (stateOverrides != null && stateOverrides.isObject()) {
@ -212,7 +216,7 @@ public class MappingsReader_v1 extends MappingsReader {
if (!BlockRegistries.JAVA_IDENTIFIERS.get().containsKey(state)) { if (!BlockRegistries.JAVA_IDENTIFIERS.get().containsKey(state)) {
throw new InvalidCustomMappingsFileException("Unknown Java block state: " + state + " for state_overrides."); throw new InvalidCustomMappingsFileException("Unknown Java block state: " + state + " for state_overrides.");
} }
componentsMap.put(state, createCustomBlockComponents(overrideEntry.getValue(), state, name)); componentsMap.put(state, createCustomBlockComponentsMapping(overrideEntry.getValue(), state, name));
} }
} }
if (componentsMap.isEmpty() && onlyOverrideStates) { if (componentsMap.isEmpty() && onlyOverrideStates) {
@ -225,7 +229,7 @@ public class MappingsReader_v1 extends MappingsReader {
.stream() .stream()
.filter(s -> s.startsWith(identifier + "[")) .filter(s -> s.startsWith(identifier + "["))
.filter(Predicate.not(componentsMap::containsKey)) .filter(Predicate.not(componentsMap::containsKey))
.forEach(state -> componentsMap.put(state, createCustomBlockComponents(null, state, name))); .forEach(state -> componentsMap.put(state, createCustomBlockComponentsMapping(null, state, name)));
} }
if (componentsMap.isEmpty()) { if (componentsMap.isEmpty()) {
@ -235,20 +239,21 @@ public class MappingsReader_v1 extends MappingsReader {
// We pass in the first state and just use the hitbox from that as the default // We pass in the first state and just use the hitbox from that as the default
// Each state will have its own so this is fine // Each state will have its own so this is fine
String firstState = componentsMap.keySet().iterator().next(); String firstState = componentsMap.keySet().iterator().next();
customBlockDataBuilder.components(createCustomBlockComponents(node, firstState, name)); CustomBlockComponentsMapping firstComponentsMapping = createCustomBlockComponentsMapping(node, firstState, name);
customBlockDataBuilder.components(firstComponentsMapping.components());
return createCustomBlockMapping(customBlockDataBuilder, componentsMap, identifier, !onlyOverrideStates); return createCustomBlockMapping(customBlockDataBuilder, componentsMap, identifier, !onlyOverrideStates);
} }
private CustomBlockMapping createCustomBlockMapping(CustomBlockData.Builder customBlockDataBuilder, Map<String, CustomBlockComponents> componentsMap, String identifier, boolean overrideItem) { private CustomBlockMapping createCustomBlockMapping(CustomBlockData.Builder customBlockDataBuilder, Map<String, CustomBlockComponentsMapping> componentsMap, String identifier, boolean overrideItem) {
Map<String, LinkedHashSet<String>> valuesMap = new Object2ObjectOpenHashMap<>(); Map<String, LinkedHashSet<String>> valuesMap = new Object2ObjectOpenHashMap<>();
List<CustomBlockPermutation> permutations = new ArrayList<>(); List<CustomBlockPermutation> permutations = new ArrayList<>();
Map<String, Function<CustomBlockState.Builder, CustomBlockState>> blockStateBuilders = new Object2ObjectOpenHashMap<>(); Map<String, CustomBlockStateBuilderMapping> blockStateBuilders = new Object2ObjectOpenHashMap<>();
// For each Java block state, extract the property values, create a CustomBlockPermutation, // For each Java block state, extract the property values, create a CustomBlockPermutation,
// and a CustomBlockState builder // and a CustomBlockState builder
for (Map.Entry<String, CustomBlockComponents> entry : componentsMap.entrySet()) { for (Map.Entry<String, CustomBlockComponentsMapping> entry : componentsMap.entrySet()) {
String state = entry.getKey(); String state = entry.getKey();
String[] pairs = splitStateString(state); String[] pairs = splitStateString(state);
@ -267,8 +272,8 @@ public class MappingsReader_v1 extends MappingsReader {
blockStateBuilder = blockStateBuilder.andThen(builder -> builder.stringProperty(property, value)); blockStateBuilder = blockStateBuilder.andThen(builder -> builder.stringProperty(property, value));
} }
permutations.add(new CustomBlockPermutation(entry.getValue(), String.join(" && ", conditions))); permutations.add(new CustomBlockPermutation(entry.getValue().components(), String.join(" && ", conditions)));
blockStateBuilders.put(state, blockStateBuilder.andThen(CustomBlockState.Builder::build)); blockStateBuilders.put(state, new CustomBlockStateBuilderMapping(blockStateBuilder.andThen(CustomBlockState.Builder::build), entry.getValue().extendedCollisionBox()));
} }
valuesMap.forEach((key, value) -> customBlockDataBuilder.stringProperty(key, new ArrayList<>(value))); valuesMap.forEach((key, value) -> customBlockDataBuilder.stringProperty(key, new ArrayList<>(value)));
@ -277,8 +282,8 @@ public class MappingsReader_v1 extends MappingsReader {
.permutations(permutations) .permutations(permutations)
.build(); .build();
// Build CustomBlockStates for each Java block state we wish to override // Build CustomBlockStates for each Java block state we wish to override
Map<String, CustomBlockState> states = blockStateBuilders.entrySet().stream() Map<String, CustomBlockStateMapping> states = blockStateBuilders.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().apply(customBlockData.blockStateBuilder()))); .collect(Collectors.toMap(Map.Entry::getKey, e -> new CustomBlockStateMapping(e.getValue().builder().apply(customBlockData.blockStateBuilder()), e.getValue().extendedCollisionBox())));
return new CustomBlockMapping(customBlockData, states, identifier, overrideItem); return new CustomBlockMapping(customBlockData, states, identifier, overrideItem);
} }
@ -290,19 +295,18 @@ public class MappingsReader_v1 extends MappingsReader {
* @param name the name of the custom block * @param name the name of the custom block
* @return the {@link CustomBlockComponents} object * @return the {@link CustomBlockComponents} object
*/ */
private CustomBlockComponents createCustomBlockComponents(JsonNode node, String stateKey, String name) { private CustomBlockComponentsMapping createCustomBlockComponentsMapping(JsonNode node, String stateKey, String name) {
// This is needed to find the correct selection box for the given block // This is needed to find the correct selection box for the given block
int id = BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(stateKey, -1); int id = BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(stateKey, -1);
BoxComponent boxComponent = createBoxComponent(id, 0, 16, 0); BoxComponent boxComponent = createBoxComponent(id);
BoxComponent extendedBoxComponent = createBoxComponent(id, 16, 32, -16); BoxComponent extendedBoxComponent = createExtendedBoxComponent(id);
CustomBlockComponents.Builder builder = new CustomBlockComponentsBuilder() CustomBlockComponents.Builder builder = new CustomBlockComponentsBuilder()
.collisionBox(boxComponent) .collisionBox(boxComponent)
.selectionBox(boxComponent) .selectionBox(boxComponent);
.extendedCollisionBox(extendedBoxComponent);
if (node == null) { if (node == null) {
// No other components were defined // No other components were defined
return builder.build(); return new CustomBlockComponentsMapping(builder.build(), extendedBoxComponent);
} }
BoxComponent selectionBox = createBoxComponent(node.get("selection_box")); BoxComponent selectionBox = createBoxComponent(node.get("selection_box"));
@ -315,7 +319,7 @@ public class MappingsReader_v1 extends MappingsReader {
} }
BoxComponent extendedCollisionBox = createBoxComponent(node.get("extended_collision_box")); BoxComponent extendedCollisionBox = createBoxComponent(node.get("extended_collision_box"));
if (extendedCollisionBox != null) { if (extendedCollisionBox != null) {
builder.extendedCollisionBox(extendedCollisionBox); extendedBoxComponent = extendedCollisionBox;
} }
@ -404,11 +408,11 @@ public class MappingsReader_v1 extends MappingsReader {
builder.tags(tagsSet); builder.tags(tagsSet);
} }
return builder.build(); return new CustomBlockComponentsMapping(builder.build(), extendedBoxComponent);
} }
/** /**
* Creates a {@link BoxComponent} based on a Java block's collision * Creates a {@link BoxComponent} based on a Java block's collision with provided bounds and offsets
* @param javaId the block's Java ID * @param javaId the block's Java ID
* @param minHeight the minimum height of the box * @param minHeight the minimum height of the box
* @param maxHeight the maximum height of the box * @param maxHeight the maximum height of the box
@ -428,11 +432,6 @@ public class MappingsReader_v1 extends MappingsReader {
float offsetY = (float) boundingBox.getSizeY() * 8; float offsetY = (float) boundingBox.getSizeY() * 8;
float offsetZ = (float) boundingBox.getSizeZ() * 8; float offsetZ = (float) boundingBox.getSizeZ() * 8;
// Unfortunately we need to clamp the values here to an effective size of one block
// This is quite a pain for anything like fences, as the player can just jump over them
// 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 = MathUtils.clamp((float) boundingBox.getMiddleX() * 16 - 8 - offsetX, -8, 8); float cornerX = MathUtils.clamp((float) boundingBox.getMiddleX() * 16 - 8 - offsetX, -8, 8);
float cornerY = MathUtils.clamp((float) boundingBox.getMiddleY() * 16 - offsetY, minHeight, maxHeight); float cornerY = MathUtils.clamp((float) boundingBox.getMiddleY() * 16 - offsetY, minHeight, maxHeight);
float cornerZ = MathUtils.clamp((float) boundingBox.getMiddleZ() * 16 - 8 - offsetZ, -8, 8); float cornerZ = MathUtils.clamp((float) boundingBox.getMiddleZ() * 16 - 8 - offsetZ, -8, 8);
@ -444,6 +443,35 @@ public class MappingsReader_v1 extends MappingsReader {
return new BoxComponent(cornerX, cornerY + heightTranslation, cornerZ, sizeX, sizeY + heightTranslation, sizeZ); return new BoxComponent(cornerX, cornerY + heightTranslation, cornerZ, sizeX, sizeY + heightTranslation, sizeZ);
} }
/**
* Creates a {@link BoxComponent} based on a Java block's collision
* @param javaId the block's Java ID
* @return the {@link BoxComponent}
*/
private BoxComponent createBoxComponent(int javaId) {
return createBoxComponent(javaId, 0, 16, 0);
}
/**
* Creates the {@link BoxComponent} for an extended collision box based on a Java block's collision
* @param javaId the block's Java ID
* @return the {@link BoxComponent} or null if the block's collision box would not exceed 16 y units
*/
private BoxComponent createExtendedBoxComponent(int javaId) {
BlockCollision blockCollision = BlockUtils.getCollision(javaId);
if (blockCollision == null) {
return null;
}
BoundingBox boundingBox = blockCollision.getBoundingBoxes()[0];
float offsetY = (float) boundingBox.getSizeY() * 8;
float cornerY = (float) boundingBox.getMiddleY() * 16 - offsetY;
float sizeY = (float) boundingBox.getSizeY() * 16;
if (cornerY > 16 || sizeY > 16) {
return createBoxComponent(javaId, 16, 32, -16);
}
return null;
}
/** /**
* Creates a {@link BoxComponent} from a JSON Node * Creates a {@link BoxComponent} from a JSON Node
* @param node the JSON node * @param node the JSON node

Datei anzeigen

@ -48,9 +48,6 @@ public class CustomBlockRegistryPopulator {
Set<CustomBlockData> customBlocks = new ObjectOpenHashSet<>(); Set<CustomBlockData> customBlocks = new ObjectOpenHashSet<>();
Int2ObjectMap<CustomBlockState> blockStateOverrides = new Int2ObjectOpenHashMap<>(); Int2ObjectMap<CustomBlockState> blockStateOverrides = new Int2ObjectOpenHashMap<>();
Map<String, CustomBlockData> customBlockItemOverrides = new HashMap<>(); Map<String, CustomBlockData> customBlockItemOverrides = new HashMap<>();
Map<CustomBlockData, Set<Integer>> extendedCollisionBoxes = new HashMap<>();
Map<BoxComponent, CustomBlockData> extendedCollisionBoxSet = new HashMap<>();
int[] extendedCollisionIndex = {0};
GeyserImpl.getInstance().getEventBus().fire(new GeyserDefineCustomBlocksEvent() { GeyserImpl.getInstance().getEventBus().fire(new GeyserDefineCustomBlocksEvent() {
@Override @Override
@ -77,20 +74,6 @@ public class CustomBlockRegistryPopulator {
throw new IllegalArgumentException("Custom block is unregistered. Name: " + customBlockState.name()); throw new IllegalArgumentException("Custom block is unregistered. Name: " + customBlockState.name());
} }
CustomBlockState oldBlockState = blockStateOverrides.put(id, customBlockState); CustomBlockState oldBlockState = blockStateOverrides.put(id, customBlockState);
BoxComponent extendedCollisionBox = customBlockState.block().components().extendedCollisionBox();
if (extendedCollisionBox != null) {
CustomBlockData extendedCollisionBlock = extendedCollisionBoxSet.getOrDefault(extendedCollisionBox, null);
if (extendedCollisionBlock == null) {
extendedCollisionBlock = createExtendedCollisionBlock(extendedCollisionBox, extendedCollisionIndex[0]++);
extendedCollisionBoxes.put(extendedCollisionBlock, new HashSet<>(id));
customBlocks.add(extendedCollisionBlock);
extendedCollisionBoxSet.put(extendedCollisionBox, extendedCollisionBlock);
} else {
Set<Integer> existingJavaIds = extendedCollisionBoxes.getOrDefault(extendedCollisionBlock, new HashSet<>());
existingJavaIds.add(id);
extendedCollisionBoxes.put(extendedCollisionBlock, existingJavaIds);
}
}
if (oldBlockState != null) { if (oldBlockState != null) {
GeyserImpl.getInstance().getLogger().debug("Duplicate block state override for Java Identifier: " + GeyserImpl.getInstance().getLogger().debug("Duplicate block state override for Java Identifier: " +
javaIdentifier + " Old override: " + oldBlockState.name() + " New override: " + customBlockState.name()); javaIdentifier + " Old override: " + oldBlockState.name() + " New override: " + customBlockState.name());
@ -110,6 +93,9 @@ public class CustomBlockRegistryPopulator {
customBlocks.add(customSkull.getCustomBlockData()); customBlocks.add(customSkull.getCustomBlockData());
} }
Map<CustomBlockData, Set<Integer>> extendedCollisionBoxes = new HashMap<>();
Map<BoxComponent, CustomBlockData> extendedCollisionBoxSet = new HashMap<>();
int[] extendedCollisionIndex = {0};
MappingsConfigReader mappingsConfigReader = new MappingsConfigReader(); MappingsConfigReader mappingsConfigReader = new MappingsConfigReader();
mappingsConfigReader.loadBlockMappingsFromJson((key, block) -> { mappingsConfigReader.loadBlockMappingsFromJson((key, block) -> {
customBlocks.add(block.data()); customBlocks.add(block.data());
@ -118,13 +104,13 @@ public class CustomBlockRegistryPopulator {
} }
block.states().forEach((javaIdentifier, customBlockState) -> { block.states().forEach((javaIdentifier, customBlockState) -> {
int id = BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(javaIdentifier, -1); int id = BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(javaIdentifier, -1);
blockStateOverrides.put(id, customBlockState); blockStateOverrides.put(id, customBlockState.state());
BoxComponent extendedCollisionBox = customBlockState.block().components().extendedCollisionBox(); BoxComponent extendedCollisionBox = customBlockState.extendedCollisionBox();
if (extendedCollisionBox != null) { if (extendedCollisionBox != null) {
CustomBlockData extendedCollisionBlock = extendedCollisionBoxSet.getOrDefault(extendedCollisionBox, null); CustomBlockData extendedCollisionBlock = extendedCollisionBoxSet.getOrDefault(extendedCollisionBox, null);
if (extendedCollisionBlock == null) { if (extendedCollisionBlock == null) {
extendedCollisionBlock = createExtendedCollisionBlock(extendedCollisionBox, extendedCollisionIndex[0]++); extendedCollisionBlock = createExtendedCollisionBlock(extendedCollisionBox, extendedCollisionIndex[0]++);
extendedCollisionBoxes.put(extendedCollisionBlock, new HashSet<>(id)); extendedCollisionBoxes.computeIfAbsent(extendedCollisionBlock, k -> new HashSet<>()).add(id);
customBlocks.add(extendedCollisionBlock); customBlocks.add(extendedCollisionBlock);
extendedCollisionBoxSet.put(extendedCollisionBox, extendedCollisionBlock); extendedCollisionBoxSet.put(extendedCollisionBox, extendedCollisionBlock);
} else { } else {
@ -375,11 +361,14 @@ public class CustomBlockRegistryPopulator {
private static CustomBlockData createExtendedCollisionBlock(BoxComponent boxComponent, int extendedCollisionBlock) { private static CustomBlockData createExtendedCollisionBlock(BoxComponent boxComponent, int extendedCollisionBlock) {
CustomBlockData customBlockData = new CustomBlockDataBuilder() CustomBlockData customBlockData = new CustomBlockDataBuilder()
.name(Constants.GEYSER_NAMESPACE + ":extended_collision_" + extendedCollisionBlock) .name("extended_collision_" + extendedCollisionBlock)
.components( .components(
new CustomBlockComponentsBuilder() new CustomBlockComponentsBuilder()
.collisionBox(boxComponent) .collisionBox(boxComponent)
.selectionBox(new BoxComponent(0, 0, 0, 0, 0, 0)) .selectionBox(BoxComponent.EMPTY_BOX)
.materialInstance("*", new MaterialInstance("glass", "alpha_test", false, false))
.lightDampening(0)
.geometry("geometry.invisible")
.build()) .build())
.build(); .build();
return customBlockData; return customBlockData;