Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add waitTick built-in to pressKey and pressMouse #4362

Merged
merged 1 commit into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public interface TestInput {
* Starts holding down a key binding. The key binding will be held until it is released. The key binding must be
* bound. Does nothing if the key binding is already being held.
*
* <p><strong>Most key bindings will only start reacting to this when a tick is waited.</strong>
*
* @param keyBinding The key binding to hold
* @see #releaseKey(KeyBinding)
* @see #pressKey(KeyBinding)
Expand All @@ -45,6 +47,8 @@ public interface TestInput {
* Starts holding down a key binding. The key binding will be held until it is released. The key binding must be
* bound. Does nothing if the key binding is already being held.
*
* <p><strong>Most key bindings will only start reacting to this when a tick is waited.</strong>
*
* @param keyBindingGetter The function to get the key binding from the game options
* @see #releaseKey(Function)
* @see #pressKey(Function)
Expand All @@ -56,6 +60,8 @@ public interface TestInput {
* Starts holding down a key or mouse button. The key will be held until it is released. Does nothing if the key or
* mouse button is already being held.
*
* <p><strong>Most key bindings will only start reacting to this when a tick is waited.</strong>
*
* @param key The key or mouse button to hold
* @see #releaseKey(InputUtil.Key)
* @see #pressKey(InputUtil.Key)
Expand All @@ -66,6 +72,8 @@ public interface TestInput {
* Starts holding down a key. The key will be held until it is released. Does nothing if the key is already being
* held.
*
* <p><strong>Most key bindings will only start reacting to this when a tick is waited.</strong>
*
* @param keyCode The key code of the key to hold
* @see #releaseKey(int)
* @see #pressKey(int)
Expand All @@ -76,6 +84,8 @@ public interface TestInput {
* Starts holding down a mouse button. The mouse button will be held until it is released. Does nothing if the mouse
* button is already being held.
*
* <p><strong>Most key bindings will only start reacting to this when a tick is waited.</strong>
*
* @param button The mouse button to hold
* @see #releaseMouse(int)
* @see #pressMouse(int)
Expand Down Expand Up @@ -110,6 +120,8 @@ public interface TestInput {
/**
* Releases a key binding. The key binding must be bound. Does nothing if the key binding is not being held.
*
* <p><strong>Most key bindings will only react to this when a tick is waited.</strong>
*
* @param keyBinding The key binding to release
* @see #holdKey(KeyBinding)
* @see #releaseKey(Function)
Expand All @@ -119,6 +131,8 @@ public interface TestInput {
/**
* Releases a key binding. The key binding must be bound. Does nothing if the key binding is not being held.
*
* <p><strong>Most key bindings will only react to this when a tick is waited.</strong>
*
* @param keyBindingGetter The function to get the key binding from the game options
* @see #holdKey(Function)
* @see #releaseKey(KeyBinding)
Expand All @@ -128,6 +142,8 @@ public interface TestInput {
/**
* Releases a key or mouse button. Does nothing if the key or mouse button is not being held.
*
* <p><strong>Most key bindings will only react to this when a tick is waited.</strong>
*
* @param key The key or mouse button to release
* @see #holdKey(InputUtil.Key)
*/
Expand All @@ -136,6 +152,8 @@ public interface TestInput {
/**
* Releases a key. Does nothing if the key is not being held.
*
* <p><strong>Most key bindings will only react to this when a tick is waited.</strong>
*
* @param keyCode The GLFW key code of the key to release
* @see #holdKey(int)
*/
Expand All @@ -144,6 +162,8 @@ public interface TestInput {
/**
* Releases a mouse button. Does nothing if the mouse button is not being held.
*
* <p><strong>Most key bindings will only react to this when a tick is waited.</strong>
*
* @param button The GLFW mouse button to release
* @see #holdMouse(int)
*/
Expand Down Expand Up @@ -174,7 +194,10 @@ public interface TestInput {
void releaseAlt();

/**
* Presses and releases a key binding. The key binding must be bound.
* Presses and releases a key binding, then waits a tick. The key binding must be bound.
*
* <p>A tick is waited because most key bindings need a tick to happen to react to the press. If you don't want the
* delay, use {@link #holdKeyFor(KeyBinding, int) holdKeyFor} with a tick count of {@code 0}.
*
* @param keyBinding The key binding to press
* @see #holdKey(KeyBinding)
Expand All @@ -183,7 +206,10 @@ public interface TestInput {
void pressKey(KeyBinding keyBinding);

/**
* Presses and releases a key binding. The key binding must be bound.
* Presses and releases a key binding, then waits a tick. The key binding must be bound.
*
* <p>A tick is waited because most key bindings need a tick to happen to react to the press. If you don't want the
* delay, use {@link #holdKeyFor(Function, int) holdKeyFor} with a tick count of {@code 0}.
*
* @param keyBindingGetter The function to get the key binding from the game options
* @see #holdKey(Function)
Expand All @@ -192,15 +218,21 @@ public interface TestInput {
void pressKey(Function<GameOptions, KeyBinding> keyBindingGetter);

/**
* Presses and releases a key or mouse button.
* Presses and releases a key or mouse button, then waits a tick.
*
* <p>A tick is waited because most key bindings need a tick to happen to react to the press. If you don't want the
* delay, use {@link #holdKeyFor(InputUtil.Key, int) holdKeyFor} with a tick count of {@code 0}.
*
* @param key The key or mouse button to press.
* @see #holdKey(InputUtil.Key)
*/
void pressKey(InputUtil.Key key);

/**
* Presses and releases a key.
* Presses and releases a key, then waits a tick.
*
* <p>A tick is waited because most key bindings need a tick to happen to react to the press. If you don't want the
* delay, use {@link #holdKeyFor(int, int) holdKeyFor} with a tick count of {@code 0}.
*
* <p>For sending Unicode text input (e.g. into text boxes), use {@link #typeChar(int)} or
* {@link #typeChars(String)} instead.
Expand All @@ -211,7 +243,10 @@ public interface TestInput {
void pressKey(int keyCode);

/**
* Presses and releases a mouse button.
* Presses and releases a mouse button, then waits a tick.
*
* <p>A tick is waited because most key bindings need a tick to happen to react to the press. If you don't want the
* delay, use {@link #holdMouseFor(int, int) holdMouseFor} with a tick count of {@code 0}.
*
* @param button The GLFW mouse button to press
* @see #holdMouse(int)
Expand All @@ -222,6 +257,9 @@ public interface TestInput {
* Holds a key binding for the specified number of ticks and then releases it. Waits until this process is finished.
* The key binding must be bound.
*
* <p>Although the key will be released when this method returns, <strong>most key bindings will only react to this
* when a tick is waited.</strong>
*
* @param keyBinding The key binding to hold
* @param ticks The number of ticks to hold the key binding for
* @see #holdKey(KeyBinding)
Expand All @@ -233,6 +271,9 @@ public interface TestInput {
* Holds a key binding for the specified number of ticks and then releases it. Waits until this process is finished.
* The key binding must be bound.
*
* <p>Although the key will be released when this method returns, <strong>most key bindings will only react to this
* when a tick is waited.</strong>
*
* @param keyBindingGetter The key binding to hold
* @param ticks The number of ticks to hold the key binding for
* @see #holdKey(Function)
Expand All @@ -244,6 +285,9 @@ public interface TestInput {
* Holds a key or mouse button for the specified number of ticks and then releases it. Waits until this process is
* finished.
*
* <p>Although the key or mouse button will be released when this method returns, <strong>most key bindings will
* only react to this when a tick is waited.</strong>
*
* @param key The key or mouse button to hold
* @param ticks The number of ticks to hold the key or mouse button for
* @see #holdKey(InputUtil.Key)
Expand All @@ -253,6 +297,9 @@ public interface TestInput {
/**
* Holds a key for the specified number of ticks and then releases it. Waits until this process is finished.
*
* <p>Although the key will be released when this method returns, <strong>most key bindings will only react to this
* when a tick is waited.</strong>
*
* @param keyCode The GLFW key code of the key to hold
* @param ticks The number of ticks to hold the key for
* @see #holdKey(int)
Expand All @@ -263,6 +310,9 @@ public interface TestInput {
* Holds a mouse button for the specified number of ticks and then releases it. Waits until this process is
* finished.
*
* <p>Although the mouse button will be released when this method returns, <strong>most key bindings will only react
* to this when a tick is waited.</strong>
*
* @param button The GLFW mouse button to hold
* @param ticks The number of ticks to hold the mouse button for
* @see #holdMouse(int)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@
*
* <p>The game remains paused unless you explicitly unpause it using various waiting functions such as
* {@link net.fabricmc.fabric.api.client.gametest.v1.ClientGameTestContext#waitTick() ClientGameTestContext.waitTick()}.
* A side effect of this is that <strong>the results of your code may not be immediate if the game needs a tick to
* process them</strong>. A big example of this is key bindings, although some key binding methods have built-in tick
* waits to mitigate the issue. See the {@link net.fabricmc.fabric.api.client.gametest.v1.TestInput TestInput}
* documentation for details. Another pseudo-example is effects on the server need a tick to propagate to the client and
* vice versa, although this is related to packets more than the fact the game is suspended (see the network
* synchronization section below). A good strategy for debugging these issues is by
* {@linkplain net.fabricmc.fabric.api.client.gametest.v1.ClientGameTestContext#takeScreenshot(String) taking screenshots},
* which capture the immediate state of the game.
*
* <p>A few changes have been made to how the vanilla game threads run, to make tests more reproducible. Notably, there
* is exactly one server tick per client tick while a server is running (singleplayer or multiplayer). There is also a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
*
* <ul>
* <li>A packet can be either "in-flight", which is between the time it is sent and the time it is handled on the
* Netty thread on the receiving side, or it can be queued for handling on the receiving main thread, which it
* Netty thread on the receiving side, or it can be queued for handling on the receiving main thread, which is
* between when it is handled on the Netty thread and it is removed from the main thread task queue.
* <ul>
* <li>Some packets are handled directly on the Netty thread and never enter the second stage. The
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ public void pressKey(InputUtil.Key key) {

holdKey(key);
releaseKey(key);
context.waitTick();
}

@Override
Expand All @@ -229,7 +230,7 @@ public void pressMouse(int button) {
public void holdKeyFor(KeyBinding keyBinding, int ticks) {
ThreadingImpl.checkOnGametestThread("holdKeyFor");
Preconditions.checkNotNull(keyBinding, "keyBinding");
Preconditions.checkArgument(ticks > 0, "ticks must be positive");
Preconditions.checkArgument(ticks >= 0, "ticks cannot be negative");

holdKeyFor(getBoundKey(keyBinding, "hold"), ticks);
}
Expand All @@ -238,7 +239,7 @@ public void holdKeyFor(KeyBinding keyBinding, int ticks) {
public void holdKeyFor(Function<GameOptions, KeyBinding> keyBindingGetter, int ticks) {
ThreadingImpl.checkOnGametestThread("holdKeyFor");
Preconditions.checkNotNull(keyBindingGetter, "keyBindingGetter");
Preconditions.checkArgument(ticks > 0, "ticks must be positive");
Preconditions.checkArgument(ticks >= 0, "ticks cannot be negative");

KeyBinding keyBinding = context.computeOnClient(client -> keyBindingGetter.apply(client.options));
holdKeyFor(keyBinding, ticks);
Expand All @@ -248,7 +249,7 @@ public void holdKeyFor(Function<GameOptions, KeyBinding> keyBindingGetter, int t
public void holdKeyFor(InputUtil.Key key, int ticks) {
ThreadingImpl.checkOnGametestThread("holdKeyFor");
Preconditions.checkNotNull(key, "key");
Preconditions.checkArgument(ticks > 0, "ticks must be positive");
Preconditions.checkArgument(ticks >= 0, "ticks cannot be negative");

holdKey(key);
context.waitTicks(ticks);
Expand All @@ -258,15 +259,15 @@ public void holdKeyFor(InputUtil.Key key, int ticks) {
@Override
public void holdKeyFor(int keyCode, int ticks) {
ThreadingImpl.checkOnGametestThread("holdKeyFor");
Preconditions.checkArgument(ticks > 0, "ticks must be positive");
Preconditions.checkArgument(ticks >= 0, "ticks cannot be negative");

holdKeyFor(InputUtil.Type.KEYSYM.createFromCode(keyCode), ticks);
}

@Override
public void holdMouseFor(int button, int ticks) {
ThreadingImpl.checkOnGametestThread("holdMouseFor");
Preconditions.checkArgument(ticks > 0, "ticks must be positive");
Preconditions.checkArgument(ticks >= 0, "ticks cannot be negative");

holdKeyFor(InputUtil.Type.MOUSE.createFromCode(button), ticks);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,8 @@ public void runTest(ClientGameTestContext context) {

{
context.getInput().pressKey(options -> options.chatKey);
context.waitTick();
context.getInput().typeChars("Hello, World!");
context.getInput().pressKey(InputUtil.GLFW_KEY_ENTER);
context.getInput().holdKeyFor(InputUtil.GLFW_KEY_ENTER, 0); // press without delay, enter not a keybind
context.waitTick(); // wait for the server to receive the chat message
context.takeScreenshot("chat_message_sent");
}
Expand All @@ -86,7 +85,7 @@ public void runTest(ClientGameTestContext context) {

{
context.getInput().pressKey(options -> options.inventoryKey);
context.waitTicks(2); // allow the client to process the key press, and then the server to receive the request
context.waitTick(); // wait for the server to receive the request
context.takeScreenshot("in_game_inventory");
context.setScreen(() -> null);
}
Expand Down