Skip to content

Commit

Permalink
Collisions without BlockMapping
Browse files Browse the repository at this point in the history
  • Loading branch information
Camotoy committed May 17, 2024
1 parent 1cd0aad commit 06dc0d1
Show file tree
Hide file tree
Showing 14 changed files with 100 additions and 126 deletions.
2 changes: 0 additions & 2 deletions core/src/main/java/org/geysermc/geyser/GeyserImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@
import org.geysermc.geyser.extension.GeyserExtensionManager;
import org.geysermc.geyser.impl.MinecraftVersionImpl;
import org.geysermc.geyser.level.WorldManager;
import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.network.netty.GeyserServer;
import org.geysermc.geyser.registry.BlockRegistries;
Expand Down Expand Up @@ -258,7 +257,6 @@ public void initialize() {

VersionCheckUtils.checkForOutdatedJava(logger);

Blocks.VAULT.javaId();
for (int i = 0; i < BlockRegistries.JAVA_BLOCKS.get().length; i++) {
String cleanIdentifier = BlockRegistries.JAVA_BLOCKS.get(i).getCleanJavaIdentifier();
String newIdentifier = BlockRegistries.BLOCK_STATES.get(i).block().javaIdentifier();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,6 @@ public final class BlockStateValues {
private static final Int2IntMap WATER_LEVEL = new Int2IntOpenHashMap();
private static final IntSet UPPER_DOORS = new IntOpenHashSet();

public static final int JAVA_AIR_ID = 0;

public static int JAVA_COBWEB_ID;
public static int JAVA_FURNACE_ID;
public static int JAVA_FURNACE_LIT_ID;
public static int JAVA_HONEY_BLOCK_ID;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.geysermc.geyser.api.block.custom.CustomBlockData;
import org.geysermc.geyser.api.block.custom.CustomBlockState;
import org.geysermc.geyser.api.block.custom.nonvanilla.JavaBlockState;
import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.registry.loader.CollisionRegistryLoader;
Expand Down Expand Up @@ -82,19 +83,13 @@ public class BlockRegistries {
/**
* A mapped registry containing which holds block IDs to its {@link BlockCollision}.
*/
public static final IntMappedRegistry<BlockCollision> COLLISIONS;
public static final ListRegistry<BlockCollision> COLLISIONS;

/**
* A mapped registry containing the Java identifiers to IDs.
*/
public static final MappedRegistry<String, Integer, Object2IntMap<String>> JAVA_IDENTIFIER_TO_ID = MappedRegistry.create(RegistryLoaders.empty(Object2IntOpenHashMap::new));

/**
* A registry which stores unique Java IDs to its clean identifier
* This is used in the statistics form.
*/
public static final ArrayRegistry<String> CLEAN_JAVA_IDENTIFIERS = ArrayRegistry.create(RegistryLoaders.uninitialized());

/**
* A registry containing all the waterlogged blockstates.
*/
Expand Down Expand Up @@ -141,12 +136,13 @@ public class BlockRegistries {
public static final SimpleMappedRegistry<String, CustomSkull> CUSTOM_SKULLS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new));

static {
Blocks.VAULT.javaId(); // FIXME
CustomSkullRegistryPopulator.populate();
BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.PRE_INIT);
CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.DEFINITION);
CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.NON_VANILLA_REGISTRATION);
BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_JAVA);
COLLISIONS = IntMappedRegistry.create(Pair.of("org.geysermc.geyser.translator.collision.CollisionRemapper", "mappings/collision.json"), CollisionRegistryLoader::new);
COLLISIONS = ListRegistry.create(Pair.of("org.geysermc.geyser.translator.collision.CollisionRemapper", "mappings/collisions.nbt"), CollisionRegistryLoader::new);
CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.VANILLA_REGISTRATION);
CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.CUSTOM_REGISTRATION);
BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_BEDROCK);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.geysermc.geyser.registry.loader.RegistryLoader;

import java.util.List;
import java.util.function.Supplier;

