diff --git a/src/main/java/de/bixilon/minosoft/terminal/commands/Commands.kt b/src/main/java/de/bixilon/minosoft/terminal/commands/Commands.kt
index a4607f707..4f7213d2c 100644
--- a/src/main/java/de/bixilon/minosoft/terminal/commands/Commands.kt
+++ b/src/main/java/de/bixilon/minosoft/terminal/commands/Commands.kt
@@ -32,7 +32,7 @@ object Commands {
SayCommand,
ActionCommand, QueryCommand,
- DebugCommand,
+ DebugCommand, BenchmarkCommand,
DisconnectCommand,
)
}
diff --git a/src/main/java/de/bixilon/minosoft/terminal/commands/connection/BenchmarkCommand.kt b/src/main/java/de/bixilon/minosoft/terminal/commands/connection/BenchmarkCommand.kt
new file mode 100644
index 000000000..6afa44d01
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/terminal/commands/connection/BenchmarkCommand.kt
@@ -0,0 +1,76 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2023 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.terminal.commands.connection
+
+import de.bixilon.kotlinglm.GLM.PIf
+import de.bixilon.kotlinglm.vec3.Vec3d
+import de.bixilon.kutil.random.RandomUtil.nextDouble
+import de.bixilon.kutil.random.RandomUtil.nextFloat
+import de.bixilon.kutil.random.RandomUtil.nextInt
+import de.bixilon.kutil.time.TimeUtil.millis
+import de.bixilon.minosoft.commands.nodes.ArgumentNode
+import de.bixilon.minosoft.commands.nodes.LiteralNode
+import de.bixilon.minosoft.commands.parser.brigadier._int.IntParser
+import de.bixilon.minosoft.commands.stack.CommandStack
+import de.bixilon.minosoft.data.entities.EntityRotation
+import de.bixilon.minosoft.data.entities.data.EntityData
+import de.bixilon.minosoft.data.entities.entities.Entity
+import de.bixilon.minosoft.data.entities.entities.player.RemotePlayerEntity
+import de.bixilon.minosoft.data.entities.entities.player.additional.PlayerAdditional
+import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
+import de.bixilon.minosoft.util.KUtil.startInit
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
+import java.util.*
+import kotlin.math.cbrt
+import kotlin.math.sin
+
+object BenchmarkCommand : ConnectionCommand {
+ override var node = LiteralNode("benchmark").addChild(
+ LiteralNode("players", executor = { benchmarkPlayers(it) }).addChild(ArgumentNode("count", parser = IntParser(min = 0, max = 100000), executable = true)),
+ )
+
+
+ private fun benchmark(connection: PlayConnection, count: Int, factory: (position: Vec3d, rotation: EntityRotation, id: Int) -> Entity) {
+ val offset = connection.player.physics.position
+ val random = Random()
+
+ val entities: MutableList = ArrayList(count)
+ val spread = minOf(cbrt(count.toDouble()), 5.0)
+ for (id in 0 until count) {
+ val position = offset + Vec3d(random.nextDouble(-spread, spread), random.nextDouble(-spread, spread), random.nextDouble(-spread, spread))
+ val rotation = EntityRotation(random.nextFloat(-179.0f, 179.0f), random.nextFloat(-89.0f, 89.0f))
+ val entity = factory.invoke(position, rotation, id)
+ entity.startInit()
+ entities += entity
+ connection.world.entities.add(random.nextInt(100000, 200000), null, entity)
+ // TODO: make them move randomly?
+ }
+
+ connection.ticker += {
+ val time = (millis() % 1000L) / 1000.0f * PIf * 2
+ val delta = Vec3d(sin(time))
+
+ for (entity in entities) {
+ entity.forceMove(delta)
+ }
+ }
+ }
+
+ private fun benchmarkPlayers(stack: CommandStack) {
+ val count = stack.get("count") ?: 100
+ val type = stack.connection.registries.entityType[RemotePlayerEntity] ?: return
+
+ benchmark(stack.connection, count) { position, rotation, id -> RemotePlayerEntity(stack.connection, type, EntityData(stack.connection, Int2ObjectOpenHashMap()), position, rotation, PlayerAdditional("Dummy $id")) }
+ }
+}