From 04c31297179487ac728e97df5e7108a316516838 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Sat, 12 Nov 2022 20:15:02 +0100 Subject: [PATCH] Initial commit --- .../pixlyzer/physics/PhysicsExtractor.kt | 48 ++++++++ .../bixilon/pixlyzer/physics/PhysicsUtil.kt | 110 ++++++++++++++++++ .../physics/abstractions/MinecraftPlayer.kt | 45 +++++++ .../physics/abstractions/MinecraftWorld.kt | 13 +++ .../pixlyzer/physics/tests/AbstractTest.kt | 25 ++++ .../pixlyzer/physics/tests/EmptyTest.kt | 19 +++ .../pixlyzer/physics/tests/GravityTest.kt | 96 +++++++++++++++ .../pixlyzer/physics/tests/PhysicsTest.kt | 3 + .../physics/tests/packet/PacketReceiveTest.kt | 58 +++++++++ 9 files changed, 417 insertions(+) create mode 100644 src/main/kotlin/de/bixilon/pixlyzer/physics/PhysicsExtractor.kt create mode 100644 src/main/kotlin/de/bixilon/pixlyzer/physics/PhysicsUtil.kt create mode 100644 src/main/kotlin/de/bixilon/pixlyzer/physics/abstractions/MinecraftPlayer.kt create mode 100644 src/main/kotlin/de/bixilon/pixlyzer/physics/abstractions/MinecraftWorld.kt create mode 100644 src/main/kotlin/de/bixilon/pixlyzer/physics/tests/AbstractTest.kt create mode 100644 src/main/kotlin/de/bixilon/pixlyzer/physics/tests/EmptyTest.kt create mode 100644 src/main/kotlin/de/bixilon/pixlyzer/physics/tests/GravityTest.kt create mode 100644 src/main/kotlin/de/bixilon/pixlyzer/physics/tests/PhysicsTest.kt create mode 100644 src/main/kotlin/de/bixilon/pixlyzer/physics/tests/packet/PacketReceiveTest.kt diff --git a/src/main/kotlin/de/bixilon/pixlyzer/physics/PhysicsExtractor.kt b/src/main/kotlin/de/bixilon/pixlyzer/physics/PhysicsExtractor.kt new file mode 100644 index 0000000..6713cfb --- /dev/null +++ b/src/main/kotlin/de/bixilon/pixlyzer/physics/PhysicsExtractor.kt @@ -0,0 +1,48 @@ +package de.bixilon.pixlyzer.physics + +import de.bixilon.pixlyzer.physics.tests.AbstractTest +import de.bixilon.pixlyzer.physics.tests.EmptyTest +import de.bixilon.pixlyzer.physics.tests.GravityTest +import de.bixilon.pixlyzer.physics.tests.PhysicsTest +import de.bixilon.pixlyzer.physics.tests.packet.PacketReceiveTest +import java.lang.reflect.Method + +object PhysicsExtractor { + val tests = listOf>( + EmptyTest::class.java, + PacketReceiveTest::class.java, + GravityTest::class.java, + ) + + + fun prepare(clazz: AbstractTest) { + clazz.result = mutableMapOf() + clazz.world = clazz.createWorld() + clazz.player = clazz.createPlayer(clazz.world) + } + + fun run(method: Method, clazz: AbstractTest) { + prepare(clazz) + method.invoke(clazz) + println("Result: ${method.name}: ${clazz.result}") + } + + + fun start() { + for (tests in tests) { + val instance = tests.getConstructor().newInstance() + + for (method in tests.declaredMethods) { + method.isAccessible = true + if (!method.isAnnotationPresent(PhysicsTest::class.java)) { + continue + } + try { + run(method, instance) + } catch (error: Throwable) { + error.printStackTrace() + } + } + } + } +} diff --git a/src/main/kotlin/de/bixilon/pixlyzer/physics/PhysicsUtil.kt b/src/main/kotlin/de/bixilon/pixlyzer/physics/PhysicsUtil.kt new file mode 100644 index 0000000..e51dcea --- /dev/null +++ b/src/main/kotlin/de/bixilon/pixlyzer/physics/PhysicsUtil.kt @@ -0,0 +1,110 @@ +package de.bixilon.pixlyzer.physics + +import com.google.common.collect.Queues +import com.mojang.authlib.GameProfile +import de.bixilon.pixlyzer.EntitySpawner.setDimension +import de.bixilon.pixlyzer.physics.abstractions.MinecraftPlayer +import de.bixilon.pixlyzer.physics.abstractions.MinecraftWorld +import net.minecraft.client.MinecraftClient +import net.minecraft.client.input.Input +import net.minecraft.client.network.ClientPlayNetworkHandler +import net.minecraft.client.network.ClientPlayerEntity +import net.minecraft.client.network.PlayerListEntry +import net.minecraft.client.option.GameOptions +import net.minecraft.client.option.SimpleOption +import net.minecraft.client.recipebook.ClientRecipeBook +import net.minecraft.client.tutorial.TutorialManager +import net.minecraft.client.world.ClientChunkManager +import net.minecraft.client.world.ClientEntityManager +import net.minecraft.client.world.ClientWorld +import net.minecraft.entity.Entity +import net.minecraft.network.ClientConnection +import net.minecraft.network.NetworkSide +import net.minecraft.scoreboard.Scoreboard +import net.minecraft.stat.StatHandler +import net.minecraft.util.math.BlockPos +import net.minecraft.util.profiler.DummyProfiler +import net.minecraft.util.registry.RegistryEntry +import net.minecraft.world.Difficulty +import net.minecraft.world.biome.Biome +import net.minecraft.world.biome.source.BiomeAccess +import net.minecraft.world.border.WorldBorder +import net.minecraft.world.dimension.DimensionType +import org.objenesis.ObjenesisStd +import java.util.* +import java.util.function.Supplier + +object PhysicsUtil { + private val OBJENESIS = ObjenesisStd() + + fun createChunkManager(native: ClientWorld): ClientChunkManager { + val chunkManager = OBJENESIS.newInstance(ClientChunkManager::class.java) + chunkManager.world = native + chunkManager.chunks = chunkManager.ClientChunkMap(ClientChunkManager.getChunkMapRadius(3)) + + + return chunkManager + } + + fun createWorld(): MinecraftWorld { + val native = OBJENESIS.newInstance(ClientWorld::class.java) + native.chunkManager = createChunkManager(native) + + val properties = ClientWorld.Properties(Difficulty.EASY, false, false) + native.properties = properties + native.clientWorldProperties = ClientWorld.Properties(properties.difficulty, properties.isHardcore, properties.flatWorld) + native.setSpawnPos(BlockPos(0, 0, 0), 0.0f) + + native.scoreboard = Scoreboard() + native.border = WorldBorder() + native.profiler = Supplier { DummyProfiler.INSTANCE } + native.setDimension() + native.entityManager = ClientEntityManager(Entity::class.java, native.ClientEntityHandler()) + + native.biomeAccess = BiomeAccess(BiomeAccess.Storage { biomeX, biomeY, biomeZ -> return@Storage RegistryEntry.Direct(null) }, 0L) + + return MinecraftWorld(native) + } + + private fun createNetworkHandler(client: MinecraftClient): ClientPlayNetworkHandler { + val handler = OBJENESIS.newInstance(ClientPlayNetworkHandler::class.java) + handler.profile = GameProfile(UUID(1L, 1L), "physics") + handler.client = client + handler.connection = ClientConnection(NetworkSide.CLIENTBOUND) + return handler + } + + private fun createGameOptions(): GameOptions? { + val options = OBJENESIS.newInstance(GameOptions::class.java) + options.autoJump = SimpleOption.ofBoolean("", false) + + return options + } + + private fun createMinecraftClient(): MinecraftClient { + val client = OBJENESIS.newInstance(MinecraftClient::class.java) + + client.tasks = Queues.newConcurrentLinkedQueue() + client.thread = Thread.currentThread() + client.options = createGameOptions() + client.tutorialManager = TutorialManager(client, client.options ) + + return client + } + + fun createPlayer(world: MinecraftWorld): MinecraftPlayer { + val client = createMinecraftClient() + val networkHandler = createNetworkHandler(client) + val native = ClientPlayerEntity(client, world.level, networkHandler, StatHandler(), ClientRecipeBook(), false, false) + + client.player = native + native.playerListEntry = PlayerListEntry(networkHandler.profile, false) + native.input = Input() + native.shoulderEntityLeft = null + native.shoulderEntityRight = null + + client.cameraEntity = native + + return MinecraftPlayer(native) + } +} diff --git a/src/main/kotlin/de/bixilon/pixlyzer/physics/abstractions/MinecraftPlayer.kt b/src/main/kotlin/de/bixilon/pixlyzer/physics/abstractions/MinecraftPlayer.kt new file mode 100644 index 0000000..e1647cc --- /dev/null +++ b/src/main/kotlin/de/bixilon/pixlyzer/physics/abstractions/MinecraftPlayer.kt @@ -0,0 +1,45 @@ +package de.bixilon.pixlyzer.physics.abstractions + +import net.minecraft.client.input.Input +import net.minecraft.client.network.ClientPlayerEntity +import net.minecraft.network.Packet +import net.minecraft.network.listener.ClientPlayPacketListener +import net.minecraft.util.math.Vec3d + +class MinecraftPlayer( + val native: ClientPlayerEntity, +) { + + fun handlePacket(packet: Packet) { + packet.apply(native.networkHandler) + } + + fun tick(count:Int=1) { + for(i in 0 until count) { + native.tick() + } + } + + fun teleport(x: Double, y: Double, z: Double) { + native.setPosition(Vec3d(x, y, z)) + } + + fun setKeys( + forwards: Boolean = false, + backwards: Boolean = false, + right: Boolean = false, + left: Boolean = false, + jump: Boolean = false, + sneak: Boolean = false, + ) { + val input = Input() + input.pressingForward = forwards + input.pressingBack = backwards + input.pressingRight = right + input.pressingLeft = left + input.jumping = jump + input.sneaking = sneak + + native.input = input + } +} diff --git a/src/main/kotlin/de/bixilon/pixlyzer/physics/abstractions/MinecraftWorld.kt b/src/main/kotlin/de/bixilon/pixlyzer/physics/abstractions/MinecraftWorld.kt new file mode 100644 index 0000000..5ad8ae2 --- /dev/null +++ b/src/main/kotlin/de/bixilon/pixlyzer/physics/abstractions/MinecraftWorld.kt @@ -0,0 +1,13 @@ +package de.bixilon.pixlyzer.physics.abstractions + +import net.minecraft.block.BlockState +import net.minecraft.client.world.ClientWorld +import net.minecraft.util.math.BlockPos + +class MinecraftWorld( + val level: ClientWorld, +) { + fun set(x: Int, y: Int, z: Int, value: BlockState?) { + level.setBlockState(BlockPos(x, y, z), value) + } +} diff --git a/src/main/kotlin/de/bixilon/pixlyzer/physics/tests/AbstractTest.kt b/src/main/kotlin/de/bixilon/pixlyzer/physics/tests/AbstractTest.kt new file mode 100644 index 0000000..393c66f --- /dev/null +++ b/src/main/kotlin/de/bixilon/pixlyzer/physics/tests/AbstractTest.kt @@ -0,0 +1,25 @@ +package de.bixilon.pixlyzer.physics.tests + +import de.bixilon.kutil.cast.CastUtil.unsafeNull +import de.bixilon.pixlyzer.physics.PhysicsUtil +import de.bixilon.pixlyzer.physics.abstractions.MinecraftPlayer +import de.bixilon.pixlyzer.physics.abstractions.MinecraftWorld + +abstract class AbstractTest { + open val skip: Boolean = false + var world: MinecraftWorld = unsafeNull() + var player: MinecraftPlayer = unsafeNull() + var result: MutableMap = mutableMapOf() + + open fun createWorld(): MinecraftWorld = PhysicsUtil.createWorld() + open fun createPlayer(world: MinecraftWorld): MinecraftPlayer = PhysicsUtil.createPlayer(world) + + + protected fun storeBasic() { + result["x"] = player.native.x + result["y"] = player.native.y + result["z"] = player.native.z + result["yaw"] = player.native.yaw + result["pitch"] = player.native.pitch + } +} diff --git a/src/main/kotlin/de/bixilon/pixlyzer/physics/tests/EmptyTest.kt b/src/main/kotlin/de/bixilon/pixlyzer/physics/tests/EmptyTest.kt new file mode 100644 index 0000000..4f379f9 --- /dev/null +++ b/src/main/kotlin/de/bixilon/pixlyzer/physics/tests/EmptyTest.kt @@ -0,0 +1,19 @@ +package de.bixilon.pixlyzer.physics.tests + +class EmptyTest : AbstractTest() { + + @PhysicsTest("initial_position") + fun testInitialPosition() { + result["x"] = player.native.x + result["y"] = player.native.y + result["z"] = player.native.z + } + + @PhysicsTest("empty_teleport") + fun testTeleporting() { + player.teleport(123.0, 535.0, 19.0) + result["x"] = player.native.x + result["y"] = player.native.y + result["z"] = player.native.z + } +} diff --git a/src/main/kotlin/de/bixilon/pixlyzer/physics/tests/GravityTest.kt b/src/main/kotlin/de/bixilon/pixlyzer/physics/tests/GravityTest.kt new file mode 100644 index 0000000..b6a69f1 --- /dev/null +++ b/src/main/kotlin/de/bixilon/pixlyzer/physics/tests/GravityTest.kt @@ -0,0 +1,96 @@ +package de.bixilon.pixlyzer.physics.tests + +class GravityTest : AbstractTest() { + + @PhysicsTest("blank_falling_1") + fun blankFalling1() { + player.teleport(45.00, 178.0, 13.00) + player.tick() + storeBasic() + } + + @PhysicsTest("blank_falling_2") + fun blankFalling2() { + player.teleport(45.00, 178.0, 13.00) + player.tick(2) + storeBasic() + } + + @PhysicsTest("blank_falling_3") + fun blankFalling3() { + player.teleport(45.00, 178.0, 13.00) + player.tick(3) + storeBasic() + } + + @PhysicsTest("blank_falling_90") + fun blankFalling90() { + player.teleport(45.00, 178.0, 13.00) + player.tick(90) + storeBasic() + } + + @PhysicsTest("forwards_falling_1") + fun forwardFalling1() { + player.teleport(45.00, 178.0, 13.00) + player.setKeys(forwards = true) + player.tick() + storeBasic() + } + + @PhysicsTest("forwards_falling_2") + fun forwardFalling2() { + player.teleport(45.00, 178.0, 13.00) + player.setKeys(forwards = true) + player.tick(2) + storeBasic() + } + + @PhysicsTest("forwards_falling_2") + fun forwardFalling3() { + player.teleport(45.00, 178.0, 13.00) + player.setKeys(forwards = true) + player.tick(3) + storeBasic() + } + + @PhysicsTest("forwards_falling_90") + fun forwardFalling90() { + player.teleport(45.00, 178.0, 13.00) + player.setKeys(forwards = true) + player.tick(90) + storeBasic() + } + + @PhysicsTest("backwards_falling_1") + fun backwardsFalling1() { + player.teleport(45.00, 178.0, 13.00) + player.setKeys(backwards = true) + player.tick() + storeBasic() + } + + @PhysicsTest("backwards_falling_2") + fun backwardsFalling2() { + player.teleport(45.00, 178.0, 13.00) + player.setKeys(backwards = true) + player.tick(2) + storeBasic() + } + + @PhysicsTest("backwards_falling_2") + fun backwardsFalling3() { + player.teleport(45.00, 178.0, 13.00) + player.setKeys(backwards = true) + player.tick(3) + storeBasic() + } + + @PhysicsTest("backwards_falling_90") + fun backwardsFalling90() { + player.teleport(45.00, 178.0, 13.00) + player.setKeys(backwards = true) + player.tick(90) + storeBasic() + } +} diff --git a/src/main/kotlin/de/bixilon/pixlyzer/physics/tests/PhysicsTest.kt b/src/main/kotlin/de/bixilon/pixlyzer/physics/tests/PhysicsTest.kt new file mode 100644 index 0000000..a049abf --- /dev/null +++ b/src/main/kotlin/de/bixilon/pixlyzer/physics/tests/PhysicsTest.kt @@ -0,0 +1,3 @@ +package de.bixilon.pixlyzer.physics.tests + +annotation class PhysicsTest(val id: String) diff --git a/src/main/kotlin/de/bixilon/pixlyzer/physics/tests/packet/PacketReceiveTest.kt b/src/main/kotlin/de/bixilon/pixlyzer/physics/tests/packet/PacketReceiveTest.kt new file mode 100644 index 0000000..2a96986 --- /dev/null +++ b/src/main/kotlin/de/bixilon/pixlyzer/physics/tests/packet/PacketReceiveTest.kt @@ -0,0 +1,58 @@ +package de.bixilon.pixlyzer.physics.tests.packet + +import de.bixilon.pixlyzer.physics.tests.AbstractTest +import de.bixilon.pixlyzer.physics.tests.PhysicsTest +import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket +import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket.Flag + +class PacketReceiveTest : AbstractTest() { + + private fun createPacket(x: Double, xRelative: Boolean, y: Double, yRelative: Boolean, z: Double, zRelative: Boolean, yaw: Float, yawRelative: Boolean, pitch: Float, pitchRelative: Boolean, dismount: Boolean): PlayerPositionLookS2CPacket { + val flags: MutableSet = mutableSetOf() + if (xRelative) { + flags += Flag.X + } + if (yRelative) { + flags += Flag.Y + } + if (zRelative) { + flags += Flag.Z + } + if (yawRelative) { + flags += Flag.Y_ROT + } + if (pitchRelative) { + flags += Flag.X_ROT + } + + return PlayerPositionLookS2CPacket(x, y, z, yaw, pitch, flags, 0, dismount) + } + + @PhysicsTest("receive_empty") + fun testEmpty() { + val packet = createPacket(0.0, true, 0.0, true, 0.0, true, 0.0f, true, 0.0f, true, false) + player.handlePacket(packet) + storeBasic() + result["mount"] = player.native.jumpingMount != null + } + + @PhysicsTest("receive_relative") + fun testRelative() { + player.teleport(623.0, 71.0, 782.0) + val packet = createPacket(14.0, true, 87.0, true, 91.0, true, 9.0f, true, 92.0f, true, false) + + player.handlePacket(packet) + storeBasic() + result["mount"] = player.native.jumpingMount != null + } + + @PhysicsTest("receive_absolute") + fun testAbsolut() { + player.teleport(623.0, 71.0, 782.0) + val packet = createPacket(14.0, false, 87.0, false, 91.0, false, 9.0f, false, 92.0f, false, false) + + player.handlePacket(packet) + storeBasic() + result["mount"] = player.native.jumpingMount != null + } +}