diff --git a/pom.xml b/pom.xml
index b4bb87a..e687014 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,7 +17,7 @@
net.minestom
minestom-snapshots
- d606051f1e
+ 7dd1792096
org.slf4j
diff --git a/src/main/java/net/pivipi/LoginHandler.java b/src/main/java/net/pivipi/LoginHandler.java
index 09b5293..7a976ca 100644
--- a/src/main/java/net/pivipi/LoginHandler.java
+++ b/src/main/java/net/pivipi/LoginHandler.java
@@ -1,6 +1,7 @@
package net.pivipi;
import net.minestom.server.coordinate.Pos;
+import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.attribute.Attribute;
@@ -9,23 +10,24 @@ 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;
+import net.pivipi.game.Game;
+import net.pivipi.game.Stadium;
public class LoginHandler {
private final Instance spawningInstance;
- private final Stadium stadium = new Stadium();
+ private final Game game;
public LoginHandler(Instance spawningInstance) {
this.spawningInstance = spawningInstance;
+ this.game = new Game(new Stadium(spawningInstance, new Vec(-50, 64, -50), new Vec(100)));
}
public void setup(GlobalEventHandler globalEventHandler) {
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);
+ new BallKicker(game.stadium).setup(globalEventHandler);
}
private void onLogin(AsyncPlayerConfigurationEvent event) {
@@ -35,11 +37,11 @@ public class LoginHandler {
event.setHardcore(true);
player.setRespawnPoint(new Pos(0, 67, 0));
- stadium.players.add(player);
+ game.addPlayer(player);
}
private void onQuit(PlayerDisconnectEvent event) {
- stadium.players.remove(event.getPlayer());
+ game.removePlayer(event.getPlayer());
}
private void onSpawn(PlayerSpawnEvent event) {
@@ -49,11 +51,6 @@ public class LoginHandler {
player.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.2);
player.getAttribute(Attribute.GENERIC_JUMP_STRENGTH).setBaseValue(0.36813); // just enough to jump a block
- if (stadium.ball == null) {
- Ball ball = new Ball(stadium);
- ball.setInstance(event.getInstance());
- ball.teleport(new Pos(0, 90, 5));
- stadium.ball = ball;
- }
+ game.startWarmup();
}
}
diff --git a/src/main/java/net/pivipi/Stats.java b/src/main/java/net/pivipi/Stats.java
index 8223e3d..1d0c4f3 100644
--- a/src/main/java/net/pivipi/Stats.java
+++ b/src/main/java/net/pivipi/Stats.java
@@ -2,6 +2,7 @@ package net.pivipi;
import net.kyori.adventure.text.Component;
import net.minestom.server.instance.InstanceManager;
+import net.minestom.server.timer.ExecutionType;
import net.minestom.server.timer.SchedulerManager;
import net.minestom.server.timer.TaskSchedule;
@@ -19,7 +20,7 @@ public class Stats implements Runnable {
public void start(SchedulerManager schedulerManager) {
//this.benchmarkManager = MinecraftServer.getBenchmarkManager();
- schedulerManager.scheduleTask(this, TaskSchedule.immediate(), TaskSchedule.tick(tickDelay));
+ schedulerManager.scheduleTask(this, TaskSchedule.immediate(), TaskSchedule.tick(tickDelay), ExecutionType.TICK_END);
}
@Override
@@ -29,14 +30,11 @@ public class Stats implements Runnable {
lastRun = now;
double mspt = (double)delay / tickDelay;
- double tps = 1000 / mspt;
-
- long memAllocated = runtime.totalMemory() / 1024 / 1024;
- long memUsed = memAllocated - runtime.freeMemory() / 1024 / 1024;
+ long memUsed = (runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024;
- Component footer = Component.text("%.3f MSPT | %.3f TPS | %dMB / %dMB".formatted(mspt, tps, memUsed, memAllocated));
+ Component footer = Component.text("%.3f MSPT | %dMB".formatted(mspt, memUsed));
- instanceManager.getInstances().forEach(instance -> {
+ instanceManager.getInstances().forEach(instance -> { // TODO make this async
instance.getPlayers().forEach(player -> {
player.sendPlayerListFooter(footer);
});
diff --git a/src/main/java/net/pivipi/ball/Ball.java b/src/main/java/net/pivipi/ball/Ball.java
index 4c19ee3..11f3055 100644
--- a/src/main/java/net/pivipi/ball/Ball.java
+++ b/src/main/java/net/pivipi/ball/Ball.java
@@ -6,8 +6,8 @@ import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.metadata.other.FallingBlockMeta;
import net.minestom.server.instance.block.Block;
+import net.pivipi.game.Stadium;
import net.pivipi.physics.Physics;
-import net.pivipi.world.Stadium;
public class Ball extends Entity {
private long lastTick;
diff --git a/src/main/java/net/pivipi/ball/BallKicker.java b/src/main/java/net/pivipi/ball/BallKicker.java
index 893c1e3..d140466 100644
--- a/src/main/java/net/pivipi/ball/BallKicker.java
+++ b/src/main/java/net/pivipi/ball/BallKicker.java
@@ -10,9 +10,9 @@ import net.minestom.server.event.player.PlayerHandAnimationEvent;
import net.minestom.server.event.player.PlayerStartSneakingEvent;
import net.minestom.server.event.player.PlayerStopSneakingEvent;
import net.minestom.server.instance.block.Block;
+import net.pivipi.game.Stadium;
import net.pivipi.physics.Collision;
import net.pivipi.physics.CollisionData;
-import net.pivipi.world.Stadium;
public class BallKicker { // TODO apply physics settings here
public final Stadium stadium;
diff --git a/src/main/java/net/pivipi/game/Game.java b/src/main/java/net/pivipi/game/Game.java
new file mode 100644
index 0000000..df48f95
--- /dev/null
+++ b/src/main/java/net/pivipi/game/Game.java
@@ -0,0 +1,104 @@
+package net.pivipi.game;
+
+import net.minestom.server.coordinate.Pos;
+import net.minestom.server.entity.Player;
+import net.pivipi.ball.Ball;
+
+public class Game {
+ public final Stadium stadium;
+
+ public boolean started; // true even if warmup
+ public boolean warmup;
+ public boolean paused; // is game paused
+ public long startedTime; // fine until year 292272993 but trust me it will pass in an Instant
+ public long lostTime; // how much ms the game was paused for
+ public long addedTime; // also called stoppage time, cosmetic since a person decides when to end the match
+
+ private long pauseStart;
+
+ public Game(Stadium stadium) {
+ this.stadium = stadium;
+ }
+
+
+ public boolean addPlayer(Player player) {
+ return stadium.players.add(player);
+ }
+
+ public boolean removePlayer(Player player) {
+ return stadium.players.remove(player);
+ }
+
+ /**
+ * starts warmup
+ * @return true if the game was not running
+ */
+ public boolean startWarmup() {
+ if (!started && !warmup) return false;
+
+ this.started = true;
+ this.warmup = true;
+ this.startedTime = System.currentTimeMillis();
+
+ Ball ball = new Ball(stadium);
+ ball.setInstance(stadium.instance);
+ ball.teleport(new Pos(stadium.max.sub(stadium.size.div(2))));
+ stadium.ball = ball;
+
+ return true;
+ }
+
+ /**
+ * starts the game
+ * @return true if the game was not running or if there was warmup
+ */
+ public boolean start() {
+ if (started && !warmup) return false;
+
+ this.started = true;
+ this.warmup = false;
+ this.startedTime = System.currentTimeMillis();
+ // TODO
+ return true;
+ }
+
+ /**
+ * ends the game
+ * @return true if the game was running
+ */
+ public boolean end() {
+ if (!started) return false;
+
+ this.started = false;
+ this.warmup = false;
+ // TODO
+ return true;
+ }
+
+ public boolean pause() {
+ if (paused) return false;
+
+ pauseStart = System.currentTimeMillis();
+ paused = true;
+
+ return true;
+ }
+
+ public boolean unpause() {
+ if (!paused) return false;
+
+ lostTime += System.currentTimeMillis() - pauseStart;
+ paused = false;
+
+ return true;
+ }
+
+ /**
+ * suggests how much added time
+ * basically rounds down lost time to minutes
+ * @return
+ */
+ public long suggestAddedTime() {
+ return (lostTime / 60000) * 60000;
+ }
+}
diff --git a/src/main/java/net/pivipi/game/PhysicsSettings.java b/src/main/java/net/pivipi/game/PhysicsSettings.java
new file mode 100644
index 0000000..e40dfd7
--- /dev/null
+++ b/src/main/java/net/pivipi/game/PhysicsSettings.java
@@ -0,0 +1,47 @@
+package net.pivipi.game;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Type;
+
+public class PhysicsSettings {
+ public double gravity = 9.8;
+ public double blockBounciness = 0.5;
+ public double playerHeadBounciness = 0.5;
+ public double playerSneakingHeadBounciness = 0.2;
+ public double playerBodyBounciness = 0.2;
+ public double playerSneakingBodyBounciness = 0;
+ public double playerCarryStrength = 2;
+ public double headJumpStrength = 5;
+ public double headNodStep = 20;
+ public double jumpStrength = 20;
+ public double groundFriction = 0.5;
+ public double airFriction = 0.1;
+
+ public String setByString(String key, String valueStr) {
+
+ try {
+ Field field = this.getClass().getDeclaredField(key);
+ Type type = field.getAnnotatedType().getType();
+ Object value;
+
+ if (type.equals(double.class)) {
+ value = Double.valueOf(valueStr);
+ } else {
+ return "This property is not changeable because I can't yet handle type " + type.getTypeName();
+ }
+
+ field.setAccessible(true);
+ field.set(this, value);
+
+ return field.getName() + " is now " + value.toString();
+ } catch (NumberFormatException e) {
+ return "Not a decimal number: " + valueStr;
+ } catch (NoSuchFieldException e) {
+ return "Invalid key: " + key;
+ } catch (IllegalArgumentException e) {
+ return "Invalid value: " + valueStr;
+ } catch (IllegalAccessException e) {
+ return "This property is not changeable";
+ }
+ }
+}
diff --git a/src/main/java/net/pivipi/game/Stadium.java b/src/main/java/net/pivipi/game/Stadium.java
new file mode 100644
index 0000000..4059236
--- /dev/null
+++ b/src/main/java/net/pivipi/game/Stadium.java
@@ -0,0 +1,42 @@
+package net.pivipi.game;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import net.minestom.server.coordinate.Vec;
+import net.minestom.server.entity.Player;
+import net.minestom.server.instance.Instance;
+import net.pivipi.ball.Ball;
+
+public class Stadium {
+ public final Set players = new HashSet();
+ public Ball ball; // TODO public?
+
+ /**
+ * the instance where this stadium is
+ */
+ public final Instance instance;
+
+ /**
+ * the lower corner pos
+ */
+ public final Vec pos;
+
+ /**
+ * the stadium size
+ */
+ public final Vec size;
+
+ /**
+ * the max corner pos that is pos + size
+ */
+ public final Vec max;
+
+
+ public Stadium(Instance instance, Vec pos, Vec size) {
+ this.instance = instance;
+ this.pos = pos;
+ this.size = size;
+ this.max = pos.add(size);
+ }
+}
diff --git a/src/main/java/net/pivipi/physics/Physics.java b/src/main/java/net/pivipi/physics/Physics.java
index 98a7f14..07900aa 100644
--- a/src/main/java/net/pivipi/physics/Physics.java
+++ b/src/main/java/net/pivipi/physics/Physics.java
@@ -9,27 +9,18 @@ import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.server.play.ParticlePacket;
import net.minestom.server.particle.Particle;
+import net.pivipi.game.PhysicsSettings;
public class Physics {
- private final double gravity = 9.8;
- 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 playerSneakingBodyBounciness = 0;
- private final double playerCarryStrength = 2;
- private final double headJumpStrength = 5;
- private final double headNodStep = 20;
- private final double jumpStrength = 20;
- private final double groundFriction = 0.5;
- private final double airFriction = 0.1;
- private final int groundY = 64;
+ private PhysicsSettings settings;
private final double flame = 20; // flame starts at speed
private final double flameFreq = 100; // ms per flame
private final double flameIncrement = 0.5; // ms per flame decrement per speed unit
private final float flameSpread = 0.2f;
+ private final int groundY = 64; // this should be removed when block collisions
+
private Vec velocity = new Vec(0, 0, 0);
private final Entity entity;
@@ -59,12 +50,12 @@ public class Physics {
}
private Vec applyPhysics(double delta, Set players) {
- velocity = velocity.sub(0, gravity * delta, 0).mul(1 - (airFriction * delta), 1, 1 - (airFriction * delta));
+ velocity = velocity.sub(0, settings.gravity * delta, 0).mul(1 - (settings.airFriction * delta), 1, 1 - (settings.airFriction * delta));
ArrayList collisions = new ArrayList<>();
if (Collision.collidesWithGround(groundY, entity)) {
entity.teleport(entity.getPosition().withY(groundY));
- velocity = velocity.mul(1 - (groundFriction * delta), -blockBounciness, 1 - (groundFriction * delta));
+ velocity = velocity.mul(1 - (settings.groundFriction * delta), -settings.blockBounciness, 1 - (settings.groundFriction * delta));
} else {
for (Player player : players) {
CollisionData collisionData = new CollisionData();
@@ -103,17 +94,17 @@ public class Physics {
if (movementPos.y() > 0) {
double headPitchDiff = Math.abs(movementPos.pitch());
System.out.println(headPitchDiff);
- addVelocity(player.getPosition().direction().mul(headPitchDiff / headNodStep).withY(headJumpStrength));
- } else velocity = velocity.mul(1, player.isSneaking() ? -playerSneakingHeadBounciness : -playerHeadBounciness, 1);
+ addVelocity(player.getPosition().direction().mul(headPitchDiff / settings.headNodStep).withY(settings.headJumpStrength));
+ } else velocity = velocity.mul(1, player.isSneaking() ? -settings.playerSneakingHeadBounciness : -settings.playerHeadBounciness, 1);
entity.teleport(entity.getPosition().withY(y -> y + headOffsetY));
} else {
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() ? -settings.playerSneakingBodyBounciness : -settings.playerBodyBounciness;
velocity = velocity
- .withX(x -> oppositeX ? x * bodyBounciness : x + movementPos.x() * playerCarryStrength)
- .withY(y -> collisionData.distance.y() < 1.0 ? movementPos.y() * jumpStrength : y) // magic value legs
- .withZ(z -> oppositeZ ? z * bodyBounciness : z + movementPos.z() * playerCarryStrength);
+ .withX(x -> oppositeX ? x * bodyBounciness : x + movementPos.x() * settings.playerCarryStrength)
+ .withY(y -> collisionData.distance.y() < 1.0 ? movementPos.y() * settings.jumpStrength : y) // magic value legs
+ .withZ(z -> oppositeZ ? z * bodyBounciness : z + movementPos.z() * settings.playerCarryStrength);
}
}
diff --git a/src/main/java/net/pivipi/world/Stadium.java b/src/main/java/net/pivipi/world/Stadium.java
deleted file mode 100644
index 0e13d32..0000000
--- a/src/main/java/net/pivipi/world/Stadium.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package net.pivipi.world;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import net.minestom.server.entity.Player;
-import net.pivipi.ball.Ball;
-
-public class Stadium {
- public final Set players = new HashSet();
- public Ball ball;
-}