mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-10-30 13:13:00 +00:00
Add a couple of tests for pocket computers
- Ensure they're correctly synced to the client. This definitely isn't comprehensive, but doing anything further probably involves multiple players, which is tricky. - Quick rendering test for in-hand computers.
This commit is contained in:
@@ -49,9 +49,9 @@ public class PocketComputerItem extends Item implements IComputerItem, IMedia, I
|
||||
private static final String NBT_UPGRADE = "Upgrade";
|
||||
private static final String NBT_UPGRADE_INFO = "UpgradeInfo";
|
||||
public static final String NBT_LIGHT = "Light";
|
||||
private static final String NBT_ON = "On";
|
||||
public static final String NBT_ON = "On";
|
||||
|
||||
private static final String NBT_INSTANCE = "Instanceid";
|
||||
private static final String NBT_INSTANCE = "InstanceId";
|
||||
private static final String NBT_SESSION = "SessionId";
|
||||
|
||||
private final ComputerFamily family;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.gametest.core;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
/**
|
||||
* Extensions to {@link Minecraft}, injected via mixin.
|
||||
*/
|
||||
public interface MinecraftExtensions {
|
||||
boolean computercraft$isRenderingStable();
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.mixin.gametest.client;
|
||||
|
||||
import dan200.computercraft.gametest.core.MinecraftExtensions;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.client.renderer.LevelRenderer;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@Mixin(Minecraft.class)
|
||||
class MinecraftMixin implements MinecraftExtensions {
|
||||
@Final
|
||||
@Shadow
|
||||
public LevelRenderer levelRenderer;
|
||||
|
||||
@Shadow
|
||||
@Nullable
|
||||
public ClientLevel level;
|
||||
|
||||
@Shadow
|
||||
@Nullable
|
||||
public LocalPlayer player;
|
||||
|
||||
@Unique
|
||||
private final AtomicBoolean isStable = new AtomicBoolean(false);
|
||||
|
||||
@Inject(method = "runTick", at = @At("TAIL"))
|
||||
private void updateStable(boolean render, CallbackInfo ci) {
|
||||
isStable.set(
|
||||
level != null && player != null &&
|
||||
levelRenderer.isChunkCompiled(player.blockPosition()) && levelRenderer.countRenderedChunks() > 10 &&
|
||||
levelRenderer.hasRenderedAllChunks()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean computercraft$isRenderingStable() {
|
||||
return isStable.get();
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ class Inventory_Test {
|
||||
/**
|
||||
* Ensures inventory methods check an item is valid before moving it.
|
||||
*
|
||||
* @see <https://github.com/cc-tweaked/cc-restitched/issues/121>
|
||||
* @see <https://github.com/cc-tweaked/cc-restitched/issues/122>
|
||||
*/
|
||||
@GameTest
|
||||
fun Fails_on_full(helper: GameTestHelper) = helper.sequence {
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package dan200.computercraft.gametest
|
||||
|
||||
import dan200.computercraft.api.lua.ObjectArguments
|
||||
import dan200.computercraft.client.pocket.ClientPocketComputers
|
||||
import dan200.computercraft.core.apis.TermAPI
|
||||
import dan200.computercraft.gametest.api.*
|
||||
import dan200.computercraft.mixin.gametest.GameTestHelperAccessor
|
||||
import dan200.computercraft.shared.ModRegistry
|
||||
import dan200.computercraft.shared.computer.core.ComputerState
|
||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem
|
||||
import dan200.computercraft.test.core.computer.getApi
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.gametest.framework.GameTestHelper
|
||||
import net.minecraft.gametest.framework.GameTestSequence
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import kotlin.random.Random
|
||||
|
||||
class Pocket_Computer_Test {
|
||||
/**
|
||||
* Checks pocket computer state is synced to the holding player.
|
||||
*/
|
||||
@ClientGameTest(template = Structures.DEFAULT)
|
||||
fun Sync_state(context: GameTestHelper) = context.sequence {
|
||||
// We use a unique label for each test run as computers from previous runs may not have been disposed yet.
|
||||
val unique = java.lang.Long.toHexString(Random.nextLong())
|
||||
|
||||
// Give the player a pocket computer.
|
||||
thenExecute {
|
||||
context.positionAt(BlockPos(2, 2, 2))
|
||||
context.givePocketComputer(unique)
|
||||
}
|
||||
// Write some text to the computer.
|
||||
thenOnComputer(unique) { getApi<TermAPI>().write(ObjectArguments("Hello, world!")) }
|
||||
// And ensure its synced to the client.
|
||||
thenIdle(4)
|
||||
thenOnClient {
|
||||
val pocketComputer = ClientPocketComputers.get(minecraft.player!!.mainHandItem)
|
||||
assertEquals(ComputerState.ON, pocketComputer.state)
|
||||
|
||||
val term = pocketComputer.terminal
|
||||
assertEquals("Hello, world!", term.getLine(0).toString().trim(), "Terminal contents is synced")
|
||||
}
|
||||
// Update the terminal contents again.
|
||||
thenOnComputer(unique) {
|
||||
val term = getApi<TermAPI>()
|
||||
term.setCursorPos(1, 1)
|
||||
term.setCursorBlink(true)
|
||||
term.write(ObjectArguments("Updated text :)"))
|
||||
}
|
||||
// And ensure the new computer state and terminal are sent.
|
||||
thenIdle(4)
|
||||
thenOnClient {
|
||||
val pocketComputer = ClientPocketComputers.get(minecraft.player!!.mainHandItem)
|
||||
assertEquals(ComputerState.BLINKING, pocketComputer.state)
|
||||
|
||||
val term = pocketComputer.terminal
|
||||
assertEquals("Updated text :)", term.getLine(0).toString().trim(), "Terminal contents is synced")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks pocket computers are rendered when being held like a map.
|
||||
*/
|
||||
@ClientGameTest(template = Structures.DEFAULT)
|
||||
fun Renders_map_view(context: GameTestHelper) = context.sequence {
|
||||
// We use a unique label for each test run as computers from previous runs may not have been disposed yet.
|
||||
val unique = java.lang.Long.toHexString(Random.nextLong())
|
||||
|
||||
// Give the player a pocket computer.
|
||||
thenExecute {
|
||||
context.positionAt(BlockPos(2, 2, 2), xRot = 90.0f)
|
||||
context.givePocketComputer(unique)
|
||||
}
|
||||
thenOnComputer(unique) {
|
||||
val terminal = getApi<TermAPI>().terminal
|
||||
terminal.write("Hello, world!")
|
||||
terminal.setCursorPos(1, 2)
|
||||
terminal.textColour = 2
|
||||
terminal.backgroundColour = 3
|
||||
terminal.write("Some coloured text")
|
||||
}
|
||||
thenIdle(4)
|
||||
thenScreenshot(showGui = true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Give the current player a pocket computer, suitable to be controlled by [GameTestSequence.thenOnComputer].
|
||||
*/
|
||||
private fun GameTestHelper.givePocketComputer(name: String? = null) {
|
||||
val player = level.randomPlayer!!
|
||||
player.inventory.clearContent()
|
||||
|
||||
val testName = (this as GameTestHelperAccessor).testInfo.testName
|
||||
val label = testName + (if (name == null) "" else ".$name")
|
||||
|
||||
val item = ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get().create(1, label, -1, null)
|
||||
item.getOrCreateTag().putBoolean(PocketComputerItem.NBT_ON, true)
|
||||
player.inventory.setItem(0, item)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package dan200.computercraft.gametest.api
|
||||
|
||||
import dan200.computercraft.gametest.core.MinecraftExtensions
|
||||
import dan200.computercraft.mixin.gametest.GameTestSequenceAccessor
|
||||
import dan200.computercraft.shared.platform.Registries
|
||||
import net.minecraft.client.Minecraft
|
||||
@@ -20,9 +21,7 @@ import java.util.concurrent.atomic.AtomicBoolean
|
||||
/**
|
||||
* Attempt to guess whether all chunks have been rendered.
|
||||
*/
|
||||
fun Minecraft.isRenderingStable(): Boolean = level != null && player != null &&
|
||||
levelRenderer.isChunkCompiled(player!!.blockPosition()) && levelRenderer.countRenderedChunks() > 10 &&
|
||||
levelRenderer.hasRenderedAllChunks()
|
||||
fun Minecraft.isRenderingStable(): Boolean = (this as MinecraftExtensions).`computercraft$isRenderingStable`()
|
||||
|
||||
/**
|
||||
* Run a task on the client.
|
||||
@@ -44,7 +43,7 @@ fun GameTestSequence.thenOnClient(task: ClientTestHelper.() -> Unit): GameTestSe
|
||||
/**
|
||||
* Take a screenshot of the current game state.
|
||||
*/
|
||||
fun GameTestSequence.thenScreenshot(name: String? = null): GameTestSequence {
|
||||
fun GameTestSequence.thenScreenshot(name: String? = null, showGui: Boolean = false): GameTestSequence {
|
||||
val suffix = if (name == null) "" else "-$name"
|
||||
val test = (this as GameTestSequenceAccessor).parent
|
||||
val fullName = "${test.testName}$suffix"
|
||||
@@ -63,7 +62,7 @@ fun GameTestSequence.thenScreenshot(name: String? = null): GameTestSequence {
|
||||
|
||||
// Now disable the GUI, take a screenshot and reenable it. Sleep a little afterwards to ensure the render thread
|
||||
// has caught up.
|
||||
thenOnClient { minecraft.options.hideGui = true }
|
||||
thenOnClient { minecraft.options.hideGui = !showGui }
|
||||
thenIdle(2)
|
||||
|
||||
// Take a screenshot and wait for it to have finished.
|
||||
@@ -96,12 +95,12 @@ fun GameTestHelper.positionAtArmorStand() {
|
||||
/**
|
||||
* Position the player at a given coordinate.
|
||||
*/
|
||||
fun GameTestHelper.positionAt(pos: BlockPos) {
|
||||
fun GameTestHelper.positionAt(pos: BlockPos, yRot: Float = 0.0f, xRot: Float = 0.0f) {
|
||||
val absolutePos = absolutePos(pos)
|
||||
val player = level.randomPlayer ?: throw GameTestAssertException("Player does not exist")
|
||||
|
||||
player.setupForTest()
|
||||
player.connection.teleport(absolutePos.x + 0.5, absolutePos.y + 0.5, absolutePos.z + 0.5, 0.0f, 0.0f)
|
||||
player.connection.teleport(absolutePos.x + 0.5, absolutePos.y + 0.5, absolutePos.z + 0.5, yRot, xRot)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -78,6 +78,7 @@ object TestHooks {
|
||||
Loot_Test::class.java,
|
||||
Modem_Test::class.java,
|
||||
Monitor_Test::class.java,
|
||||
Pocket_Computer_Test::class.java,
|
||||
Printer_Test::class.java,
|
||||
Recipe_Test::class.java,
|
||||
Turtle_Test::class.java,
|
||||
|
||||
@@ -13,5 +13,8 @@
|
||||
"GameTestSequenceMixin",
|
||||
"SharedConstantsMixin",
|
||||
"TestCommandAccessor"
|
||||
],
|
||||
"client": [
|
||||
"client.MinecraftMixin"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user