public class ListRegistry<M> extends Registry<List<M>> {
/**
Expand Down Expand Up @@ -98,6 +99,18 @@ public M register(int index, M value) {
* @return a new registry with the given RegistryLoader supplier
*/
public static <I, M> ListRegistry<M> create(RegistryLoader<I, List<M>> registryLoader) {
return new ListRegistry<M>(null, registryLoader);
return new ListRegistry<>(null, registryLoader);
}

/**
* Creates a new integer mapped registry with the given {@link RegistryLoader} and input.
*
* @param registryLoader the registry loader
* @param <I> the input
* @param <M> the type value
* @return a new registry with the given RegistryLoader supplier
*/
public static <I, M> ListRegistry<M> create(I input, Supplier<RegistryLoader<I, List<M>>> registryLoader) {
return new ListRegistry<>(input, registryLoader.get());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,19 @@

package org.geysermc.geyser.registry.loader;

import com.fasterxml.jackson.databind.node.ArrayNode;
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.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import lombok.AllArgsConstructor;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.nbt.NbtList;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.nbt.NbtUtils;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.type.BlockMapping;
import org.geysermc.geyser.translator.collision.BlockCollision;
import org.geysermc.geyser.translator.collision.CollisionRemapper;
import org.geysermc.geyser.translator.collision.OtherCollision;
Expand All @@ -51,41 +52,43 @@
/**
* Loads collision data from the given resource path.
*/
public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String, Int2ObjectMap<BlockCollision>> {
public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String, List<BlockCollision>> {

@Override
public Int2ObjectMap<BlockCollision> load(Pair<String, String> input) {
Int2ObjectMap<BlockCollision> collisions = new Int2ObjectOpenHashMap<>();

public List<BlockCollision> load(Pair<String, String> input) {
Map<Class<?>, CollisionInfo> annotationMap = new IdentityHashMap<>();
for (Class<?> clazz : FileUtils.getGeneratedClassesForAnnotation(CollisionRemapper.class.getName())) {
GeyserImpl.getInstance().getLogger().debug("Found annotated collision translator: " + clazz.getCanonicalName());

CollisionRemapper collisionRemapper = clazz.getAnnotation(CollisionRemapper.class);
annotationMap.put(clazz, new CollisionInfo(collisionRemapper, Pattern.compile(collisionRemapper.regex()), Pattern.compile(collisionRemapper.paramRegex())));
annotationMap.put(clazz, new CollisionInfo(collisionRemapper, Pattern.compile(collisionRemapper.regex())));
}

// Load collision mappings file
int[] indices;
List<BoundingBox[]> collisionList;
try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow(input.value())) {
ArrayNode collisionNode = (ArrayNode) GeyserImpl.JSON_MAPPER.readTree(stream);
collisionList = loadBoundingBoxes(collisionNode);
NbtMap collisionData = (NbtMap) NbtUtils.createGZIPReader(stream).readTag();
indices = collisionData.getIntArray("indices");
//SuppressWarnings unchecked
collisionList = loadBoundingBoxes(collisionData.getList("collisions", NbtType.LIST));
} catch (Exception e) {
throw new AssertionError("Unable to load collision data", e);
}

BlockMapping[] blockMappings = BlockRegistries.JAVA_BLOCKS.get();
List<BlockState> blockStates = BlockRegistries.BLOCK_STATES.get();
List<BlockCollision> collisions = new ObjectArrayList<>(blockStates.size());

// Map of unique collisions to its instance
Map<BlockCollision, BlockCollision> collisionInstances = new Object2ObjectOpenHashMap<>();
for (int i = 0; i < blockMappings.length; i++) {
BlockMapping blockMapping = blockMappings[i];
if (blockMapping == null) {
GeyserImpl.getInstance().getLogger().warning("Missing block mapping for Java block " + i);
for (int i = 0; i < blockStates.size(); i++) {
BlockState state = blockStates.get(i);
if (state == null) {
GeyserImpl.getInstance().getLogger().warning("Missing block state for Java block " + i);
continue;
}

BlockCollision newCollision = instantiateCollision(blockMapping, annotationMap, collisionList);
BlockCollision newCollision = instantiateCollision(state, annotationMap, indices[i], collisionList);

if (newCollision != null) {
// If there's an existing instance equal to this one, use that instead
Expand All @@ -97,33 +100,27 @@ public Int2ObjectMap<BlockCollision> load(Pair<String, String> input) {
}
}

collisions.put(i, newCollision);
collisions.add(newCollision);
}
return collisions;
}

private @Nullable BlockCollision instantiateCollision(BlockMapping mapping, Map<Class<?>, CollisionInfo> annotationMap, List<BoundingBox[]> collisionList) {
String[] blockIdParts = mapping.getJavaIdentifier().split("\\[");
String blockName = blockIdParts[0].replace("minecraft:", "");
String params = "";
if (blockIdParts.length == 2) {
params = "[" + blockIdParts[1];
}
int collisionIndex = mapping.getCollisionIndex();
private @Nullable BlockCollision instantiateCollision(BlockState state, Map<Class<?>, CollisionInfo> annotationMap, int collisionIndex, List<BoundingBox[]> collisionList) {
String blockName = state.block().javaIdentifier().substring("minecraft:".length());

for (Map.Entry<Class<?>, CollisionInfo> collisionRemappers : annotationMap.entrySet()) {
Class<?> type = collisionRemappers.getKey();
CollisionInfo collisionInfo = collisionRemappers.getValue();
CollisionRemapper annotation = collisionInfo.collisionRemapper;

if (collisionInfo.pattern.matcher(blockName).find() && collisionInfo.paramsPattern.matcher(params).find()) {
if (collisionInfo.pattern.matcher(blockName).find()) {
try {
if (annotation.passDefaultBoxes()) {
// Create an OtherCollision instance and get the bounding boxes
BoundingBox[] defaultBoxes = collisionList.get(collisionIndex);
return (BlockCollision) type.getDeclaredConstructor(String.class, BoundingBox[].class).newInstance(params, defaultBoxes);
return (BlockCollision) type.getDeclaredConstructor(BlockState.class, BoundingBox[].class).newInstance(state, defaultBoxes);
} else {
return (BlockCollision) type.getDeclaredConstructor(String.class).newInstance(params);
return (BlockCollision) type.getDeclaredConstructor(BlockState.class).newInstance(state);
}
} catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
throw new RuntimeException(e);
Expand All @@ -138,25 +135,25 @@ public Int2ObjectMap<BlockCollision> load(Pair<String, String> input) {

// Unless some of the low IDs are changed, which is unlikely, the second item should always be full collision
if (collisionIndex == 1) {
return new SolidCollision(params);
return new SolidCollision(state);
}
return new OtherCollision(collisionList.get(collisionIndex));
}

private List<BoundingBox[]> loadBoundingBoxes(ArrayNode collisionNode) {
private List<BoundingBox[]> loadBoundingBoxes(List<NbtList> collisionNode) {
List<BoundingBox[]> collisions = new ObjectArrayList<>();
for (int collisionIndex = 0; collisionIndex < collisionNode.size(); collisionIndex++) {
ArrayNode boundingBoxArray = (ArrayNode) collisionNode.get(collisionIndex);
@SuppressWarnings("unchecked") NbtList<NbtList<Double>> boundingBoxArray = (NbtList<NbtList<Double>>) collisionNode.get(collisionIndex);

BoundingBox[] boundingBoxes = new BoundingBox[boundingBoxArray.size()];
for (int i = 0; i < boundingBoxArray.size(); i++) {
ArrayNode boxProperties = (ArrayNode) boundingBoxArray.get(i);
boundingBoxes[i] = new BoundingBox(boxProperties.get(0).asDouble(),
boxProperties.get(1).asDouble(),
boxProperties.get(2).asDouble(),
boxProperties.get(3).asDouble(),
boxProperties.get(4).asDouble(),
boxProperties.get(5).asDouble());
NbtList<Double> boxProperties = boundingBoxArray.get(i);
boundingBoxes[i] = new BoundingBox(boxProperties.get(0),
boxProperties.get(1),
boxProperties.get(2),
boxProperties.get(3),
boxProperties.get(4),
boxProperties.get(5));
}

// Sorting by lowest Y first fixes some bugs
Expand All @@ -173,6 +170,5 @@ private List<BoundingBox[]> loadBoundingBoxes(ArrayNode collisionNode) {
public static class CollisionInfo {
private final CollisionRemapper collisionRemapper;
private final Pattern pattern;
private final Pattern paramsPattern;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,6 @@ private static void registerJavaBlocks() {
Deque<String> cleanIdentifiers = new ArrayDeque<>();

int javaRuntimeId = -1;
int cobwebBlockId = -1;
int furnaceRuntimeId = -1;
int furnaceLitRuntimeId = -1;
int honeyBlockRuntimeId = -1;
Expand Down Expand Up @@ -485,10 +484,7 @@ private static void registerJavaBlocks() {
// It's possible to only have this store differences in names, but the key set of all Java names is used in sending command suggestions
BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.register(cleanJavaIdentifier.intern(), bedrockIdentifier.intern());

if (javaId.contains("cobweb")) {
cobwebBlockId = uniqueJavaId;

} else if (javaId.startsWith("minecraft:furnace[facing=north")) {
if (javaId.startsWith("minecraft:furnace[facing=north")) {
if (javaId.contains("lit=true")) {
furnaceLitRuntimeId = javaRuntimeId;
} else {
Expand All @@ -507,11 +503,6 @@ private static void registerJavaBlocks() {
}
}

if (cobwebBlockId == -1) {
throw new AssertionError("Unable to find cobwebs in palette");
}
BlockStateValues.JAVA_COBWEB_ID = cobwebBlockId;

if (furnaceRuntimeId == -1) {
throw new AssertionError("Unable to find furnace in palette");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,6 @@
*/
String regex();

/**
* Regex of block state parameters to apply this collision to
* Defaults to matching any value
*/
String paramRegex() default ".*";

/**
* Signals if a new instance needs to created for every block state
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@
package org.geysermc.geyser.translator.collision;

import lombok.EqualsAndHashCode;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.level.physics.CollisionManager;

@EqualsAndHashCode(callSuper = true)
@CollisionRemapper(regex = "^dirt_path$", passDefaultBoxes = true)
public class DirtPathCollision extends BlockCollision {
public DirtPathCollision(String params, BoundingBox[] defaultBoxes) {
public DirtPathCollision(BlockState state, BoundingBox[] defaultBoxes) {
super(defaultBoxes);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
package org.geysermc.geyser.translator.collision;

import lombok.EqualsAndHashCode;
import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.session.GeyserSession;

Expand All @@ -40,20 +42,18 @@ public class DoorCollision extends BlockCollision {
*/
private int facing;

public DoorCollision(String params, BoundingBox[] defaultBoxes) {
public DoorCollision(BlockState state, BoundingBox[] defaultBoxes) {
super(defaultBoxes);
if (params.contains("facing=north")) {
facing = 1;
} else if (params.contains("facing=east")) {
facing = 2;
} else if (params.contains("facing=south")) {
facing = 3;
} else if (params.contains("facing=west")) {
facing = 4;
}
facing = switch (state.getValue(Properties.HORIZONTAL_FACING)) {
case NORTH -> 1;
case EAST -> 2;
case SOUTH -> 3;
case WEST -> 4;
default -> throw new IllegalStateException();
};

// If the door is open it changes direction
if (params.contains("open=true")) {
if (state.getValue(Properties.OPEN)) {
facing = facing % 2 + 1;
}
}
Expand Down

0 comments on commit 06dc0d1

Please sign in to comment.