diff --git a/build.gradle.kts b/build.gradle.kts index 21c096c80..cd2c8b8d9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -220,7 +220,7 @@ testing { options { val options = this as TestNGOptions options.preserveOrder = true - options.excludeGroups("version", "fluid", "world", "raycasting", "pixlyzer", "item", "block", "physics", "light", "packet", "container", "item_stack", "signature", "private_key", "interaction", "item_digging", "world_renderer", "rendering") + options.excludeGroups("command", "registry", "biome", "input", "version", "fluid", "world", "raycasting", "pixlyzer", "item", "block", "physics", "light", "packet", "container", "item_stack", "signature", "private_key", "interaction", "item_digging", "world_renderer", "rendering") } } } diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/baked/CuboidBakeTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/baked/CuboidBakeTest.kt index c9964af16..72906e798 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/baked/CuboidBakeTest.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/baked/CuboidBakeTest.kt @@ -42,12 +42,13 @@ class CuboidBakeTest { fun cuboidY90() { val from = Vec3(1, 2, 3) / BLOCK_SIZE val to = Vec3(16, 15, 14) / BLOCK_SIZE - val model = SingleBlockStateApply(BlockModel(elements = listOf(ModelElement(from, to, faces = createFaces(from, to))), textures = mapOf("test" to minecraft("block/test").texture())), y = 90) + val model = SingleBlockStateApply(BlockModel(elements = listOf(ModelElement(from, to, faces = createFaces(from, to))), textures = mapOf("test" to minecraft("block/test").texture())), y = 1) val baked = model.bake(createTextureManager("block/test"))!! baked.assertFace(Directions.DOWN, block(2, 2, 1, 2, 2, 16, 13, 2, 16, 13, 2, 1), block(1, 14, 16, 14, 16, 3, 1, 3), 0.5f) baked.assertFace(Directions.UP, block(2, 15, 1, 13, 15, 1, 13, 15, 16, 2, 15, 16), block(1, 2, 1, 13, 16, 13, 16, 2), 1.0f) + // TODO: other sides } } diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/baked/FullCubeBakeTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/baked/FullCubeBakeTest.kt index c9928eab9..af80d697e 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/baked/FullCubeBakeTest.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/baked/FullCubeBakeTest.kt @@ -49,7 +49,7 @@ class FullCubeBakeTest { fun fullCubeY90() { val from = Vec3(0.0f) val to = Vec3(1.0f) - val model = SingleBlockStateApply(BlockModel(elements = listOf(ModelElement(from, to, faces = createFaces())), textures = mapOf("test" to minecraft("block/test").texture())), y = 90) + val model = SingleBlockStateApply(BlockModel(elements = listOf(ModelElement(from, to, faces = createFaces())), textures = mapOf("test" to minecraft("block/test").texture())), y = 1) val baked = model.bake(createTextureManager("block/test"))!! @@ -66,7 +66,7 @@ class FullCubeBakeTest { fun fullCubeX90() { val from = Vec3(0.0f) val to = Vec3(1.0f) - val model = SingleBlockStateApply(BlockModel(elements = listOf(ModelElement(from, to, faces = createFaces())), textures = mapOf("test" to minecraft("block/test").texture())), x = 90) + val model = SingleBlockStateApply(BlockModel(elements = listOf(ModelElement(from, to, faces = createFaces())), textures = mapOf("test" to minecraft("block/test").texture())), x = 1) val baked = model.bake(createTextureManager("block/test"))!! @@ -82,7 +82,7 @@ class FullCubeBakeTest { fun fullCubeX90Y90() { val from = Vec3(0.0f) val to = Vec3(1.0f) - val model = SingleBlockStateApply(BlockModel(elements = listOf(ModelElement(from, to, faces = createFaces())), textures = mapOf("test" to minecraft("block/test").texture())), x = 90, y = 90) + val model = SingleBlockStateApply(BlockModel(elements = listOf(ModelElement(from, to, faces = createFaces())), textures = mapOf("test" to minecraft("block/test").texture())), x = 1, y = 1) val baked = model.bake(createTextureManager("block/test"))!! diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/input/interaction/InteractionManagerTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/input/interaction/InteractionManagerTest.kt index 948f81e14..9ce55f80c 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/input/interaction/InteractionManagerTest.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/input/interaction/InteractionManagerTest.kt @@ -26,7 +26,7 @@ import de.bixilon.minosoft.protocol.packets.c2s.play.entity.interact.EntityAttac import de.bixilon.minosoft.protocol.packets.c2s.play.move.SwingArmC2SP import org.testng.annotations.Test -@Test(groups = ["integration"]) +@Test(groups = ["interaction"]) class InteractionManagerTest { fun attackNoTarget() { diff --git a/src/main/java/de/bixilon/minosoft/data/direction/DirectionUtil.kt b/src/main/java/de/bixilon/minosoft/data/direction/DirectionUtil.kt index 0f5d35062..eb4e58549 100644 --- a/src/main/java/de/bixilon/minosoft/data/direction/DirectionUtil.kt +++ b/src/main/java/de/bixilon/minosoft/data/direction/DirectionUtil.kt @@ -16,9 +16,20 @@ package de.bixilon.minosoft.data.direction import de.bixilon.kotlinglm.func.rad import de.bixilon.kotlinglm.mat4x4.Mat4 import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.kutil.array.ArrayUtil +import de.bixilon.minosoft.data.Axes object DirectionUtil { + fun Directions.rotateY(count: Int = 1): Directions { + if (count == 0) return this + if (axis == Axes.Y) return this + var count = count % Directions.SIZE_SIDES + if (count < 0) count += Directions.SIZE_SIDES + + return Directions.HORIZONTAL[ArrayUtil.modifyArrayIndex((horizontalId - Directions.SIDE_OFFSET) + count, Directions.SIZE_SIDES)] + } + fun rotateMatrix(direction: Directions): Mat4 { return when (direction) { Directions.DOWN -> Mat4().translateAssign(Vec3(0.5f)).rotateAssign(180.0f.rad, Vec3(1, 0, 0)).translateAssign(Vec3(-0.5f)) diff --git a/src/main/java/de/bixilon/minosoft/data/direction/Directions.kt b/src/main/java/de/bixilon/minosoft/data/direction/Directions.kt index 23cf8ed28..6e7241eae 100644 --- a/src/main/java/de/bixilon/minosoft/data/direction/Directions.kt +++ b/src/main/java/de/bixilon/minosoft/data/direction/Directions.kt @@ -20,7 +20,6 @@ import de.bixilon.kutil.cast.CastUtil.unsafeCast import de.bixilon.kutil.cast.CastUtil.unsafeNull import de.bixilon.kutil.enums.EnumUtil import de.bixilon.kutil.enums.ValuesEnum -import de.bixilon.kutil.exception.Broken import de.bixilon.kutil.reflection.ReflectionUtil.forceSet import de.bixilon.minosoft.data.Axes import de.bixilon.minosoft.data.registries.blocks.properties.serializer.BlockPropertiesSerializer @@ -33,13 +32,14 @@ import kotlin.reflect.jvm.javaField enum class Directions( @Deprecated("remove") val horizontalId: Int, val vector: Vec3i, + val horizontal: Int, ) { - DOWN(-1, Vec3i(0, -1, 0)), - UP(-1, Vec3i(0, 1, 0)), - NORTH(2, Vec3i(0, 0, -1)), - SOUTH(0, Vec3i(0, 0, 1)), - WEST(1, Vec3i(-1, 0, 0)), - EAST(3, Vec3i(1, 0, 0)); + DOWN(-1, Vec3i(0, -1, 0), -1), + UP(-1, Vec3i(0, 1, 0), -1), + NORTH(2, Vec3i(0, 0, -1), 0), + SOUTH(0, Vec3i(0, 0, 1), 2), + WEST(1, Vec3i(-1, 0, 0), 3), + EAST(3, Vec3i(1, 0, 0), 1); val negative = ordinal % 2 == 0 @@ -63,15 +63,6 @@ enum class Directions( return vector[axis] } - fun rotateYC(): Directions { - return when (this) { - NORTH -> EAST - SOUTH -> WEST - WEST -> NORTH - EAST -> SOUTH - else -> Broken("Rotation: $this") - } - } @Deprecated("outsource") fun getPositions(from: Vec3, to: Vec3): Array { @@ -153,6 +144,7 @@ enum class Directions( override val VALUES = values() override val NAME_MAP: Map = EnumUtil.getEnumValues(VALUES) val SIDES = arrayOf(NORTH, SOUTH, WEST, EAST) + val HORIZONTAL = arrayOf(NORTH, EAST, SOUTH, WEST) val XYZ = arrayOf(WEST, EAST, DOWN, UP, NORTH, SOUTH) diff --git a/src/main/java/de/bixilon/minosoft/data/entities/block/CampfireBlockEntity.kt b/src/main/java/de/bixilon/minosoft/data/entities/block/CampfireBlockEntity.kt index ccb2a726f..aea26a43e 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/block/CampfireBlockEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/block/CampfireBlockEntity.kt @@ -20,6 +20,7 @@ import de.bixilon.kutil.primitive.IntUtil.toInt import de.bixilon.kutil.random.RandomUtil.chance import de.bixilon.minosoft.data.container.ItemStackUtil import de.bixilon.minosoft.data.container.stack.ItemStack +import de.bixilon.minosoft.data.direction.DirectionUtil.rotateY import de.bixilon.minosoft.data.direction.Directions import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties.Companion.getFacing import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties.Companion.isLit @@ -82,9 +83,9 @@ class CampfireBlockEntity(connection: PlayConnection) : BlockEntity(connection) val direction = HORIZONTAL[Math.floorMod(index + facing, Directions.SIDES.size)] val position = Vec3d(blockPosition) + Vec3d( - 0.5f - direction.vector.x * DIRECTION_OFFSET + direction.rotateYC().vector.x * DIRECTION_OFFSET, + 0.5f - direction.vector.x * DIRECTION_OFFSET + direction.rotateY().vector.x * DIRECTION_OFFSET, 0.5f, - 0.5f - direction.vector.z * DIRECTION_OFFSET + direction.rotateYC().vector.z * DIRECTION_OFFSET, + 0.5f - direction.vector.z * DIRECTION_OFFSET + direction.rotateY().vector.z * DIRECTION_OFFSET, ) for (i in 0 until 4) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/element/face/FaceUV.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/element/face/FaceUV.kt index 1396b48e1..aa81706ad 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/element/face/FaceUV.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/element/face/FaceUV.kt @@ -14,6 +14,7 @@ package de.bixilon.minosoft.gui.rendering.models.block.element.face import de.bixilon.kotlinglm.vec2.Vec2 +import de.bixilon.minosoft.data.direction.Directions import de.bixilon.minosoft.gui.rendering.models.block.element.ModelElement.Companion.BLOCK_SIZE data class FaceUV( @@ -22,4 +23,18 @@ data class FaceUV( ) { constructor(u1: Float, v1: Float, u2: Float, v2: Float) : this(Vec2(u1, v1), Vec2(u2, v2)) constructor(u1: Int, v1: Int, u2: Int, v2: Int) : this(u1 / BLOCK_SIZE, v1 / BLOCK_SIZE, u2 / BLOCK_SIZE, v2 / BLOCK_SIZE) + + + fun toArray(direction: Directions): FloatArray { + return when (direction) { + // @formatter:off + Directions.DOWN, + Directions.SOUTH, + Directions.WEST -> floatArrayOf(start.x, start.y, start.x, end.y, end.x, end.y, end.x, start.y) + Directions.UP -> floatArrayOf(start.x, end.y, end.x, end.y, end.x, start.y, start.x, start.y) + Directions.NORTH, + Directions.EAST -> floatArrayOf(end.x, start.y, start.x, start.y, start.x, end.y, end.x, end.y) + // @formatter:on + } + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/apply/SingleBlockStateApply.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/apply/SingleBlockStateApply.kt index 4f1e180fc..073bb0da6 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/apply/SingleBlockStateApply.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/apply/SingleBlockStateApply.kt @@ -16,11 +16,14 @@ package de.bixilon.minosoft.gui.rendering.models.block.state.apply import de.bixilon.kutil.json.JsonObject import de.bixilon.kutil.primitive.BooleanUtil.toBoolean import de.bixilon.kutil.primitive.IntUtil.toInt +import de.bixilon.minosoft.data.direction.DirectionUtil.rotateY import de.bixilon.minosoft.data.direction.Directions import de.bixilon.minosoft.gui.rendering.models.block.BlockModel import de.bixilon.minosoft.gui.rendering.models.block.state.baked.BakedFace import de.bixilon.minosoft.gui.rendering.models.block.state.baked.BakedModel +import de.bixilon.minosoft.gui.rendering.models.block.state.baked.BakingUtil.compact import de.bixilon.minosoft.gui.rendering.models.block.state.baked.BakingUtil.positions +import de.bixilon.minosoft.gui.rendering.models.block.state.baked.BakingUtil.pushRight import de.bixilon.minosoft.gui.rendering.models.block.state.baked.SideSize import de.bixilon.minosoft.gui.rendering.models.loader.BlockLoader import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureManager @@ -39,27 +42,48 @@ data class SingleBlockStateApply( override fun bake(textures: TextureManager): BakedModel? { if (model.elements == null) return null - val bakedFaces: MutableMap> = EnumMap(Directions::class.java) // TODO: use array + val bakedFaces: Array> = Array(Directions.SIZE) { mutableListOf() } val sizes: MutableMap> = EnumMap(Directions::class.java) for (element in model.elements) { for ((direction, face) in element.faces) { val texture = face.createTexture(model, textures) + var rotatedDirection = direction + if (y != 0) { + rotatedDirection = rotatedDirection.rotateY(this.y) + } + val positions = positions(rotatedDirection, element.from, element.to) - val positions = positions(direction, element.from, element.to) + var uv = face.uv.toArray(direction) + if (y != 0 && !uvLock) { + uv = uv.pushRight(2, if (rotatedDirection.negative) -y else y) + } + val shade = direction.shade + + val bakedFace = BakedFace(positions, uv, shade, face.tintIndex, face.cull, texture) + + bakedFaces[direction.ordinal] += bakedFace } } - TODO() + + return BakedModel(bakedFaces.compact(), emptyArray()) } - companion object { + const val ROTATION_STEP = 90 + fun deserialize(model: BlockModel, data: JsonObject): SingleBlockStateApply { val uvLock = data["uvlock"]?.toBoolean() ?: false val weight = data["weight"]?.toInt() ?: 1 - val x = data["x"]?.toInt() ?: 0 - val y = data["y"]?.toInt() ?: 0 + var x = data["x"]?.toInt() ?: 0 + var y = data["y"]?.toInt() ?: 0 + + if (x % ROTATION_STEP != 0) throw IllegalArgumentException("Invalid x rotation: $x") + x /= ROTATION_STEP + + if (y % ROTATION_STEP != 0) throw IllegalArgumentException("Invalid x rotation: $y") + y /= ROTATION_STEP return SingleBlockStateApply(model, uvLock, weight, x, y) } @@ -69,5 +93,13 @@ data class SingleBlockStateApply( return deserialize(model, data) } + + val Directions.shade: Float + get() = when (this) { + Directions.UP -> 1.0f + Directions.DOWN -> 0.5f + Directions.NORTH, Directions.SOUTH -> 0.8f + Directions.WEST, Directions.EAST -> 0.6f + } } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/baked/BakingUtil.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/baked/BakingUtil.kt index 5a433ff58..d7413b143 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/baked/BakingUtil.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/baked/BakingUtil.kt @@ -14,6 +14,7 @@ package de.bixilon.minosoft.gui.rendering.models.block.state.baked import de.bixilon.kotlinglm.vec3.Vec3 +import de.bixilon.kutil.array.ArrayUtil.cast import de.bixilon.minosoft.data.direction.Directions object BakingUtil { @@ -31,4 +32,33 @@ object BakingUtil { } } + inline fun Array>.compact(): Array> { + val array: Array?> = arrayOfNulls(size) + + for ((index, entries) in this.withIndex()) { + array[index] = entries.toTypedArray() + } + + return array.cast() + } + + + fun FloatArray.pushRight(components: Int, steps: Int): FloatArray { + if (this.size % components != 0) throw IllegalArgumentException("Size mismatch!") + var steps = steps % (size / components) + if (steps < 0) steps += size * components + + val target = FloatArray(size) + + // push every value $components*steps right + + val count = components * steps + + for ((index, value) in this.withIndex()) { + val destination = (index + count) % this.size // TODO: allow negative steps + target[destination] = value + } + + return target + } } diff --git a/src/test/java/de/bixilon/minosoft/data/direction/DirectionUtilTest.kt b/src/test/java/de/bixilon/minosoft/data/direction/DirectionUtilTest.kt new file mode 100644 index 000000000..bca82af62 --- /dev/null +++ b/src/test/java/de/bixilon/minosoft/data/direction/DirectionUtilTest.kt @@ -0,0 +1,81 @@ +/* + * 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.data.direction + +import de.bixilon.minosoft.data.direction.DirectionUtil.rotateY +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +class DirectionUtilTest { + + @Test + fun rotateY1() { + assertEquals(Directions.UP.rotateY(1), Directions.UP) + assertEquals(Directions.DOWN.rotateY(1), Directions.DOWN) + assertEquals(Directions.NORTH.rotateY(1), Directions.EAST) + assertEquals(Directions.EAST.rotateY(1), Directions.SOUTH) + assertEquals(Directions.SOUTH.rotateY(1), Directions.WEST) + assertEquals(Directions.WEST.rotateY(1), Directions.NORTH) + } + + @Test + fun rotateY5() { + assertEquals(Directions.UP.rotateY(5), Directions.UP) + assertEquals(Directions.DOWN.rotateY(5), Directions.DOWN) + assertEquals(Directions.NORTH.rotateY(5), Directions.EAST) + assertEquals(Directions.EAST.rotateY(5), Directions.SOUTH) + assertEquals(Directions.SOUTH.rotateY(5), Directions.WEST) + assertEquals(Directions.WEST.rotateY(5), Directions.NORTH) + } + + @Test + fun rotateY2() { + assertEquals(Directions.UP.rotateY(2), Directions.UP) + assertEquals(Directions.DOWN.rotateY(2), Directions.DOWN) + assertEquals(Directions.NORTH.rotateY(2), Directions.SOUTH) + assertEquals(Directions.EAST.rotateY(2), Directions.WEST) + assertEquals(Directions.SOUTH.rotateY(2), Directions.NORTH) + assertEquals(Directions.WEST.rotateY(2), Directions.EAST) + } + + @Test + fun rotateY3() { + assertEquals(Directions.UP.rotateY(3), Directions.UP) + assertEquals(Directions.DOWN.rotateY(3), Directions.DOWN) + assertEquals(Directions.NORTH.rotateY(3), Directions.WEST) + assertEquals(Directions.EAST.rotateY(3), Directions.NORTH) + assertEquals(Directions.SOUTH.rotateY(3), Directions.EAST) + assertEquals(Directions.WEST.rotateY(3), Directions.SOUTH) + } + + @Test + fun `rotateY-1`() { + assertEquals(Directions.UP.rotateY(-1), Directions.UP) + assertEquals(Directions.DOWN.rotateY(-1), Directions.DOWN) + assertEquals(Directions.NORTH.rotateY(-1), Directions.WEST) + assertEquals(Directions.EAST.rotateY(-1), Directions.NORTH) + assertEquals(Directions.SOUTH.rotateY(-1), Directions.EAST) + assertEquals(Directions.WEST.rotateY(-1), Directions.SOUTH) + } + + @Test + fun rotateY4() { + assertEquals(Directions.UP.rotateY(4), Directions.UP) + assertEquals(Directions.DOWN.rotateY(4), Directions.DOWN) + assertEquals(Directions.NORTH.rotateY(4), Directions.NORTH) + assertEquals(Directions.EAST.rotateY(4), Directions.EAST) + assertEquals(Directions.SOUTH.rotateY(4), Directions.SOUTH) + assertEquals(Directions.WEST.rotateY(4), Directions.WEST) + } +} diff --git a/src/test/java/de/bixilon/minosoft/gui/rendering/models/block/state/baked/BakingUtilTest.kt b/src/test/java/de/bixilon/minosoft/gui/rendering/models/block/state/baked/BakingUtilTest.kt index 1a2167b54..2e4a28d6f 100644 --- a/src/test/java/de/bixilon/minosoft/gui/rendering/models/block/state/baked/BakingUtilTest.kt +++ b/src/test/java/de/bixilon/minosoft/gui/rendering/models/block/state/baked/BakingUtilTest.kt @@ -15,6 +15,7 @@ package de.bixilon.minosoft.gui.rendering.models.block.state.baked import de.bixilon.kotlinglm.vec3.Vec3 import de.bixilon.minosoft.data.direction.Directions +import de.bixilon.minosoft.gui.rendering.models.block.state.baked.BakingUtil.pushRight import kotlin.test.Test import kotlin.test.assertContentEquals @@ -70,4 +71,46 @@ class BakingUtilTest { floatArrayOf(6.0f, 2.0f, 3.0f, 6.0f, 2.0f, 4.0f, 6.0f, 5.0f, 4.0f, 6.0f, 5.0f, 3.0f) ) } + + @Test + fun pushRight1() { + val array = floatArrayOf(0f, 1f, 2f, 3f, 4f, 5f) + val expected = floatArrayOf(4f, 5f, 0f, 1f, 2f, 3f) + assertContentEquals(expected, array.pushRight(2, 1)) + } + + @Test + fun pushRight2() { + val array = floatArrayOf(0f, 1f, 2f, 3f, 4f, 5f) + val expected = floatArrayOf(2f, 3f, 4f, 5f, 0f, 1f) + assertContentEquals(expected, array.pushRight(2, 2)) + } + + @Test + fun pushRight3() { + val array = floatArrayOf(0f, 1f, 2f, 3f, 4f, 5f) + val expected = floatArrayOf(0f, 1f, 2f, 3f, 4f, 5f) + assertContentEquals(expected, array.pushRight(2, 3)) + } + + @Test + fun pushLeft1() { + val array = floatArrayOf(0f, 1f, 2f, 3f, 4f, 5f) + val expected = floatArrayOf(2f, 3f, 4f, 5f, 0f, 1f) + assertContentEquals(expected, array.pushRight(2, -1)) + } + + @Test + fun pushLeft2() { + val array = floatArrayOf(0f, 1f, 2f, 3f, 4f, 5f) + val expected = floatArrayOf(4f, 5f, 0f, 1f, 2f, 3f) + assertContentEquals(expected, array.pushRight(2, -2)) + } + + @Test + fun pushLeft3() { + val array = floatArrayOf(0f, 1f, 2f, 3f, 4f, 5f) + val expected = floatArrayOf(0f, 1f, 2f, 3f, 4f, 5f) + assertContentEquals(expected, array.pushRight(2, -3)) + } }