Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-09-08 20:43:04 +02:00
Collision Registry (#2430)
* Fix trapdoor collision * Add EqualsAndHashCode to all Collision subclasses and shift code around EqualsAndHashCode are required on subclasses otherwise blocks will be assigned an incorrect collision instance. (Doors and trapdoors are mixed and ladder sometimes gets a DoorCollision instance). Added protected constructor to BlockCollision to make boundingBoxes final. Removed EmptyCollision because I don't think it is useful. Moved conversion from ArrayNode to BoundingBoxes[] from OtherCollision to CollisionRegistryLoader Removed regex from SnowCollision and use default bounding boxes. * Deduplicate BlockCollision instances * Create one set of bounding boxes for all BlockCollisions * Don't depend on the player's block position in DoorCollision * Fix dirt path position corrections Grass paths were renamed to dirt path in 1.17 Fix position correction for y=1, y=2, y=255, and y=256 * Increase pushAwayTolerance depending on distance from origin This should fix position corrections for blocks less than 1 unit in length/width at high coordinates. This includes ladders after x 4096 or z 4096 Not too sure about the math here though * Use ThreadLocal for position Hopefully resolves concurrency issues * Remove comment and add layer check to SnowCollision
Dieser Commit ist enthalten in:
Ursprung
6f93bbfe21
Commit
1d04a61a46
@ -97,11 +97,14 @@ public class FishingHookEntity extends ThrowableEntity {
|
|||||||
boolean collided = false;
|
boolean collided = false;
|
||||||
for (Vector3i blockPos : collidableBlocks) {
|
for (Vector3i blockPos : collidableBlocks) {
|
||||||
int blockID = session.getConnector().getWorldManager().getBlockAt(session, blockPos);
|
int blockID = session.getConnector().getWorldManager().getBlockAt(session, blockPos);
|
||||||
BlockCollision blockCollision = BlockUtils.getCollision(blockID, blockPos.getX(), blockPos.getY(), blockPos.getZ());
|
BlockCollision blockCollision = BlockUtils.getCollision(blockID, blockPos);
|
||||||
if (blockCollision != null && blockCollision.checkIntersection(boundingBox)) {
|
if (blockCollision != null) {
|
||||||
|
if (blockCollision.checkIntersection(boundingBox)) {
|
||||||
// TODO Push bounding box out of collision to improve movement
|
// TODO Push bounding box out of collision to improve movement
|
||||||
collided = true;
|
collided = true;
|
||||||
}
|
}
|
||||||
|
blockCollision.setPosition(null);
|
||||||
|
}
|
||||||
|
|
||||||
int waterLevel = BlockStateValues.getWaterLevel(blockID);
|
int waterLevel = BlockStateValues.getWaterLevel(blockID);
|
||||||
if (BlockRegistries.WATERLOGGED.get().contains(blockID)) {
|
if (BlockRegistries.WATERLOGGED.get().contains(blockID)) {
|
||||||
|
@ -220,23 +220,21 @@ public class CollisionManager {
|
|||||||
|
|
||||||
// Used when correction code needs to be run before the main correction
|
// Used when correction code needs to be run before the main correction
|
||||||
for (Vector3i blockPos : collidableBlocks) {
|
for (Vector3i blockPos : collidableBlocks) {
|
||||||
BlockCollision blockCollision = BlockUtils.getCollisionAt(
|
BlockCollision blockCollision = BlockUtils.getCollisionAt(session, blockPos);
|
||||||
session, blockPos.getX(), blockPos.getY(), blockPos.getZ()
|
|
||||||
);
|
|
||||||
if (blockCollision != null) {
|
if (blockCollision != null) {
|
||||||
blockCollision.beforeCorrectPosition(playerBoundingBox);
|
blockCollision.beforeCorrectPosition(playerBoundingBox);
|
||||||
|
blockCollision.setPosition(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main correction code
|
// Main correction code
|
||||||
for (Vector3i blockPos : collidableBlocks) {
|
for (Vector3i blockPos : collidableBlocks) {
|
||||||
BlockCollision blockCollision = BlockUtils.getCollisionAt(
|
BlockCollision blockCollision = BlockUtils.getCollisionAt(session, blockPos);
|
||||||
session, blockPos.getX(), blockPos.getY(), blockPos.getZ()
|
|
||||||
);
|
|
||||||
if (blockCollision != null) {
|
if (blockCollision != null) {
|
||||||
if (!blockCollision.correctPosition(session, playerBoundingBox)) {
|
if (!blockCollision.correctPosition(session, playerBoundingBox)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
blockCollision.setPosition(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,7 +249,7 @@ public class CollisionManager {
|
|||||||
*/
|
*/
|
||||||
public boolean isUnderSlab() {
|
public boolean isUnderSlab() {
|
||||||
Vector3i position = session.getPlayerEntity().getPosition().toInt();
|
Vector3i position = session.getPlayerEntity().getPosition().toInt();
|
||||||
BlockCollision collision = BlockUtils.getCollisionAt(session, position.getX(), position.getY(), position.getZ());
|
BlockCollision collision = BlockUtils.getCollisionAt(session, position);
|
||||||
if (collision != null) {
|
if (collision != null) {
|
||||||
// Determine, if the player's bounding box *were* at full height, if it would intersect with the block
|
// Determine, if the player's bounding box *were* at full height, if it would intersect with the block
|
||||||
// at the current location.
|
// at the current location.
|
||||||
@ -262,6 +260,7 @@ public class CollisionManager {
|
|||||||
playerBoundingBox.setSizeY(EntityType.PLAYER.getHeight());
|
playerBoundingBox.setSizeY(EntityType.PLAYER.getHeight());
|
||||||
playerBoundingBox.setMiddleY(standingY);
|
playerBoundingBox.setMiddleY(standingY);
|
||||||
boolean result = collision.checkIntersection(playerBoundingBox);
|
boolean result = collision.checkIntersection(playerBoundingBox);
|
||||||
|
collision.setPosition(null);
|
||||||
playerBoundingBox.setSizeY(originalHeight);
|
playerBoundingBox.setSizeY(originalHeight);
|
||||||
playerBoundingBox.setMiddleY(originalY);
|
playerBoundingBox.setMiddleY(originalY);
|
||||||
return result;
|
return result;
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
package org.geysermc.connector.network.translators.collision.translators;
|
package org.geysermc.connector.network.translators.collision.translators;
|
||||||
|
|
||||||
import com.nukkitx.math.vector.Vector3d;
|
import com.nukkitx.math.vector.Vector3d;
|
||||||
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
@ -36,11 +37,10 @@ import org.geysermc.connector.network.translators.collision.BoundingBox;
|
|||||||
public class BlockCollision {
|
public class BlockCollision {
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
protected BoundingBox[] boundingBoxes;
|
protected final BoundingBox[] boundingBoxes;
|
||||||
|
|
||||||
protected int x;
|
@EqualsAndHashCode.Exclude
|
||||||
protected int y;
|
protected final ThreadLocal<Vector3i> position;
|
||||||
protected int z;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is used for the step up logic.
|
* This is used for the step up logic.
|
||||||
@ -51,7 +51,6 @@ public class BlockCollision {
|
|||||||
* I didn't just set it for beds because other collision may also be slightly raised off the ground.
|
* I didn't just set it for beds because other collision may also be slightly raised off the ground.
|
||||||
* If this causes any problems, change this back to 0 and add an exception for beds.
|
* If this causes any problems, change this back to 0 and add an exception for beds.
|
||||||
*/
|
*/
|
||||||
@EqualsAndHashCode.Exclude
|
|
||||||
protected double pushUpTolerance = 1;
|
protected double pushUpTolerance = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,10 +58,13 @@ public class BlockCollision {
|
|||||||
*/
|
*/
|
||||||
protected double pushAwayTolerance = CollisionManager.COLLISION_TOLERANCE * 1.1;
|
protected double pushAwayTolerance = CollisionManager.COLLISION_TOLERANCE * 1.1;
|
||||||
|
|
||||||
public void setPosition(int x, int y, int z) {
|
protected BlockCollision(BoundingBox[] boxes) {
|
||||||
this.x = x;
|
this.boundingBoxes = boxes;
|
||||||
this.y = y;
|
this.position = new ThreadLocal<>();
|
||||||
this.z = z;
|
}
|
||||||
|
|
||||||
|
public void setPosition(Vector3i newPosition) {
|
||||||
|
this.position.set(newPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -78,6 +80,11 @@ public class BlockCollision {
|
|||||||
* This functionality is currently only used in 6 or 7 layer snow
|
* This functionality is currently only used in 6 or 7 layer snow
|
||||||
*/
|
*/
|
||||||
public boolean correctPosition(GeyserSession session, BoundingBox playerCollision) {
|
public boolean correctPosition(GeyserSession session, BoundingBox playerCollision) {
|
||||||
|
Vector3i blockPos = this.position.get();
|
||||||
|
int x = blockPos.getX();
|
||||||
|
int y = blockPos.getY();
|
||||||
|
int z = blockPos.getZ();
|
||||||
|
|
||||||
double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2);
|
double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2);
|
||||||
for (BoundingBox b : this.boundingBoxes) {
|
for (BoundingBox b : this.boundingBoxes) {
|
||||||
double boxMinY = (b.getMiddleY() + y) - (b.getSizeY() / 2);
|
double boxMinY = (b.getMiddleY() + y) - (b.getSizeY() / 2);
|
||||||
@ -103,27 +110,34 @@ public class BlockCollision {
|
|||||||
playerCollision.getMiddleY() - y,
|
playerCollision.getMiddleY() - y,
|
||||||
playerCollision.getMiddleZ() - z);
|
playerCollision.getMiddleZ() - z);
|
||||||
|
|
||||||
|
// The ULP should give an upper bound on the floating point error
|
||||||
|
double xULP = Math.ulp((float) Math.max(Math.abs(playerCollision.getMiddleX()) + playerCollision.getSizeX() / 2.0, Math.abs(x) + 1));
|
||||||
|
double zULP = Math.ulp((float) Math.max(Math.abs(playerCollision.getMiddleZ()) + playerCollision.getSizeZ() / 2.0, Math.abs(z) + 1));
|
||||||
|
|
||||||
|
double xPushAwayTolerance = Math.max(pushAwayTolerance, xULP);
|
||||||
|
double zPushAwayTolerance = Math.max(pushAwayTolerance, zULP);
|
||||||
|
|
||||||
double northFaceZPos = b.getMiddleZ() - (b.getSizeZ() / 2);
|
double northFaceZPos = b.getMiddleZ() - (b.getSizeZ() / 2);
|
||||||
double translateDistance = northFaceZPos - relativePlayerPosition.getZ() - (playerCollision.getSizeZ() / 2);
|
double translateDistance = northFaceZPos - relativePlayerPosition.getZ() - (playerCollision.getSizeZ() / 2);
|
||||||
if (Math.abs(translateDistance) < pushAwayTolerance) {
|
if (Math.abs(translateDistance) < zPushAwayTolerance) {
|
||||||
playerCollision.translate(0, 0, translateDistance);
|
playerCollision.translate(0, 0, translateDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
double southFaceZPos = b.getMiddleZ() + (b.getSizeZ() / 2);
|
double southFaceZPos = b.getMiddleZ() + (b.getSizeZ() / 2);
|
||||||
translateDistance = southFaceZPos - relativePlayerPosition.getZ() + (playerCollision.getSizeZ() / 2);
|
translateDistance = southFaceZPos - relativePlayerPosition.getZ() + (playerCollision.getSizeZ() / 2);
|
||||||
if (Math.abs(translateDistance) < pushAwayTolerance) {
|
if (Math.abs(translateDistance) < zPushAwayTolerance) {
|
||||||
playerCollision.translate(0, 0, translateDistance);
|
playerCollision.translate(0, 0, translateDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
double eastFaceXPos = b.getMiddleX() + (b.getSizeX() / 2);
|
double eastFaceXPos = b.getMiddleX() + (b.getSizeX() / 2);
|
||||||
translateDistance = eastFaceXPos - relativePlayerPosition.getX() + (playerCollision.getSizeX() / 2);
|
translateDistance = eastFaceXPos - relativePlayerPosition.getX() + (playerCollision.getSizeX() / 2);
|
||||||
if (Math.abs(translateDistance) < pushAwayTolerance) {
|
if (Math.abs(translateDistance) < xPushAwayTolerance) {
|
||||||
playerCollision.translate(translateDistance, 0, 0);
|
playerCollision.translate(translateDistance, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
double westFaceXPos = b.getMiddleX() - (b.getSizeX() / 2);
|
double westFaceXPos = b.getMiddleX() - (b.getSizeX() / 2);
|
||||||
translateDistance = westFaceXPos - relativePlayerPosition.getX() - (playerCollision.getSizeX() / 2);
|
translateDistance = westFaceXPos - relativePlayerPosition.getX() - (playerCollision.getSizeX() / 2);
|
||||||
if (Math.abs(translateDistance) < pushAwayTolerance) {
|
if (Math.abs(translateDistance) < xPushAwayTolerance) {
|
||||||
playerCollision.translate(translateDistance, 0, 0);
|
playerCollision.translate(translateDistance, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,6 +157,11 @@ public class BlockCollision {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean checkIntersection(BoundingBox playerCollision) {
|
public boolean checkIntersection(BoundingBox playerCollision) {
|
||||||
|
Vector3i blockPos = this.position.get();
|
||||||
|
int x = blockPos.getX();
|
||||||
|
int y = blockPos.getY();
|
||||||
|
int z = blockPos.getZ();
|
||||||
|
|
||||||
for (BoundingBox b : boundingBoxes) {
|
for (BoundingBox b : boundingBoxes) {
|
||||||
if (b.checkIntersection(x, y, z, playerCollision)) {
|
if (b.checkIntersection(x, y, z, playerCollision)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -25,24 +25,26 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.network.translators.collision.translators;
|
package org.geysermc.connector.network.translators.collision.translators;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
||||||
|
import org.geysermc.connector.network.translators.collision.CollisionManager;
|
||||||
import org.geysermc.connector.network.translators.collision.CollisionRemapper;
|
import org.geysermc.connector.network.translators.collision.CollisionRemapper;
|
||||||
|
|
||||||
@CollisionRemapper(regex = "^grass_path$", passDefaultBoxes = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class GrassPathCollision extends BlockCollision {
|
@CollisionRemapper(regex = "^dirt_path$", passDefaultBoxes = true)
|
||||||
public GrassPathCollision(String params, BoundingBox[] defaultBoxes) {
|
public class DirtPathCollision extends BlockCollision {
|
||||||
super();
|
public DirtPathCollision(String params, BoundingBox[] defaultBoxes) {
|
||||||
boundingBoxes = defaultBoxes;
|
super(defaultBoxes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Needs to run before the main correction code or it can move the player into blocks
|
// Needs to run before the main correction code or it can move the player into blocks
|
||||||
// This is counteracted by the main collision code pushing them out
|
// This is counteracted by the main collision code pushing them out
|
||||||
@Override
|
@Override
|
||||||
public void beforeCorrectPosition(BoundingBox playerCollision) {
|
public void beforeCorrectPosition(BoundingBox playerCollision) {
|
||||||
// In Bedrock, grass paths are small blocks so the player must be pushed down
|
// In Bedrock, dirt paths are solid blocks, so the player must be pushed down.
|
||||||
double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2);
|
double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2);
|
||||||
// If the player is in the buggy area, push them down
|
double blockMaxY = position.get().getY() + 1;
|
||||||
if (playerMinY == y + 1) {
|
if (Math.abs(blockMaxY - playerMinY) <= CollisionManager.COLLISION_TOLERANCE) {
|
||||||
playerCollision.translate(0, -0.0625, 0);
|
playerCollision.translate(0, -0.0625, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -25,10 +25,13 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.network.translators.collision.translators;
|
package org.geysermc.connector.network.translators.collision.translators;
|
||||||
|
|
||||||
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
||||||
import org.geysermc.connector.network.translators.collision.CollisionRemapper;
|
import org.geysermc.connector.network.translators.collision.CollisionRemapper;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@CollisionRemapper(regex = "_door$", usesParams = true, passDefaultBoxes = true)
|
@CollisionRemapper(regex = "_door$", usesParams = true, passDefaultBoxes = true)
|
||||||
public class DoorCollision extends BlockCollision {
|
public class DoorCollision extends BlockCollision {
|
||||||
/**
|
/**
|
||||||
@ -40,8 +43,7 @@ public class DoorCollision extends BlockCollision {
|
|||||||
private int facing;
|
private int facing;
|
||||||
|
|
||||||
public DoorCollision(String params, BoundingBox[] defaultBoxes) {
|
public DoorCollision(String params, BoundingBox[] defaultBoxes) {
|
||||||
super();
|
super(defaultBoxes);
|
||||||
boundingBoxes = defaultBoxes;
|
|
||||||
if (params.contains("facing=north")) {
|
if (params.contains("facing=north")) {
|
||||||
facing = 1;
|
facing = 1;
|
||||||
} else if (params.contains("facing=east")) {
|
} else if (params.contains("facing=east")) {
|
||||||
@ -68,18 +70,22 @@ public class DoorCollision extends BlockCollision {
|
|||||||
|
|
||||||
// Check for door bug (doors are 0.1875 blocks thick on Java but 0.1825 blocks thick on Bedrock)
|
// Check for door bug (doors are 0.1875 blocks thick on Java but 0.1825 blocks thick on Bedrock)
|
||||||
if (this.checkIntersection(playerCollision)) {
|
if (this.checkIntersection(playerCollision)) {
|
||||||
|
Vector3i blockPos = this.position.get();
|
||||||
|
int x = blockPos.getX();
|
||||||
|
int z = blockPos.getZ();
|
||||||
|
|
||||||
switch (facing) {
|
switch (facing) {
|
||||||
case 1: // North
|
case 1: // North
|
||||||
playerCollision.setMiddleZ(Math.floor(playerCollision.getMiddleZ()) + 0.5125);
|
playerCollision.setMiddleZ(z + 0.5125);
|
||||||
break;
|
break;
|
||||||
case 2: // East
|
case 2: // East
|
||||||
playerCollision.setMiddleX(Math.floor(playerCollision.getMiddleX()) + 0.5125);
|
playerCollision.setMiddleX(x + 0.5125);
|
||||||
break;
|
break;
|
||||||
case 3: // South
|
case 3: // South
|
||||||
playerCollision.setMiddleZ(Math.floor(playerCollision.getMiddleZ()) + 0.4875);
|
playerCollision.setMiddleZ(z + 0.4875);
|
||||||
break;
|
break;
|
||||||
case 4: // West
|
case 4: // West
|
||||||
playerCollision.setMiddleX(Math.floor(playerCollision.getMiddleX()) + 0.4875);
|
playerCollision.setMiddleX(x + 0.4875);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2019-2021 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.connector.network.translators.collision.translators;
|
|
||||||
|
|
||||||
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
|
||||||
|
|
||||||
public class EmptyCollision extends BlockCollision {
|
|
||||||
public EmptyCollision(String params) {
|
|
||||||
super();
|
|
||||||
boundingBoxes = new BoundingBox[0];
|
|
||||||
}
|
|
||||||
}
|
|
@ -25,29 +25,13 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.network.translators.collision.translators;
|
package org.geysermc.connector.network.translators.collision.translators;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
||||||
|
|
||||||
import java.util.Arrays;
|
@EqualsAndHashCode(callSuper = true)
|
||||||
import java.util.Comparator;
|
|
||||||
|
|
||||||
public class OtherCollision extends BlockCollision {
|
public class OtherCollision extends BlockCollision {
|
||||||
|
|
||||||
public OtherCollision(ArrayNode collisionList) {
|
public OtherCollision(BoundingBox[] boundingBoxes) {
|
||||||
super();
|
super(boundingBoxes);
|
||||||
boundingBoxes = new BoundingBox[collisionList.size()];
|
|
||||||
|
|
||||||
for (int i = 0; i < collisionList.size(); i++) {
|
|
||||||
ArrayNode collisionBoxArray = (ArrayNode) collisionList.get(i);
|
|
||||||
boundingBoxes[i] = new BoundingBox(collisionBoxArray.get(0).asDouble(),
|
|
||||||
collisionBoxArray.get(1).asDouble(),
|
|
||||||
collisionBoxArray.get(2).asDouble(),
|
|
||||||
collisionBoxArray.get(3).asDouble(),
|
|
||||||
collisionBoxArray.get(4).asDouble(),
|
|
||||||
collisionBoxArray.get(5).asDouble());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sorting by lowest Y first fixes some bugs
|
|
||||||
Arrays.sort(boundingBoxes, Comparator.comparingDouble(BoundingBox::getMiddleY));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.network.translators.collision.translators;
|
package org.geysermc.connector.network.translators.collision.translators;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
||||||
import org.geysermc.connector.network.translators.collision.CollisionRemapper;
|
import org.geysermc.connector.network.translators.collision.CollisionRemapper;
|
||||||
@ -32,11 +33,11 @@ import org.geysermc.connector.network.translators.collision.CollisionRemapper;
|
|||||||
/**
|
/**
|
||||||
* In order for scaffolding to work on Bedrock, entity flags need to be sent to the player
|
* In order for scaffolding to work on Bedrock, entity flags need to be sent to the player
|
||||||
*/
|
*/
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@CollisionRemapper(regex = "^scaffolding$", usesParams = true, passDefaultBoxes = true)
|
@CollisionRemapper(regex = "^scaffolding$", usesParams = true, passDefaultBoxes = true)
|
||||||
public class ScaffoldingCollision extends BlockCollision {
|
public class ScaffoldingCollision extends BlockCollision {
|
||||||
public ScaffoldingCollision(String params, BoundingBox[] defaultBoxes) {
|
public ScaffoldingCollision(String params, BoundingBox[] defaultBoxes) {
|
||||||
super();
|
super(defaultBoxes);
|
||||||
boundingBoxes = defaultBoxes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -25,37 +25,20 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.network.translators.collision.translators;
|
package org.geysermc.connector.network.translators.collision.translators;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
||||||
import org.geysermc.connector.network.translators.collision.CollisionRemapper;
|
import org.geysermc.connector.network.translators.collision.CollisionRemapper;
|
||||||
|
|
||||||
import java.util.regex.Pattern;
|
@EqualsAndHashCode(callSuper = true)
|
||||||
import java.util.regex.Matcher;
|
@CollisionRemapper(regex = "^snow$", passDefaultBoxes = true, usesParams = true)
|
||||||
|
|
||||||
@CollisionRemapper(regex = "^snow$", usesParams = true)
|
|
||||||
public class SnowCollision extends BlockCollision {
|
public class SnowCollision extends BlockCollision {
|
||||||
private final int layers;
|
private final int layers;
|
||||||
|
|
||||||
public SnowCollision(String params) {
|
public SnowCollision(String params, BoundingBox[] defaultBoxes) {
|
||||||
super();
|
super(defaultBoxes);
|
||||||
Pattern layersPattern = Pattern.compile("layers=([0-8])");
|
int layerCharIndex = params.indexOf("=") + 1;
|
||||||
Matcher matcher = layersPattern.matcher(params);
|
layers = Integer.parseInt(params.substring(layerCharIndex, layerCharIndex + 1));
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
matcher.find();
|
|
||||||
|
|
||||||
// Hitbox is 1 layer less (you sink in 1 layer)
|
|
||||||
layers = Integer.parseInt(matcher.group(1));
|
|
||||||
|
|
||||||
if (layers > 1) {
|
|
||||||
boundingBoxes = new BoundingBox[] {
|
|
||||||
// Take away 1 because you can go 1 layer into snow layers
|
|
||||||
new BoundingBox(0.5, ((layers - 1) * 0.125) / 2, 0.5,
|
|
||||||
1, (layers - 1) * 0.125, 1)
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
// Single layers have no collision
|
|
||||||
boundingBoxes = new BoundingBox[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
pushUpTolerance = 0.125;
|
pushUpTolerance = 0.125;
|
||||||
}
|
}
|
||||||
@ -69,7 +52,7 @@ public class SnowCollision extends BlockCollision {
|
|||||||
// pushed down
|
// pushed down
|
||||||
if (layers == 4 || layers == 8) {
|
if (layers == 4 || layers == 8) {
|
||||||
double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2);
|
double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2);
|
||||||
double boxMaxY = (boundingBoxes[0].getMiddleY() + y) + (boundingBoxes[0].getSizeY() / 2);
|
double boxMaxY = (boundingBoxes[0].getMiddleY() + position.get().getY()) + (boundingBoxes[0].getSizeY() / 2);
|
||||||
// If the player is in the buggy area, push them down
|
// If the player is in the buggy area, push them down
|
||||||
if (playerMinY > boxMaxY &&
|
if (playerMinY > boxMaxY &&
|
||||||
playerMinY <= (boxMaxY + 0.125)) {
|
playerMinY <= (boxMaxY + 0.125)) {
|
||||||
@ -80,6 +63,10 @@ public class SnowCollision extends BlockCollision {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean correctPosition(GeyserSession session, BoundingBox playerCollision) {
|
public boolean correctPosition(GeyserSession session, BoundingBox playerCollision) {
|
||||||
|
if (layers == 1) {
|
||||||
|
// 1 layer of snow does not have collision
|
||||||
|
return true;
|
||||||
|
}
|
||||||
// Hack to prevent false positives
|
// Hack to prevent false positives
|
||||||
playerCollision.setSizeX(playerCollision.getSizeX() - 0.0001);
|
playerCollision.setSizeX(playerCollision.getSizeX() - 0.0001);
|
||||||
playerCollision.setSizeY(playerCollision.getSizeY() - 0.0001);
|
playerCollision.setSizeY(playerCollision.getSizeY() - 0.0001);
|
||||||
@ -87,7 +74,7 @@ public class SnowCollision extends BlockCollision {
|
|||||||
|
|
||||||
if (this.checkIntersection(playerCollision)) {
|
if (this.checkIntersection(playerCollision)) {
|
||||||
double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2);
|
double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2);
|
||||||
double boxMaxY = (boundingBoxes[0].getMiddleY() + y) + (boundingBoxes[0].getSizeY() / 2);
|
double boxMaxY = (boundingBoxes[0].getMiddleY() + position.get().getY()) + (boundingBoxes[0].getSizeY() / 2);
|
||||||
// If the player actually can't step onto it (they can step onto it from other snow layers)
|
// If the player actually can't step onto it (they can step onto it from other snow layers)
|
||||||
if ((boxMaxY - playerMinY) > 0.5) {
|
if ((boxMaxY - playerMinY) > 0.5) {
|
||||||
// Cancel the movement
|
// Cancel the movement
|
||||||
|
@ -25,15 +25,16 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.network.translators.collision.translators;
|
package org.geysermc.connector.network.translators.collision.translators;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
||||||
import org.geysermc.connector.network.translators.collision.CollisionRemapper;
|
import org.geysermc.connector.network.translators.collision.CollisionRemapper;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@CollisionRemapper(regex = "shulker_box$") // These have no collision in the mappings as it depends on the NBT data
|
@CollisionRemapper(regex = "shulker_box$") // These have no collision in the mappings as it depends on the NBT data
|
||||||
public class SolidCollision extends BlockCollision {
|
public class SolidCollision extends BlockCollision {
|
||||||
public SolidCollision(String params) {
|
public SolidCollision(String params) {
|
||||||
super();
|
super(new BoundingBox[] {
|
||||||
boundingBoxes = new BoundingBox[]{
|
|
||||||
new BoundingBox(0.5, 0.5, 0.5, 1, 1, 1)
|
new BoundingBox(0.5, 0.5, 0.5, 1, 1, 1)
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -25,8 +25,10 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.network.translators.collision.translators;
|
package org.geysermc.connector.network.translators.collision.translators;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import org.geysermc.connector.network.translators.collision.CollisionRemapper;
|
import org.geysermc.connector.network.translators.collision.CollisionRemapper;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@CollisionRemapper(regex = "^spawner$")
|
@CollisionRemapper(regex = "^spawner$")
|
||||||
public class SpawnerCollision extends SolidCollision {
|
public class SpawnerCollision extends SolidCollision {
|
||||||
public SpawnerCollision(String params) {
|
public SpawnerCollision(String params) {
|
||||||
|
@ -25,10 +25,14 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.network.translators.collision.translators;
|
package org.geysermc.connector.network.translators.collision.translators;
|
||||||
|
|
||||||
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
||||||
|
import org.geysermc.connector.network.translators.collision.CollisionManager;
|
||||||
import org.geysermc.connector.network.translators.collision.CollisionRemapper;
|
import org.geysermc.connector.network.translators.collision.CollisionRemapper;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@CollisionRemapper(regex = "_trapdoor$", usesParams = true, passDefaultBoxes = true)
|
@CollisionRemapper(regex = "_trapdoor$", usesParams = true, passDefaultBoxes = true)
|
||||||
public class TrapdoorCollision extends BlockCollision {
|
public class TrapdoorCollision extends BlockCollision {
|
||||||
/**
|
/**
|
||||||
@ -42,8 +46,7 @@ public class TrapdoorCollision extends BlockCollision {
|
|||||||
private int facing;
|
private int facing;
|
||||||
|
|
||||||
public TrapdoorCollision(String params, BoundingBox[] defaultBoxes) {
|
public TrapdoorCollision(String params, BoundingBox[] defaultBoxes) {
|
||||||
super();
|
super(defaultBoxes);
|
||||||
boundingBoxes = defaultBoxes;
|
|
||||||
if (params.contains("open=true")) {
|
if (params.contains("open=true")) {
|
||||||
if (params.contains("facing=north")) {
|
if (params.contains("facing=north")) {
|
||||||
facing = 1;
|
facing = 1;
|
||||||
@ -68,38 +71,35 @@ public class TrapdoorCollision extends BlockCollision {
|
|||||||
@Override
|
@Override
|
||||||
public boolean correctPosition(GeyserSession session, BoundingBox playerCollision) {
|
public boolean correctPosition(GeyserSession session, BoundingBox playerCollision) {
|
||||||
boolean result = super.correctPosition(session, playerCollision);
|
boolean result = super.correctPosition(session, playerCollision);
|
||||||
// Hack to prevent false positives
|
|
||||||
playerCollision.setSizeX(playerCollision.getSizeX() - 0.0001);
|
|
||||||
playerCollision.setSizeY(playerCollision.getSizeY() - 0.0001);
|
|
||||||
playerCollision.setSizeZ(playerCollision.getSizeZ() - 0.0001);
|
|
||||||
|
|
||||||
// Check for door bug (doors are 0.1875 blocks thick on Java but 0.1825 blocks thick on Bedrock)
|
// Check for door bug (doors are 0.1875 blocks thick on Java but 0.1825 blocks thick on Bedrock)
|
||||||
if (this.checkIntersection(playerCollision)) {
|
if (this.checkIntersection(playerCollision)) {
|
||||||
|
Vector3i blockPos = this.position.get();
|
||||||
|
int x = blockPos.getX();
|
||||||
|
int y = blockPos.getY();
|
||||||
|
int z = blockPos.getZ();
|
||||||
|
|
||||||
switch (facing) {
|
switch (facing) {
|
||||||
case 1: // North
|
case 1: // North
|
||||||
playerCollision.setMiddleZ(Math.floor(playerCollision.getMiddleZ()) + 0.5125);
|
playerCollision.setMiddleZ(z + 0.5125);
|
||||||
|
break;
|
||||||
|
case 2: // East
|
||||||
|
playerCollision.setMiddleX(x + 0.5125);
|
||||||
break;
|
break;
|
||||||
case 3: // South
|
case 3: // South
|
||||||
playerCollision.setMiddleZ(Math.floor(playerCollision.getMiddleZ()) + 0.4875);
|
playerCollision.setMiddleZ(z + 0.4875);
|
||||||
break;
|
break;
|
||||||
case 4: // West
|
case 4: // West
|
||||||
playerCollision.setMiddleX(Math.floor(playerCollision.getMiddleX()) + 0.4875);
|
playerCollision.setMiddleX(x + 0.4875);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
// Up-facing trapdoors are handled by the step-up check
|
||||||
break;
|
break;
|
||||||
case 6: // Down
|
case 6: // Down
|
||||||
playerCollision.setMiddleY(Math.floor(
|
// (top y of trap door) - (trap door thickness) = top y of player
|
||||||
playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2)
|
playerCollision.setMiddleY(y + 1 - (3.0 / 16.0) - playerCollision.getSizeY() / 2.0 - CollisionManager.COLLISION_TOLERANCE);
|
||||||
) + 0.0125 + (playerCollision.getSizeY() / 2));
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
case 5:
|
|
||||||
// Up-facing and east-facing trapdoors work fine
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
playerCollision.setSizeX(playerCollision.getSizeX() + 0.0001);
|
|
||||||
playerCollision.setSizeY(playerCollision.getSizeY() + 0.0001);
|
|
||||||
playerCollision.setSizeZ(playerCollision.getSizeZ() + 0.0001);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.registry;
|
package org.geysermc.connector.registry;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||||
@ -54,7 +55,7 @@ public class BlockRegistries {
|
|||||||
* A mapped registry which stores Java IDs to {@link BlockMapping}, containing miscellaneous information about
|
* A mapped registry which stores Java IDs to {@link BlockMapping}, containing miscellaneous information about
|
||||||
* blocks and their behavior in many cases.
|
* blocks and their behavior in many cases.
|
||||||
*/
|
*/
|
||||||
public static final SimpleMappedRegistry<Integer, BlockMapping> JAVA_BLOCKS = SimpleMappedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new));
|
public static final MappedRegistry<Integer, BlockMapping, Int2ObjectMap<BlockMapping>> JAVA_BLOCKS = MappedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A (bi)mapped registry containing the Java IDs to identifiers.
|
* A (bi)mapped registry containing the Java IDs to identifiers.
|
||||||
|
@ -29,23 +29,22 @@ import com.fasterxml.jackson.databind.node.ArrayNode;
|
|||||||
import it.unimi.dsi.fastutil.Pair;
|
import it.unimi.dsi.fastutil.Pair;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
import org.geysermc.connector.network.translators.collision.BoundingBox;
|
||||||
import org.geysermc.connector.network.translators.collision.CollisionRemapper;
|
import org.geysermc.connector.network.translators.collision.CollisionRemapper;
|
||||||
import org.geysermc.connector.network.translators.collision.translators.BlockCollision;
|
import org.geysermc.connector.network.translators.collision.translators.BlockCollision;
|
||||||
import org.geysermc.connector.network.translators.collision.translators.EmptyCollision;
|
|
||||||
import org.geysermc.connector.network.translators.collision.translators.OtherCollision;
|
import org.geysermc.connector.network.translators.collision.translators.OtherCollision;
|
||||||
import org.geysermc.connector.network.translators.collision.translators.SolidCollision;
|
import org.geysermc.connector.network.translators.collision.translators.SolidCollision;
|
||||||
import org.geysermc.connector.registry.BlockRegistries;
|
import org.geysermc.connector.registry.BlockRegistries;
|
||||||
|
import org.geysermc.connector.registry.type.BlockMapping;
|
||||||
import org.geysermc.connector.utils.FileUtils;
|
import org.geysermc.connector.utils.FileUtils;
|
||||||
import org.geysermc.connector.utils.Object2IntBiMap;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.*;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,35 +67,44 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String,
|
|||||||
// Load collision mappings file
|
// Load collision mappings file
|
||||||
InputStream stream = FileUtils.getResource(input.value());
|
InputStream stream = FileUtils.getResource(input.value());
|
||||||
|
|
||||||
ArrayNode collisionList;
|
List<BoundingBox[]> collisionList;
|
||||||
try {
|
try {
|
||||||
collisionList = (ArrayNode) GeyserConnector.JSON_MAPPER.readTree(stream);
|
ArrayNode collisionNode = (ArrayNode) GeyserConnector.JSON_MAPPER.readTree(stream);
|
||||||
|
collisionList = loadBoundingBoxes(collisionNode);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new AssertionError("Unable to load collision data", e);
|
throw new AssertionError("Unable to load collision data", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object2IntBiMap<String> javaIdBlockMap = BlockRegistries.JAVA_IDENTIFIERS.get();
|
Int2ObjectMap<BlockMapping> blockMap = BlockRegistries.JAVA_BLOCKS.get();
|
||||||
|
|
||||||
|
// Map of unique collisions to its instance
|
||||||
|
Map<BlockCollision, BlockCollision> collisionInstances = new Object2ObjectOpenHashMap<>();
|
||||||
|
for (Int2ObjectMap.Entry<BlockMapping> entry : blockMap.int2ObjectEntrySet()) {
|
||||||
|
BlockCollision newCollision = instantiateCollision(entry.getValue(), annotationMap, collisionList);
|
||||||
|
|
||||||
// Map of classes that don't change based on parameters that have already been created
|
|
||||||
Map<Class<?>, BlockCollision> instantiatedCollision = new IdentityHashMap<>();
|
|
||||||
for (Object2IntMap.Entry<String> entry : javaIdBlockMap.object2IntEntrySet()) {
|
|
||||||
BlockCollision newCollision = instantiateCollision(entry.getKey(), entry.getIntValue(), annotationMap, instantiatedCollision, collisionList);
|
|
||||||
if (newCollision != null) {
|
if (newCollision != null) {
|
||||||
instantiatedCollision.put(newCollision.getClass(), newCollision);
|
// If there's an existing instance equal to this one, use that instead
|
||||||
|
BlockCollision existingInstance = collisionInstances.get(newCollision);
|
||||||
|
if (existingInstance != null) {
|
||||||
|
newCollision = existingInstance;
|
||||||
|
} else {
|
||||||
|
collisionInstances.put(newCollision, newCollision);
|
||||||
}
|
}
|
||||||
collisions.put(entry.getIntValue(), newCollision);
|
}
|
||||||
|
|
||||||
|
collisions.put(entry.getIntKey(), newCollision);
|
||||||
}
|
}
|
||||||
return collisions;
|
return collisions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private BlockCollision instantiateCollision(String blockID, int numericBlockID, Map<Class<?>, CollisionInfo> annotationMap, Map<Class<?>, BlockCollision> instantiatedCollision, ArrayNode collisionList) {
|
private BlockCollision instantiateCollision(BlockMapping mapping, Map<Class<?>, CollisionInfo> annotationMap, List<BoundingBox[]> collisionList) {
|
||||||
String[] blockIdParts = blockID.split("\\[");
|
String[] blockIdParts = mapping.getJavaIdentifier().split("\\[");
|
||||||
String blockName = blockIdParts[0].replace("minecraft:", "");
|
String blockName = blockIdParts[0].replace("minecraft:", "");
|
||||||
String params = "";
|
String params = "";
|
||||||
if (blockID.contains("[")) {
|
if (blockIdParts.length == 2) {
|
||||||
params = "[" + blockIdParts[1];
|
params = "[" + blockIdParts[1];
|
||||||
}
|
}
|
||||||
int collisionIndex = BlockRegistries.JAVA_BLOCKS.get(numericBlockID).getCollisionIndex();
|
int collisionIndex = mapping.getCollisionIndex();
|
||||||
|
|
||||||
for (Map.Entry<Class<?>, CollisionInfo> collisionRemappers : annotationMap.entrySet()) {
|
for (Map.Entry<Class<?>, CollisionInfo> collisionRemappers : annotationMap.entrySet()) {
|
||||||
Class<?> type = collisionRemappers.getKey();
|
Class<?> type = collisionRemappers.getKey();
|
||||||
@ -105,67 +113,52 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader<String,
|
|||||||
|
|
||||||
if (collisionInfo.pattern.matcher(blockName).find() && collisionInfo.paramsPattern.matcher(params).find()) {
|
if (collisionInfo.pattern.matcher(blockName).find() && collisionInfo.paramsPattern.matcher(params).find()) {
|
||||||
try {
|
try {
|
||||||
if (!annotation.usesParams() && instantiatedCollision.containsKey(type)) {
|
|
||||||
return instantiatedCollision.get(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return null when empty to save unnecessary checks
|
|
||||||
if (type == EmptyCollision.class) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockCollision collision;
|
|
||||||
if (annotation.passDefaultBoxes()) {
|
if (annotation.passDefaultBoxes()) {
|
||||||
// Create an OtherCollision instance and get the bounding boxes
|
// Create an OtherCollision instance and get the bounding boxes
|
||||||
BoundingBox[] defaultBoxes = new OtherCollision((ArrayNode) collisionList.get(collisionIndex)).getBoundingBoxes();
|
BoundingBox[] defaultBoxes = collisionList.get(collisionIndex);
|
||||||
collision = (BlockCollision) type.getDeclaredConstructor(String.class, BoundingBox[].class).newInstance(params, defaultBoxes);
|
return (BlockCollision) type.getDeclaredConstructor(String.class, BoundingBox[].class).newInstance(params, defaultBoxes);
|
||||||
} else {
|
} else {
|
||||||
collision = (BlockCollision) type.getDeclaredConstructor(String.class).newInstance(params);
|
return (BlockCollision) type.getDeclaredConstructor(String.class).newInstance(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there's an existing instance equal to this one, use that instead
|
|
||||||
for (Map.Entry<Class<?>, BlockCollision> entry : instantiatedCollision.entrySet()) {
|
|
||||||
if (entry.getValue().equals(collision)) {
|
|
||||||
collision = entry.getValue();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return collision;
|
|
||||||
} catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
|
} catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
|
||||||
e.printStackTrace();
|
throw new RuntimeException(e);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unless some of the low IDs are changed, which is unlikely, the first item should always be empty collision
|
// Unless some of the low IDs are changed, which is unlikely, the first item should always be empty collision
|
||||||
if (collisionIndex == 0) {
|
if (collisionIndex == 0) {
|
||||||
if (instantiatedCollision.containsKey(EmptyCollision.class)) {
|
return null;
|
||||||
return instantiatedCollision.get(EmptyCollision.class);
|
|
||||||
} else {
|
|
||||||
return new EmptyCollision(params);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unless some of the low IDs are changed, which is unlikely, the second item should always be full collision
|
// Unless some of the low IDs are changed, which is unlikely, the second item should always be full collision
|
||||||
if (collisionIndex == 1) {
|
if (collisionIndex == 1) {
|
||||||
if (instantiatedCollision.containsKey(SolidCollision.class)) {
|
|
||||||
return instantiatedCollision.get(SolidCollision.class);
|
|
||||||
} else {
|
|
||||||
return new SolidCollision(params);
|
return new SolidCollision(params);
|
||||||
}
|
}
|
||||||
|
return new OtherCollision(collisionList.get(collisionIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockCollision collision = new OtherCollision((ArrayNode) collisionList.get(collisionIndex));
|
private List<BoundingBox[]> loadBoundingBoxes(ArrayNode collisionNode) {
|
||||||
// If there's an existing instance equal to this one, use that instead
|
List<BoundingBox[]> collisions = new ObjectArrayList<>();
|
||||||
for (Map.Entry<Class<?>, BlockCollision> entry : instantiatedCollision.entrySet()) {
|
for (int collisionIndex = 0; collisionIndex < collisionNode.size(); collisionIndex++) {
|
||||||
if (entry.getValue().equals(collision)) {
|
ArrayNode boundingBoxArray = (ArrayNode) collisionNode.get(collisionIndex);
|
||||||
collision = entry.getValue();
|
|
||||||
break;
|
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
return collision;
|
// Sorting by lowest Y first fixes some bugs
|
||||||
|
Arrays.sort(boundingBoxes, Comparator.comparingDouble(BoundingBox::getMiddleY));
|
||||||
|
collisions.add(boundingBoxes);
|
||||||
|
}
|
||||||
|
return collisions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -244,16 +244,15 @@ public class BlockUtils {
|
|||||||
return fullJavaIdentifier.substring(0, stateIndex);
|
return fullJavaIdentifier.substring(0, stateIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: these reuse classes, so don't try to store more than once instance or coordinates will get overwritten
|
public static BlockCollision getCollision(int blockId, Vector3i blockPos) {
|
||||||
public static BlockCollision getCollision(int blockId, int x, int y, int z) {
|
|
||||||
BlockCollision collision = Registries.COLLISIONS.get(blockId);
|
BlockCollision collision = Registries.COLLISIONS.get(blockId);
|
||||||
if (collision != null) {
|
if (collision != null) {
|
||||||
collision.setPosition(x, y, z);
|
collision.setPosition(blockPos);
|
||||||
}
|
}
|
||||||
return collision;
|
return collision;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BlockCollision getCollisionAt(GeyserSession session, int x, int y, int z) {
|
public static BlockCollision getCollisionAt(GeyserSession session, Vector3i blockPos) {
|
||||||
return getCollision(session.getConnector().getWorldManager().getBlockAt(session, x, y, z), x, y, z);
|
return getCollision(session.getConnector().getWorldManager().getBlockAt(session, blockPos), blockPos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren