diff --git a/src/main/java/net/pivipi/LoginHandler.java b/src/main/java/net/pivipi/LoginHandler.java index 4a717e0..298ae49 100644 --- a/src/main/java/net/pivipi/LoginHandler.java +++ b/src/main/java/net/pivipi/LoginHandler.java @@ -5,27 +5,26 @@ import net.minestom.server.entity.GameMode; import net.minestom.server.entity.Player; import net.minestom.server.event.GlobalEventHandler; import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; +import net.minestom.server.event.player.PlayerDisconnectEvent; import net.minestom.server.event.player.PlayerSpawnEvent; import net.minestom.server.instance.Instance; import net.pivipi.ball.Ball; +import net.pivipi.ball.BallKicker; +import net.pivipi.world.Stadium; public class LoginHandler { private final Instance spawningInstance; + private final Stadium stadium = new Stadium(); public LoginHandler(Instance spawningInstance) { this.spawningInstance = spawningInstance; } public void setup(GlobalEventHandler globalEventHandler) { - globalEventHandler.addListener( - AsyncPlayerConfigurationEvent.class, - event -> onLogin(event) - ); - - globalEventHandler.addListener( - PlayerSpawnEvent.class, - event -> onSpawn(event) - ); + globalEventHandler.addListener(AsyncPlayerConfigurationEvent.class, event -> onLogin(event)); + globalEventHandler.addListener(PlayerDisconnectEvent.class, event -> onQuit(event)); + globalEventHandler.addListener(PlayerSpawnEvent.class, event -> onSpawn(event)); + new BallKicker(stadium).setup(globalEventHandler); } private void onLogin(AsyncPlayerConfigurationEvent event) { @@ -35,15 +34,23 @@ public class LoginHandler { event.setHardcore(true); player.setRespawnPoint(new Pos(0, 5, 0)); + stadium.players.add(player); + } + + private void onQuit(PlayerDisconnectEvent event) { + stadium.players.remove(event.getPlayer()); } private void onSpawn(PlayerSpawnEvent event) { Player player = event.getPlayer(); player.setGameMode(GameMode.CREATIVE); - - Ball ball = new Ball(); - ball.setInstance(event.getInstance()); - ball.teleport(new Pos(0.5, 15, 0.5)); + + if (stadium.ball == null) { + Ball ball = new Ball(stadium); + ball.setInstance(event.getInstance()); + ball.teleport(new Pos(0.5, 15, 0.5)); + stadium.ball = ball; + } } } diff --git a/src/main/java/net/pivipi/Main.java b/src/main/java/net/pivipi/Main.java index 4f2d705..808ae53 100644 --- a/src/main/java/net/pivipi/Main.java +++ b/src/main/java/net/pivipi/Main.java @@ -8,6 +8,7 @@ import net.minestom.server.instance.InstanceManager; import net.minestom.server.instance.LightingChunk; import net.minestom.server.registry.DynamicRegistry.Key; import net.minestom.server.world.DimensionType; +import net.pivipi.ball.BallKicker; import net.pivipi.world.FancyDimension; import net.pivipi.world.SoccerGenerator; import net.pivipi.world.WorldConstraints; diff --git a/src/main/java/net/pivipi/ball/Ball.java b/src/main/java/net/pivipi/ball/Ball.java index 71fd87f..6abaa6f 100644 --- a/src/main/java/net/pivipi/ball/Ball.java +++ b/src/main/java/net/pivipi/ball/Ball.java @@ -1,41 +1,57 @@ package net.pivipi.ball; +import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.Entity; import net.minestom.server.entity.EntityType; import net.minestom.server.entity.metadata.other.FallingBlockMeta; +import net.minestom.server.event.player.PlayerDisconnectEvent; import net.minestom.server.instance.block.Block; import net.pivipi.physics.Physics; +import net.pivipi.world.Stadium; public class Ball extends Entity { private long lastTick; + private final Physics physics = new Physics(this); + public final Stadium stadium; - public Ball(Block block) { + public Ball(Block block, Stadium stadium) { super(EntityType.FALLING_BLOCK); // not block display because its movement lags for some reason this.setNoGravity(true); this.setGlowing(true); + this.hasPhysics = true; this.editEntityMeta(FallingBlockMeta.class, meta -> { meta.setBlock(block); }); + + this.stadium = stadium; } - public Ball() { - this(Block.WHITE_WOOL); + public Ball(Stadium stadium) { + this(Block.WHITE_WOOL, stadium); } - public void tick(long time) { // I don't know if change that to update + public void update(long time) { if (this.lastTick == 0) { this.lastTick = time; } long delay = time - this.lastTick; - physics.applyPhysics(delay / 1000.0); + physics.applyPhysics(delay / 1000.0, stadium.players); this.lastTick = time; } + + public void addVelocity(Vec velocity) { + physics.addVelocity(velocity); + } + + public void addPos(Vec vec) { + this.teleport(this.getPosition().add(vec)); + } } diff --git a/src/main/java/net/pivipi/ball/BallKicker.java b/src/main/java/net/pivipi/ball/BallKicker.java new file mode 100644 index 0000000..f25fc0f --- /dev/null +++ b/src/main/java/net/pivipi/ball/BallKicker.java @@ -0,0 +1,87 @@ +package net.pivipi.ball; + +import java.awt.Event; +import java.util.HashSet; +import java.util.Set; + +import net.minestom.server.MinecraftServer; +import net.minestom.server.ServerFlag; +import net.minestom.server.collision.VisibleSweepResult; +import net.minestom.server.coordinate.Point; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.coordinate.Vec; +import net.minestom.server.entity.Entity; +import net.minestom.server.entity.Player; +import net.minestom.server.event.GlobalEventHandler; +import net.minestom.server.event.player.PlayerMoveEvent; +import net.minestom.server.event.player.PlayerStartSneakingEvent; +import net.minestom.server.event.player.PlayerStopSneakingEvent; +import net.minestom.server.instance.Instance; +import net.pivipi.physics.Collision; +import net.pivipi.world.Stadium; + +public class BallKicker { // TODO apply physics settings here + public final Stadium stadium; + + private long lastSneak; + private int sneakStreak; + + public BallKicker(Stadium stadium) { + this.stadium = stadium; + } + + public void setup(GlobalEventHandler globalEventHandler) { + globalEventHandler.addListener(PlayerMoveEvent.class, event -> onMove(event)); + globalEventHandler.addListener(PlayerStartSneakingEvent.class, event -> onSneak(event)); + globalEventHandler.addListener(PlayerStopSneakingEvent.class, event -> onStopSneaking(event)); + } + + private void onMove(PlayerMoveEvent event) { + Player player = event.getPlayer(); + + Pos deltaPos = player.getPosition().sub(player.getPreviousPosition());// TODO + boolean collides = Collision.collidesWithEntity(stadium.ball, player); + if (collides) { + System.out.println(deltaPos); + stadium.ball.addPos(deltaPos.asVec()); + stadium.ball.addVelocity(deltaPos.asVec().mul(2, 2, 2)); + } + } + + private void onStopSneaking(PlayerStopSneakingEvent event) { + Player player = event.getPlayer(); + + Pos deltaPos = new Pos(0, 0.3, 0); + boolean collides = Collision.collidesWithEntity(stadium.ball, player); + if (collides) { + System.out.println(deltaPos); + stadium.ball.addPos(deltaPos.asVec()); + stadium.ball.addVelocity(deltaPos.asVec().mul(10)); + } + } + + private void onSneak(PlayerStartSneakingEvent event) { + long now = System.currentTimeMillis(); + long sneakDelay = now - lastSneak; + lastSneak = now; + + if (sneakDelay < 500) { + if (++sneakStreak > 5) { + Player player = event.getPlayer(); + Point targetPos = player.getTargetBlockPosition(10); + if (targetPos == null) targetPos = player.getPosition(); + targetPos = targetPos.add(0, 5, 0); + + Ball ball = new Ball(stadium); + ball.setInstance(event.getInstance()); + ball.teleport(new Pos(targetPos)); + + stadium.ball.remove(); + stadium.ball = ball; + sneakStreak = 0; + } + } else { + sneakStreak = 0; + } + } +} diff --git a/src/main/java/net/pivipi/physics/Collision.java b/src/main/java/net/pivipi/physics/Collision.java index 7523ef0..034bc18 100644 --- a/src/main/java/net/pivipi/physics/Collision.java +++ b/src/main/java/net/pivipi/physics/Collision.java @@ -10,13 +10,15 @@ import net.minestom.server.entity.Player; public class Collision { /** * - * @param player + * @param entity * @param moving the moving entity * @param velocity the applied velocity * @return null if no collision */ - public static VisibleSweepResult willCollideWithPlayer(Player player, Entity moving, Vec velocity) { - return null; // TODO + public static VisibleSweepResult willCollideWithEntity(Entity entity, Entity moving, Vec movement) { + SweepResult sweepResult = new SweepResult(1, 0, 0, 0, null, 0, 0, 0); + boolean collided = entity.getBoundingBox().intersectBoxSwept(moving.getPosition(), movement, entity.getPosition(), moving.getBoundingBox(), sweepResult); + return collided ? new VisibleSweepResult(sweepResult) : null; } /** @@ -27,7 +29,15 @@ public class Collision { */ public static VisibleSweepResult willCollideWithGround(double groundY, Entity moving, Vec movement) { SweepResult sweepResult = new SweepResult(1, 0, 0, 0, null, 0, 0, 0); - boolean collided = new BoundingBox(10, 10, 1).intersectBoxSwept(moving.getPosition(), movement, moving.getPosition().withY(groundY).sub(5, 0, 5), moving.getBoundingBox(), sweepResult); + boolean collided = new BoundingBox(10, 1, 10).intersectBoxSwept(moving.getPosition(), movement, moving.getPosition().withY(groundY - 1).sub(5, 0, 5), moving.getBoundingBox(), sweepResult); return collided ? new VisibleSweepResult(sweepResult) : null; } + + public static boolean collidesWithEntity(Entity entity1, Entity entity2) { + return entity1.getBoundingBox().intersectEntity(entity1.getPosition(), entity2); + } + + public static boolean collidesWithGround(double groundY, Entity entity) { + return new BoundingBox(10, 1, 10).intersectEntity(entity.getPosition().withY(groundY - 1).sub(5, 0, 5), entity); + } } diff --git a/src/main/java/net/pivipi/physics/Physics.java b/src/main/java/net/pivipi/physics/Physics.java index 85a9679..bec2910 100644 --- a/src/main/java/net/pivipi/physics/Physics.java +++ b/src/main/java/net/pivipi/physics/Physics.java @@ -1,14 +1,22 @@ package net.pivipi.physics; +import java.util.Set; + import net.minestom.server.collision.VisibleSweepResult; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.Entity; +import net.minestom.server.entity.Player; public class Physics { private final double gravity = 9.8; - private final double bounciness = 1; + private final double blockBounciness = 0.5; + private final double playerHeadBounciness = 0.5; + private final double playerSneakingHeadBounciness = 0.2; + private final double playerBodyBounciness = 0.2; + private final double groundFriction = 0.5; + private final double airFriction = 0.1; - private Vec velocity = new Vec(5, 0, 5); + private Vec velocity = new Vec(0, 0, 0); private final Entity entity; @@ -16,16 +24,32 @@ public class Physics { this.entity = entity; } - public void applyPhysics(double delta) { - velocity = velocity.sub(0, gravity * delta, 0); + public void applyPhysics(double delta, Set players) { + velocity = velocity.sub(0, gravity * delta, 0).mul(1 - (airFriction * delta), 1, 1 - (airFriction * delta)); - VisibleSweepResult result = Collision.willCollideWithGround(5, entity, velocity); - System.out.println(result); - if (entity.isOnGround()) { - //System.out.println(result.res); - velocity = velocity.mul(0, -bounciness, 0); + if (Collision.collidesWithGround(2, entity)) { + entity.teleport(entity.getPosition().withY(2)); + velocity = velocity.mul(1 - (groundFriction * delta), 1, 1 - (groundFriction * delta)); } - entity.setVelocity(velocity); + VisibleSweepResult result = Collision.willCollideWithGround(2, entity, velocity.mul(delta)); + if (result != null) { + velocity = velocity.mul(1, -blockBounciness, 1); + } else { + for (Player player : players) { + boolean collides = Collision.collidesWithEntity(player, entity); + if (collides) { + velocity = velocity.mul(-playerBodyBounciness, player.isSneaking() ? -playerSneakingHeadBounciness : -playerHeadBounciness, -playerBodyBounciness); + break; + } + } + } + + entity.teleport(entity.getPosition().add(velocity.mul(delta))); + //entity.setVelocity(velocity); + } + + public void addVelocity(Vec velocity) { + this.velocity = this.velocity.add(velocity); } } diff --git a/src/main/java/net/pivipi/world/Stadium.java b/src/main/java/net/pivipi/world/Stadium.java new file mode 100644 index 0000000..6150126 --- /dev/null +++ b/src/main/java/net/pivipi/world/Stadium.java @@ -0,0 +1,13 @@ +package net.pivipi.world; + +import java.util.HashSet; +import java.util.Set; + +import net.minestom.server.entity.Player; +import net.pivipi.ball.Ball; +import net.pivipi.ball.BallKicker; + +public class Stadium { + public final Set players = new HashSet(); + public Ball ball; +}