CC-Tweaked/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Modem_Test.kt

220 lines
8.5 KiB
Kotlin

// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.gametest
import dan200.computercraft.api.lua.ObjectArguments
import dan200.computercraft.core.apis.PeripheralAPI
import dan200.computercraft.core.computer.ComputerSide
import dan200.computercraft.gametest.api.*
import dan200.computercraft.impl.network.wired.WiredNodeImpl
import dan200.computercraft.shared.ModRegistry
import dan200.computercraft.shared.peripheral.modem.wired.CableBlock
import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant
import dan200.computercraft.test.core.assertArrayEquals
import dan200.computercraft.test.core.computer.LuaTaskContext
import dan200.computercraft.test.core.computer.getApi
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.gametest.framework.GameTest
import net.minecraft.gametest.framework.GameTestHelper
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.level.block.Blocks
import org.junit.jupiter.api.Assertions.assertEquals
import kotlin.time.Duration.Companion.milliseconds
class Modem_Test {
@GameTest
fun Have_peripherals(helper: GameTestHelper) = helper.sequence {
thenOnComputer {
assertEquals(listOf("monitor_0", "printer_0", "right"), getPeripheralNames(), "Starts with peripherals")
}
}
@GameTest
fun Gains_peripherals(helper: GameTestHelper) = helper.sequence {
val position = BlockPos(2, 2, 2)
thenOnComputer {
assertEquals(listOf("back"), getPeripheralNames(), "Starts with peripherals")
}
thenExecute {
helper.setBlock(
position,
CableBlock.correctConnections(
helper.level,
helper.absolutePos(position),
ModRegistry.Blocks.CABLE.get().defaultBlockState().setValue(CableBlock.CABLE, true),
),
)
}
thenIdle(1)
thenOnComputer {
assertEquals(listOf("back", "monitor_1", "printer_1"), getPeripheralNames(), "Gains new peripherals")
}
}
/**
* Sends a modem message to another computer on the same network
*/
@GameTest
fun Transmits_messages(context: GameTestHelper) = context.sequence {
thenStartComputer("send") {
val modem = findPeripheral("modem") ?: throw IllegalStateException("Cannot find modem")
while (true) {
callPeripheral(modem, "transmit", 12, 34, "Hello")
sleep(50.milliseconds)
}
}
thenOnComputer("receive") {
val modem = findPeripheral("modem") ?: throw IllegalStateException("Cannot find modem")
callPeripheral(modem, "open", 12)
pullEvent("modem_message")
.assertArrayEquals("modem_message", "left", 12, 34, "Hello", 4, message = "Modem message")
}
}
/**
* Assert that full block modems act like cables.
*
* @see [#1278](https://github.com/cc-tweaked/CC-Tweaked/issues/1278)
*/
@GameTest(setupTicks = 1)
fun Full_modems_form_networks(helper: GameTestHelper) = helper.sequence {
thenExecute {
val modem1 = helper.getBlockEntity(BlockPos(1, 2, 1), ModRegistry.BlockEntities.WIRED_MODEM_FULL.get())
val modem2 = helper.getBlockEntity(BlockPos(3, 2, 1), ModRegistry.BlockEntities.WIRED_MODEM_FULL.get())
assertEquals((modem1.element.node as WiredNodeImpl).network, (modem2.element.node as WiredNodeImpl).network, "On the same network")
}
}
/**
* Modems do not include the current peripheral when attached.
*/
@GameTest
fun Cable_modem_does_not_report_self(helper: GameTestHelper) = helper.sequence {
// Modem does not report the computer as a peripheral.
thenOnComputer { assertEquals(listOf("back", "right"), getPeripheralNames()) }
// However, if we connect the network, the other modem does.
thenExecute {
helper.setBlock(
BlockPos(1, 2, 3),
ModRegistry.Blocks.CABLE.get().defaultBlockState().setValue(CableBlock.CABLE, true),
)
}
thenIdle(2)
thenOnComputer { assertEquals(listOf("back", "computer_0", "right"), getPeripheralNames()) }
}
/**
* Modems do not include the current peripheral when attached.
*/
@GameTest
fun Full_block_modem_does_not_report_self(helper: GameTestHelper) = helper.sequence {
// Modem does not report the computer as a peripheral.
thenOnComputer { assertEquals(listOf("back", "right"), getPeripheralNames()) }
// However, if we connect the network, the other modem does.
thenExecute {
helper.setBlock(
BlockPos(1, 2, 3),
ModRegistry.Blocks.CABLE.get().defaultBlockState().setValue(CableBlock.CABLE, true),
)
}
thenIdle(2)
thenOnComputer { assertEquals(listOf("back", "computer_1", "right"), getPeripheralNames()) }
}
/**
* Test wired modems (without a cable) drop an item when the adjacent block is removed.
*/
@GameTest
fun Modem_drops_when_neighbour_removed(helper: GameTestHelper) = helper.sequence {
thenExecute {
helper.setBlock(BlockPos(2, 3, 2), Blocks.AIR)
helper.assertItemEntityPresent(ModRegistry.Items.WIRED_MODEM.get(), BlockPos(2, 2, 2), 0.0)
helper.assertBlockPresent(Blocks.AIR, BlockPos(2, 2, 2))
}
}
/**
* Test wired modems (with a cable) drop an item, but keep their cable when the adjacent block is removed.
*/
@GameTest
fun Modem_keeps_cable_when_neighbour_removed(helper: GameTestHelper) = helper.sequence {
thenExecute {
helper.setBlock(BlockPos(2, 3, 2), Blocks.AIR)
helper.assertItemEntityPresent(ModRegistry.Items.WIRED_MODEM.get(), BlockPos(2, 2, 2), 0.0)
helper.assertBlockIs(BlockPos(2, 2, 2)) {
it.block == ModRegistry.Blocks.CABLE.get() && it.getValue(CableBlock.MODEM) == CableModemVariant.None && it.getValue(CableBlock.CABLE)
}
}
}
/**
* Check chest peripherals are reattached with a new size.
*/
@GameTest
fun Chest_resizes_on_change(context: GameTestHelper) = context.sequence {
thenOnComputer {
callRemotePeripheral("minecraft:chest_0", "size").assertArrayEquals(27)
}
thenExecute { context.placeItemAt(ItemStack(Items.CHEST), BlockPos(2, 2, 2), Direction.WEST) }
thenIdle(1)
thenOnComputer {
callRemotePeripheral("minecraft:chest_0", "size").assertArrayEquals(54)
}
}
}
private fun LuaTaskContext.findPeripheral(type: String): String? {
val peripheral = getApi<PeripheralAPI>()
for (side in ComputerSide.NAMES) {
val hasType = peripheral.hasType(side, type)
if (hasType != null && hasType[0] == true) return side
}
return null
}
private suspend fun LuaTaskContext.getPeripheralNames(): List<String> {
val peripheral = getApi<PeripheralAPI>()
val peripherals = mutableListOf<String>()
for (side in ComputerSide.NAMES) {
if (!peripheral.isPresent(side)) continue
peripherals.add(side)
val hasType = peripheral.hasType(side, "peripheral_hub")
if (hasType == null || hasType[0] != true) continue
val names = peripheral.call(context, ObjectArguments(side, "getNamesRemote")).await() ?: continue
@Suppress("UNCHECKED_CAST")
peripherals.addAll(names[0] as Collection<String>)
}
peripherals.sort()
return peripherals
}
private suspend fun LuaTaskContext.callRemotePeripheral(name: String, method: String, vararg args: Any): Array<out Any?>? {
val peripheral = getApi<PeripheralAPI>()
if (peripheral.isPresent(name)) return peripheral.call(context, ObjectArguments(name, method, *args)).await()
for (side in ComputerSide.NAMES) {
if (!peripheral.isPresent(side)) continue
val hasType = peripheral.hasType(side, "peripheral_hub")
if (hasType == null || hasType[0] != true) continue
val isPresent = peripheral.call(context, ObjectArguments(side, "isPresentRemote", name)).await() ?: continue
if (isPresent[0] as Boolean) {
return peripheral.call(context, ObjectArguments(side, "callRemote", name, method, *args)).await()
}
}
throw IllegalArgumentException("No such peripheral $name")
}