This commit is contained in:
Minecon724 2024-07-09 13:55:05 +02:00
parent b4a72d274b
commit b31180d085
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
11 changed files with 426 additions and 40 deletions

View file

@ -12,6 +12,7 @@ import net.minestom.server.instance.Instance;
import net.minestom.server.instance.Weather; import net.minestom.server.instance.Weather;
import net.pivipi.ball.Ball; import net.pivipi.ball.Ball;
import net.pivipi.ball.BallKicker; import net.pivipi.ball.BallKicker;
import net.pivipi.physics.aabb.AABBPlayer;
import net.pivipi.world.Stadium; import net.pivipi.world.Stadium;
public class LoginHandler { public class LoginHandler {
@ -36,7 +37,7 @@ public class LoginHandler {
event.setHardcore(true); event.setHardcore(true);
player.setRespawnPoint(new Pos(0, 67, 0)); player.setRespawnPoint(new Pos(0, 67, 0));
stadium.players.add(player); stadium.players.add((AABBPlayer)player);
} }
private void onQuit(PlayerDisconnectEvent event) { private void onQuit(PlayerDisconnectEvent event) {

View file

@ -1,16 +1,25 @@
package net.pivipi; package net.pivipi;
import java.util.UUID;
import org.jetbrains.annotations.NotNull;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player;
import net.minestom.server.event.GlobalEventHandler; import net.minestom.server.event.GlobalEventHandler;
import net.minestom.server.instance.InstanceContainer; import net.minestom.server.instance.InstanceContainer;
import net.minestom.server.instance.InstanceManager; import net.minestom.server.instance.InstanceManager;
import net.minestom.server.instance.LightingChunk; import net.minestom.server.instance.LightingChunk;
import net.minestom.server.instance.Weather; import net.minestom.server.instance.Weather;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.PlayerProvider;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.registry.DynamicRegistry.Key; import net.minestom.server.registry.DynamicRegistry.Key;
import net.minestom.server.timer.SchedulerManager; import net.minestom.server.timer.SchedulerManager;
import net.minestom.server.timer.TaskSchedule; import net.minestom.server.timer.TaskSchedule;
import net.minestom.server.world.DimensionType; import net.minestom.server.world.DimensionType;
import net.pivipi.physics.aabb.AABBPlayer;
import net.pivipi.world.FancyDimension; import net.pivipi.world.FancyDimension;
import net.pivipi.world.SoccerGenerator; import net.pivipi.world.SoccerGenerator;
import net.pivipi.world.WorldConstraints; import net.pivipi.world.WorldConstraints;
@ -20,7 +29,7 @@ public class Main {
System.setProperty("minestom.tps", "100"); System.setProperty("minestom.tps", "100");
MinecraftServer minecraftServer = MinecraftServer.init(); MinecraftServer minecraftServer = MinecraftServer.init();
ConnectionManager connectionManager = MinecraftServer.getConnectionManager();
InstanceManager instanceManager = MinecraftServer.getInstanceManager(); InstanceManager instanceManager = MinecraftServer.getInstanceManager();
GlobalEventHandler globalEventHandler = MinecraftServer.getGlobalEventHandler(); GlobalEventHandler globalEventHandler = MinecraftServer.getGlobalEventHandler();
@ -37,6 +46,14 @@ public class Main {
WorldConstraints worldConstraints = new WorldConstraints(); WorldConstraints worldConstraints = new WorldConstraints();
worldConstraints.setup(globalEventHandler); worldConstraints.setup(globalEventHandler);
connectionManager.setPlayerProvider(new PlayerProvider() {
@Override
public @NotNull Player createPlayer(@NotNull UUID uuid, @NotNull String username,
@NotNull PlayerConnection connection) {
return new AABBPlayer(uuid, username, connection);
}
});
/* done */ /* done */
MinecraftServer.setCompressionThreshold(0); MinecraftServer.setCompressionThreshold(0);

View file

@ -10,9 +10,10 @@ import net.minestom.server.event.player.PlayerEntityInteractEvent;
import net.minestom.server.instance.Instance; import net.minestom.server.instance.Instance;
import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.Block;
import net.pivipi.physics.Physics; import net.pivipi.physics.Physics;
import net.pivipi.physics.aabb.AABBEntity;
import net.pivipi.world.Stadium; import net.pivipi.world.Stadium;
public class Ball extends Entity { public class Ball extends AABBEntity {
private long lastTick; private long lastTick;
private Player holder; private Player holder;

View file

@ -19,7 +19,7 @@ import net.minestom.server.instance.block.Block;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.server.play.BlockActionPacket; import net.minestom.server.network.packet.server.play.BlockActionPacket;
import net.minestom.server.particle.Particle.Item; import net.minestom.server.particle.Particle.Item;
import net.pivipi.physics.Collision; import net.pivipi.physics.CollisionDetector;
import net.pivipi.physics.CollisionData; import net.pivipi.physics.CollisionData;
import net.pivipi.world.Stadium; import net.pivipi.world.Stadium;
@ -50,7 +50,7 @@ public class BallKicker { // TODO apply physics settings here
Player player = event.getPlayer(); Player player = event.getPlayer();
Pos deltaPos = new Pos(0, 0.3, 0); Pos deltaPos = new Pos(0, 0.3, 0);
boolean collides = Collision.collidesWithEntity(stadium.ball, player); boolean collides = CollisionDetector.collidesWithEntity(stadium.ball, player);
if (collides) { if (collides) {
System.out.println(deltaPos); System.out.println(deltaPos);
stadium.ball.addPos(deltaPos.asVec()); stadium.ball.addPos(deltaPos.asVec());
@ -87,7 +87,7 @@ public class BallKicker { // TODO apply physics settings here
Player player = event.getPlayer(); Player player = event.getPlayer();
CollisionData collisionData = new CollisionData(); CollisionData collisionData = new CollisionData();
Collision.pushOutside(player, stadium.ball, collisionData); CollisionDetector.pushOutside(player, stadium.ball, collisionData);
double distance = collisionData.distance.withY(0).distance(0, 0, 0); double distance = collisionData.distance.withY(0).distance(0, 0, 0);
if (collisionData.distance.y() < verticalReach && distance < reach) { if (collisionData.distance.y() < verticalReach && distance < reach) {

View file

@ -7,8 +7,10 @@ import net.minestom.server.coordinate.Pos;
import net.minestom.server.coordinate.Vec; import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.Entity; import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.block.Block;
public class Collision { public class CollisionDetector {
/** /**
* *
* @param entity * @param entity
@ -42,6 +44,29 @@ public class Collision {
return new BoundingBox(10, 1, 10).intersectEntity(entity.getPosition().withY(groundY - 1).sub(5, 0, 5), entity); return new BoundingBox(10, 1, 10).intersectEntity(entity.getPosition().withY(groundY - 1).sub(5, 0, 5), entity);
} }
/**
*
* @param blockPos the block position
* @param blockBoundingBox the block bounding box get it with registry.shape
* @param pushed the pushed entity
* @return offset you must apply to push the entity outside, null if doesn't collide
*/
public static Vec pushOutsideBlock(Pos blockPos, BoundingBox blockBoundingBox, Entity pushed) {
return pushOutsideBlock(blockPos, blockBoundingBox, pushed, null);
}
/**
*
* @param blockPos the block position
* @param blockBoundingBox the block bounding box get it with registry.shape
* @param pushed the pushed entity
* @param collisionData puts data in this object
* @return offset you must apply to push the entity outside, null if doesn't collide
*/
public static Vec pushOutsideBlock(Pos blockPos, BoundingBox blockBoundingBox, Entity pushed, CollisionData collisionData) {
return pushOutside(blockPos.add(0.5, 0, 0.5), blockBoundingBox, pushed.getPosition(), pushed.getBoundingBox(), collisionData); // TODO
}
/** /**
* *
* @param pusher the entity that's pushing like a player * @param pusher the entity that's pushing like a player
@ -60,7 +85,8 @@ public class Collision {
* @return offset you must apply to push the entity outside, null if doesn't collide * @return offset you must apply to push the entity outside, null if doesn't collide
*/ */
public static Vec pushOutside(Entity pusher, Entity pushed, CollisionData collisionData) { public static Vec pushOutside(Entity pusher, Entity pushed, CollisionData collisionData) {
double ballXSize = pushed.getBoundingBox().width(); return pushOutside(pusher.getPosition(), pusher.getBoundingBox(), pushed.getPosition(), pushed.getBoundingBox(), collisionData);
/*double ballXSize = pushed.getBoundingBox().width();
double playerXSize = pusher.getBoundingBox().width(); double playerXSize = pusher.getBoundingBox().width();
double ballZSize = pushed.getBoundingBox().depth(); double ballZSize = pushed.getBoundingBox().depth();
double playerZSize = pusher.getBoundingBox().depth(); double playerZSize = pusher.getBoundingBox().depth();
@ -103,6 +129,55 @@ public class Collision {
} }
if (diffX < 0 && diffZ < 0)
return diffX < diffZ ? newBallOffset.withX(0) : newBallOffset.withZ(0);
return null;*/
}
private static Vec pushOutside(Pos pusherPos, BoundingBox pusherBox, Pos pushedPos, BoundingBox pushedBox, CollisionData collisionData) {
double ballXSize = pushedBox.width();
double playerXSize = pusherBox.width();
double ballZSize = pushedBox.depth();
double playerZSize = pusherBox.depth();
double ballHeight = pushedBox.height();
double playerHeight = pusherBox.height();
Pos ballCenterPos = pushedPos;
Pos playerCenterPos = pusherPos;
Pos ballPos = ballCenterPos.sub(ballXSize / 2, 0, ballZSize / 2); // corner
Pos playerPos = playerCenterPos.sub(playerXSize / 2, 0, playerZSize / 2);
Vec ballDistance = ballCenterPos.sub(playerCenterPos).asVec(); // center distance
if (collisionData != null) // TODO move this
collisionData.distance = ballDistance;
if (ballDistance.y() > 0 && ballPos.y() > playerPos.y() + playerHeight) return null; // doesn't collide on y+
else if (playerPos.y() > ballPos.y() + ballHeight) return null; // doesn't collide on y-
Vec newBallOffset = new Vec(0);
double diffX = 0, diffZ = 0;
if (ballDistance.x() > 0) {
diffX = ballPos.x() - (playerPos.x() + playerXSize);
if (diffX < 0) // collides on x+
newBallOffset = newBallOffset.withX(-diffX);
} else {
diffX = playerPos.x() - (ballPos.x() + ballXSize);
if (diffX < 0) // collides on x-
newBallOffset = newBallOffset.withX(diffX);
}
if (ballDistance.z() > 0) {
diffZ = ballPos.z() - (playerPos.z() + playerZSize);
if (diffZ < 0) // collides on z+
newBallOffset = newBallOffset.withZ(-diffZ);
} else {
diffZ = playerPos.z() - (ballPos.z() + ballZSize);
if (diffZ < 0) // collides on z-
newBallOffset = newBallOffset.withZ(diffZ);
}
if (diffX < 0 && diffZ < 0) if (diffX < 0 && diffZ < 0)
return diffX < diffZ ? newBallOffset.withX(0) : newBallOffset.withZ(0); return diffX < diffZ ? newBallOffset.withX(0) : newBallOffset.withZ(0);

View file

@ -1,14 +1,22 @@
package net.pivipi.physics; package net.pivipi.physics;
import java.util.ArrayList;
import java.util.List;
import java.util.Set; import java.util.Set;
import net.minestom.server.collision.BoundingBox;
import net.minestom.server.collision.VisibleSweepResult; import net.minestom.server.collision.VisibleSweepResult;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.coordinate.Vec; import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.Entity; import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.instance.block.Block;
import net.minestom.server.network.packet.server.play.ParticlePacket; import net.minestom.server.network.packet.server.play.ParticlePacket;
import net.minestom.server.particle.Particle; import net.minestom.server.particle.Particle;
import net.pivipi.ball.Ball;
import net.pivipi.physics.aabb.AABB;
import net.pivipi.physics.aabb.AABBEntity;
import net.pivipi.physics.aabb.AABBPlayer;
public class Physics { public class Physics {
private final double gravity = 9.8; private final double gravity = 9.8;
@ -23,23 +31,32 @@ public class Physics {
private final double jumpStrength = 20; private final double jumpStrength = 20;
private final double groundFriction = 0.5; private final double groundFriction = 0.5;
private final double airFriction = 0.1; private final double airFriction = 0.1;
private final int groundY = 64; private final AABB groundAABB = new AABB(new Vec(Double.MIN_VALUE, Double.MIN_VALUE, Double.MIN_VALUE), new Vec(Double.MAX_VALUE, 64, Double.MAX_VALUE));
private final double flame = 20; // flame starts at speed private final double flame = 20; // flame starts at speed
private final double flameFreq = 100; // ms per flame private final double flameFreq = 100; // ms per flame
private final double flameIncrement = 0.5; // ms per flame decrement per speed unit private final double flameIncrement = 0.5; // ms per flame decrement per speed unit
private final float flameSpread = 0.2f; private final float flameSpread = 0.2f;
private final Pos[] blocksNearby = new Pos[] {
new Pos(0, 0, 0), // bottom edge
new Pos(0, 1, 0), // top edge
new Pos(0.5, 0.5, 0), // x+ edge
new Pos(-0.5, 0.5, 0), // x- edge
new Pos(0, 0.5, 0.5), // z+ edge
new Pos(0, 0.5, -0.5), // z- edge
};
private Vec velocity = new Vec(0, 0, 0); private Vec velocity = new Vec(0, 0, 0);
private final Entity entity; private final AABBEntity entity;
private int p; private int p;
public Physics(Entity entity) { public Physics(AABBEntity entity) {
this.entity = entity; this.entity = entity;
} }
public void process(double delta, Set<Player> players) { public void process(double delta, Set<AABBPlayer> players) {
velocity = applyPhysics(delta, players); velocity = applyPhysics(delta, players);
entity.teleport(entity.getPosition().add(velocity.mul(delta))); entity.teleport(entity.getPosition().add(velocity.mul(delta)));
@ -58,40 +75,81 @@ public class Physics {
} }
} }
private Vec applyPhysics(double delta, Set<Player> players) { private Vec applyPhysics(double delta, Set<AABBPlayer> players) {
velocity = velocity.sub(0, gravity * delta, 0).mul(1 - (airFriction * delta), 1, 1 - (airFriction * delta)); velocity = velocity.sub(0, gravity * delta, 0).mul(1 - (airFriction * delta), 1, 1 - (airFriction * delta));
AABB aabb = entity.getAabb().velocity(velocity.mul(delta));
if (Collision.collidesWithGround(groundY, entity)) { double groundToi = groundAABB.timeOfImpact(aabb);
entity.teleport(entity.getPosition().withY(groundY)); //System.out.println(velocity.mul(delta));
//System.out.println(aabb.getMin(false));
if (groundToi < 1) {
if (groundToi > 0)
entity.move(velocity.mul(delta).mul(groundToi));
else entity.teleport(entity.getPosition().withY(65));
velocity = velocity.mul(1 - (groundFriction * delta), -blockBounciness, 1 - (groundFriction * delta)); velocity = velocity.mul(1 - (groundFriction * delta), -blockBounciness, 1 - (groundFriction * delta));
} else { aabb.velocity(velocity);
for (Player player : players) {
boolean collides = Collision.collidesWithEntity(player, entity);
if (collides) {
handlePlayerTouch(player);
break;
}
}
} }
players.forEach(player -> {
Vec offset = aabb.resolve(player.getAabb());
if (offset != null) {
entity.move(offset);
}
});
return velocity; return velocity;
} }
private void handlePlayerTouch(Player player) { private void handleBlockTouch(Pos blockRelativePos, int edge) {
//Pos blockPos = entity.getPosition().sub(entity.getBoundingBox().width() / 2, 0, entity.getBoundingBox().height() / 2).add(blockRelativePos);
Pos blockPos = entity.getPosition().add(blockRelativePos);//.withX(x -> (int)(x - entity.getBoundingBox().width() / 2)).withZ(z -> (int)(z - entity.getBoundingBox().depth() / 2)).withY(y -> (int)(y));
//Pos blockPos = ballEdgePos.withX(x -> (int)(x)).withY(y -> (int)(y)).withZ(z -> (int)(z));
Block block = entity.getInstance().getBlock(blockPos);
if (block.equals(Block.AIR)) return;
CollisionData collisionData = new CollisionData(); CollisionData collisionData = new CollisionData();
Vec offset = Collision.pushOutside(player, entity, collisionData); // TODO predict the collision CollisionDetector.pushOutsideBlock(blockPos, new BoundingBox(1, 1, 1), entity, collisionData);
Vec offset = collisionData.distance;
if (block != Block.AIR) {
//entity.teleport(entity.getPosition().add(collisionData.distance));
switch (edge) {
case 0:
case 1:
System.out.println(edge);
offset = offset.mul(0, 1, 0);//.withY(y -> ballEdgePos.y() - blockPos.y());
//velocity = velocity.mul(1, -blockBounciness, 1);
break;
case 2:
offset = offset.add(0.5, 0, 0);
case 3:
System.out.println(edge);
offset = offset.mul(1, 0, 0);//.withX(x -> ballEdgePos.x() - blockPos.x());
//velocity = velocity.mul(-blockBounciness, 1, 1);
break;
case 4:
System.out.println("addin");
offset = offset.add(0, 0, 0.5);
case 5:
System.out.println(edge);
offset = offset.mul(0, 0, 1);//.withZ(z -> ballEdgePos.z() - blockPos.z());
//velocity = velocity.mul(1, 1, -blockBounciness);
break;
}
System.out.println(offset);
entity.teleport(entity.getPosition().add(offset));
}
}
private void handlePlayerTouch(Player player, Vec offset) {
Vec distance = entity.getPosition().sub(entity.getPosition()).asVec();
if (offset != null) { if (offset != null) {
Pos movementPos = player.getPosition().sub(player.getPreviousPosition()); Pos movementPos = player.getPosition().sub(player.getPreviousPosition());
boolean oppositeX = (collisionData.distance.x() > 0 ? velocity.x() < 0 : velocity.x() > 0); boolean oppositeX = (distance.x() > 0 ? velocity.x() < 0 : velocity.x() > 0);
boolean oppositeZ = (collisionData.distance.z() > 0 ? velocity.z() < 0 : velocity.z() > 0); boolean oppositeZ = (distance.z() > 0 ? velocity.z() < 0 : velocity.z() > 0);
double headOffsetY = player.getBoundingBox().height() - collisionData.distance.y(); double headOffsetY = player.getBoundingBox().height() - distance.y();
System.out.println(offset);
System.out.println(oppositeX);
System.out.println(velocity.x());
if (headOffsetY < 0.6) { // landed on head, magic value head height if (headOffsetY < 0.6) { // landed on head, magic value head height
if (movementPos.y() > 0) { if (movementPos.y() > 0) {
@ -101,18 +159,13 @@ public class Physics {
} else velocity = velocity.mul(1, player.isSneaking() ? -playerSneakingHeadBounciness : -playerHeadBounciness, 1); } else velocity = velocity.mul(1, player.isSneaking() ? -playerSneakingHeadBounciness : -playerHeadBounciness, 1);
entity.teleport(entity.getPosition().withY(y -> y + headOffsetY)); entity.teleport(entity.getPosition().withY(y -> y + headOffsetY));
} else { } else {
System.out.println("tping");
entity.teleport(entity.getPosition().add(offset.mul(1.1))); // magic value to make some space in case of desync entity.teleport(entity.getPosition().add(offset.mul(1.1))); // magic value to make some space in case of desync
double bodyBounciness = player.isSneaking() ? -playerSneakingBodyBounciness : -playerBodyBounciness; double bodyBounciness = player.isSneaking() ? -playerSneakingBodyBounciness : -playerBodyBounciness;
System.out.println(velocity);
velocity = velocity velocity = velocity
.withX(x -> oppositeX ? x * bodyBounciness : x + movementPos.x() * playerCarryStrength) .withX(x -> oppositeX ? x * bodyBounciness : x + movementPos.x() * playerCarryStrength)
.withY(y -> collisionData.distance.y() < 1.0 ? movementPos.y() * jumpStrength : y) // magic value legs .withY(y -> distance.y() < 1.0 ? movementPos.y() * jumpStrength : y) // magic value legs
.withZ(z -> oppositeZ ? z * bodyBounciness : z + movementPos.z() * playerCarryStrength); .withZ(z -> oppositeZ ? z * bodyBounciness : z + movementPos.z() * playerCarryStrength);
System.out.println(velocity);
} }
} }

View file

@ -0,0 +1,154 @@
package net.pivipi.physics.aabb;
import net.kyori.adventure.bossbar.BossBar.Overlay;
import net.minestom.server.collision.BoundingBox;
import net.minestom.server.collision.SweepResult;
import net.minestom.server.collision.VisibleSweepResult;
import net.minestom.server.coordinate.Vec;
import net.pivipi.physics.CollisionData;
public class AABB {
Vec min, max;
Vec velocity = Vec.ZERO;
public AABB(Vec min, Vec max) {
this.min = min;
this.max = max;
}
public Vec getMin(boolean swept) {
if (swept) min = min.min(min.add(velocity));
return min;
}
public Vec getMax(boolean swept) {
if (swept) max = max.min(max.add(velocity));
return max;
}
public Vec getVelocity() {
return velocity;
}
public AABB velocity(Vec velocity) {
this.velocity = velocity;
return this;
}
/**
* check if collides target
* @param aabb the target
* @param swept is target swept
* @return
*/
public boolean collides(AABB aabb, boolean swept) {
Vec bMin = aabb.getMin(swept);
Vec bMax = aabb.getMax(swept);
return (min.x() <= bMax.x() && max.x() >= bMin.x() &&
min.y() <= bMax.y() && max.y() >= bMin.y() &&
min.z() <= bMax.z() && max.z() >= bMin.z());
}
/**
* time of impact with target
* @param moving another target (moving or not)
* @return percent of velocity moved, Double.NEGATIVE_INFINITY if already collides, Double.POSITIVE_INFINITY otherwise
*/
public double timeOfImpact(AABB moving) {
if (this.collides(moving, false)) return Double.NEGATIVE_INFINITY;
SweepResult sweepResult = new SweepResult(1, 0, 0, 0, null, 0, 0, 0);
Vec bb = max.sub(min);
Vec bb2 = moving.max.sub(moving.min);
Vec relativeVelocity = moving.velocity.sub(velocity);
boolean collides = new BoundingBox(bb.x(), bb.y(), bb.z()).intersectBoxSwept(moving.min, relativeVelocity, min, new BoundingBox(bb2.x(), bb2.y(), bb2.z()), sweepResult);
if (!collides) return Double.POSITIVE_INFINITY;
return new VisibleSweepResult(sweepResult).res;
/* Vec relativeVelocity = moving.velocity.sub(velocity);
double enterX = Double.NEGATIVE_INFINITY, exitX = Double.POSITIVE_INFINITY;
double enterY = Double.NEGATIVE_INFINITY, exitY = Double.POSITIVE_INFINITY;
double enterZ = Double.NEGATIVE_INFINITY, exitZ = Double.POSITIVE_INFINITY;
boolean overlap = true;
if (relativeVelocity.x() != 0) {
enterX = (moving.min.x() - max.x()) / relativeVelocity.x();
exitX = (moving.max.x() - min.x()) / relativeVelocity.x();
} else {
overlap = overlap && !(max.x() < moving.min.x() || moving.max.x() < min.x());
}
if (relativeVelocity.y() != 0) {
enterY = (moving.min.y() - max.y()) / relativeVelocity.y();
exitY = (moving.max.y() - min.y()) / relativeVelocity.y();
} else {
overlap = overlap && !(max.y() < moving.min.y() || moving.max.y() < min.y());
}
if (relativeVelocity.z() != 0) {
enterZ = (moving.min.z() - max.z()) / relativeVelocity.z();
exitZ = (moving.max.z() - min.z()) / relativeVelocity.z();
} else {
overlap = overlap && !(max.z() < moving.min.z() || moving.max.z() < min.z());
}
//if (overlap) return Double.NEGATIVE_INFINITY;
double entry = Math.max(Math.max(enterX, enterY), enterZ);
double exit = Math.min(Math.min(exitX, exitY), exitZ);
return entry > exit ? Double.POSITIVE_INFINITY : entry; // TODO simplify*/
}
/**
* don't push myself inside
* @param aabb the object, it can be moving
* @return offset to move me by or null if no overlap
*/
public Vec resolveSwept(AABB aabb) {
double toi = timeOfImpact(aabb);
return toi < 0 || toi > 1 ? null : velocity.mul(toi);
}
/**
* push myself outside
* @param aabb the static object
* @return offset to move me by or null if no overlap
*/
public Vec resolve(AABB aabb) {
Vec bMin = aabb.getMin(false);
Vec bMax = aabb.getMax(false);
Vec offset = Vec.ZERO;
Vec overlap = new Vec(
Math.min(max.x(), bMax.x()) - Math.max(min.x(), bMin.x()),
Math.min(max.y(), bMax.y()) - Math.max(min.y(), bMin.y()),
Math.min(max.z(), bMax.z()) - Math.max(min.z(), bMin.z()));
if (overlap.x() <= 0 || overlap.y() <= 0 || overlap.z() <= 0)
return null;
if (overlap.x() < overlap.y() && overlap.x() < overlap.z()) {
if (min.x() < bMin.x())
offset = offset.withX(x -> x - overlap.x());
else
offset = offset.withX(x -> x + overlap.x());
} else if (overlap.y() < overlap.x() && overlap.y() < overlap.z()) {
if (min.y() < bMin.y())
offset = offset.withY(y -> y - overlap.y());
else
offset = offset.withY(y -> y + overlap.y());
} else {
if (min.z() < bMin.z())
offset = offset.withZ(z -> z - overlap.z());
else
offset = offset.withZ(z -> z + overlap.z());
}
return offset;
}
}

View file

@ -0,0 +1,29 @@
package net.pivipi.physics.aabb;
import org.jetbrains.annotations.NotNull;
import net.minestom.server.collision.BoundingBox;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityType;
public class AABBEntity extends Entity {
protected AABB aabb = new AABB(Vec.ZERO, Vec.ZERO);
public AABBEntity(@NotNull EntityType entityType) {
super(entityType);
// TODO Auto-generated constructor stub
}
public AABB getAabb() {
aabb.min = this.getPosition().sub(this.getBoundingBox().width() / 2, 0, this.getBoundingBox().depth() / 2).asVec();
aabb.max = this.getPosition().add(this.getBoundingBox().width() / 2, this.getBoundingBox().height(), this.getBoundingBox().depth() / 2).asVec();
aabb.velocity = this.getVelocity();
return aabb;
}
public void move(Vec offset) {
this.teleport(this.getPosition().add(offset));
}
}

View file

@ -0,0 +1,44 @@
package net.pivipi.physics.aabb;
import java.util.UUID;
import org.jetbrains.annotations.NotNull;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.Player;
import net.minestom.server.network.PlayerProvider;
import net.minestom.server.network.player.PlayerConnection;
public class AABBPlayer extends Player {
protected AABB aabb = new AABB(Vec.ZERO, Vec.ZERO);
private Pos lastPosition = Pos.ZERO;
private long lastUpdate;
private double delta;
private Pos movement;
public AABBPlayer(@NotNull UUID uuid, @NotNull String username, @NotNull PlayerConnection playerConnection) {
super(uuid, username, playerConnection);
// TODO Auto-generated constructor stub
}
public AABB getAabb() {
aabb.min = this.getPosition().sub(this.getBoundingBox().width() / 2, 0, this.getBoundingBox().depth() / 2).asVec();
aabb.max = this.getPosition().add(this.getBoundingBox().width() / 2, this.getBoundingBox().height(), this.getBoundingBox().depth() / 2).asVec();
aabb.velocity = this.getVelocity().mul(delta).add(movement);
return aabb;
}
@Override
public void update(long time) {
super.update(time);
this.movement = this.getPosition().sub(lastPosition);
this.lastPosition = this.getPosition();
this.delta = (time - lastUpdate) / 1000.0;
this.lastUpdate = time;
}
}

View file

@ -0,0 +1,11 @@
package net.pivipi.physics.aabb;
import net.minestom.server.coordinate.Vec;
public class BlockAABB extends AABB {
public BlockAABB(Vec pos) {
super(pos, pos.add(1));
}
}

View file

@ -5,8 +5,9 @@ import java.util.Set;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.pivipi.ball.Ball; import net.pivipi.ball.Ball;
import net.pivipi.physics.aabb.AABBPlayer;
public class Stadium { public class Stadium {
public final Set<Player> players = new HashSet<Player>(); public final Set<AABBPlayer> players = new HashSet<AABBPlayer>();
public Ball ball; public Ball ball;
} }