Skip to content

Commit

Permalink
Add various lifetime-bound try-with-resources APIs to client gametests (
Browse files Browse the repository at this point in the history
#4318)

* Add various lifetime-bound try-with-resources APIs to client gametests
  • Loading branch information
Earthcomputer authored Dec 24, 2024
1 parent efa825c commit 99ff640
Show file tree
Hide file tree
Showing 35 changed files with 1,573 additions and 250 deletions.
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ jobs:
with:
distribution: 'microsoft'
java-version: '21'
- run: mkdir run && echo "eula=true" >> run/eula.txt
- name: Run Client Gametests
uses: modmuss50/xvfb-action@v1
with:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@
import net.minecraft.client.gui.screen.Screen;

/**
* Context for a client gametest containing various helpful functions and functions to access the game. Functions in
* this class can only be called on the client gametest thread.
* Context for a client gametest containing various helpful functions and functions to access the game.
*
* <p>Functions in this class can only be called on the client gametest thread.
*/
@ApiStatus.NonExtendable
public interface ClientGameTestContext {
Expand Down Expand Up @@ -61,25 +62,28 @@ public interface ClientGameTestContext {
* Waits for a predicate to be true. Fails if the predicate is not satisfied after {@link #DEFAULT_TIMEOUT} ticks.
*
* @param predicate The predicate to check
* @return The number of ticks waited
*/
void waitFor(Predicate<MinecraftClient> predicate);
int waitFor(Predicate<MinecraftClient> predicate);

/**
* Waits for a predicate to be true. Fails if the predicate is not satisfied after {@code timeout} ticks. If
* {@code timeout} is {@link #NO_TIMEOUT}, there is no timeout.
*
* @param predicate The predicate to check
* @param timeout The number of ticks before timing out
* @return The number of ticks waited
*/
void waitFor(Predicate<MinecraftClient> predicate, int timeout);
int waitFor(Predicate<MinecraftClient> predicate, int timeout);

/**
* Waits for the given screen class to be shown. If {@code screenClass} is {@code null}, waits for the current
* screen to be {@code null}. Fails if the screen does not open after {@link #DEFAULT_TIMEOUT} ticks.
*
* @param screenClass The screen class to wait to open
* @return The number of ticks waited
*/
void waitForScreen(@Nullable Class<? extends Screen> screenClass);
int waitForScreen(@Nullable Class<? extends Screen> screenClass);

/**
* Opens a {@link Screen} on the client.
Expand Down Expand Up @@ -126,7 +130,14 @@ public interface ClientGameTestContext {
*
* @return The client gametest input handler
*/
ClientGameTestInput getInput();
TestInput getInput();

/**
* Creates a world builder for creating singleplayer worlds and dedicated servers.
*
* @return A new world builder
*/
TestWorldBuilder worldBuilder();

/**
* Restores all game options in {@link MinecraftClient#options} to their default values for client gametests. This
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.fabricmc.fabric.api.client.gametest.v1;

import org.jetbrains.annotations.ApiStatus;

import net.minecraft.SharedConstants;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.util.math.BlockPos;

/**
* Context for a client gametest containing various helpful functions while a client world is open.
*
* <p>Functions in this class can only be called on the client gametest thread.
*/
@ApiStatus.NonExtendable
public interface TestClientWorldContext {
/**
* The default timeout in ticks to wait for chunks to load/render (1 minute).
*/
int DEFAULT_CHUNK_LOAD_TIMEOUT = SharedConstants.TICKS_PER_MINUTE;

/**
* Waits for all chunks that will be downloaded from the server to be downloaded. Fails if the chunks haven't been
* downloaded after {@link #DEFAULT_CHUNK_LOAD_TIMEOUT} ticks. See {@link #waitForChunksDownload(int)} for details.
*
* @return The number of ticks waited
*/
default int waitForChunksDownload() {
return waitForChunksDownload(DEFAULT_CHUNK_LOAD_TIMEOUT);
}

/**
Waits for all chunks that will be downloaded from the server to be downloaded. After this, methods such as
* {@link ClientWorld#getChunk(int, int)} and {@link ClientWorld#getBlockState(BlockPos)} will return the expected
* value. However, the chunks may not yet be rendered and may not appear in screenshots, if you need this, use
* {@link #waitForChunksRender(int)} instead. Fails if the chunks haven't been downloaded after {@code timeout}
* ticks.
*
* @param timeout The number of ticks before timing out
* @return The number of ticks waited
*/
int waitForChunksDownload(int timeout);

/**
* Waits for all chunks to be downloaded and rendered. After this, all chunks that will ever be visible are visible
* in screenshots. Fails if the chunks haven't been downloaded and rendered after
* {@link #DEFAULT_CHUNK_LOAD_TIMEOUT} ticks.
*
* @return The number of ticks waited
*/
default int waitForChunksRender() {
return waitForChunksRender(DEFAULT_CHUNK_LOAD_TIMEOUT);
}

/**
* Waits for all chunks to be downloaded and rendered. After this, all chunks that will ever be visible are visible
* in screenshots. Fails if the chunks haven't been downloaded and rendered after {@code timeout} ticks.
*
* @param timeout The number of ticks before timing out
* @return The number of ticks waited
*/
default int waitForChunksRender(int timeout) {
return waitForChunksRender(true, timeout);
}

/**
* Waits for all chunks to be rendered, optionally waiting for chunks to be downloaded first. After this, all chunks
* that are present in the client world will be visible in screenshots. Fails if the chunks haven't been rendered
* (and optionally downloaded) after {@link #DEFAULT_CHUNK_LOAD_TIMEOUT} ticks.
*
* @param waitForDownload Whether to wait for chunks to be downloaded
* @return The number of ticks waited
*/
default int waitForChunksRender(boolean waitForDownload) {
return waitForChunksRender(waitForDownload, DEFAULT_CHUNK_LOAD_TIMEOUT);
}

/**
* Waits for all chunks to be rendered, optionally waiting for chunks to be downloaded first. After this, all chunks
* that are present in the client world will be visible in screenshots. Fails if the chunks haven't been rendered
* (and optionally downloaded) after {@code timeout} ticks.
*
* @param waitForDownload Whether to wait for chunks to be downloaded
* @param timeout The number of ticks before timing out
* @return The number of ticks waited
*/
int waitForChunksRender(boolean waitForDownload, int timeout);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.fabricmc.fabric.api.client.gametest.v1;

import org.jetbrains.annotations.ApiStatus;

/**
* Context for a client gametest containing various helpful functions while an in-process dedicated server is running.
* This class implements {@link AutoCloseable} and is intended to be used in a try-with-resources statement. When
* closed, the dedicated server will be stopped.
*
* <p>Functions in this class can only be called on the client gametest thread.
*/
@ApiStatus.NonExtendable
public interface TestDedicatedServerContext extends TestServerContext, AutoCloseable {
/**
* Connects the client to the dedicated server. The resulting connection is intended to be used in a
* try-with-resources statement.
*
* @return The connection handle to the dedicated server
*/
TestServerConnection connect();

/**
* Stops the dedicated server.
*/
@Override
void close();
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
* The client gametest input handler used to simulate inputs to the client.
*/
@ApiStatus.NonExtendable
public interface ClientGameTestInput {
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.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.fabricmc.fabric.api.client.gametest.v1;

import org.jetbrains.annotations.ApiStatus;

/**
* Context for a connection to a dedicated server containing various helpful functions while the connection is alive.
* This class implements {@link AutoCloseable} and is intended to be used in a try-with-resources statement. When
* closed, the client will be disconnected from the server.
*
* <p>Functions in this class can only be called on the client gametest thread.
*/
@ApiStatus.NonExtendable
public interface TestServerConnection extends AutoCloseable {
/**
* Gets the client world context for this connection.
*
* @return The client world context
*/
TestClientWorldContext getClientWorld();

/**
* Disconnects the client from the dedicated server.
*/
@Override
void close();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.fabricmc.fabric.api.client.gametest.v1;

import org.apache.commons.lang3.function.FailableConsumer;
import org.apache.commons.lang3.function.FailableFunction;
import org.jetbrains.annotations.ApiStatus;

import net.minecraft.server.MinecraftServer;

/**
* Context for a client gametest containing various helpful functions while a server (integrated or dedicated) is
* running.
*
* <p>Functions in this class can only be called on the client gametest thread.
*/
@ApiStatus.NonExtendable
public interface TestServerContext {
/**
* Runs a command on the server.
*
* @param command The command to run
*/
void runCommand(String command);

/**
* Runs the given action on the server thread, and waits for it to complete.
*
* @param action The action to run on the server thread
* @param <E> The type of the checked exception that the action throws
* @throws E When the action throws an exception
*/
<E extends Throwable> void runOnServer(FailableConsumer<MinecraftServer, E> action) throws E;

/**
* Runs the given function on the server thread, and returns the result.
*
* @param function The function to run on the server thread
* @return The result of the function
* @param <T> The type of the value to return
* @param <E> The type of the checked exception that the function throws
* @throws E When the function throws an exception
*/
<T, E extends Throwable> T computeOnServer(FailableFunction<MinecraftServer, T, E> function) throws E;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.fabricmc.fabric.api.client.gametest.v1;

import org.jetbrains.annotations.ApiStatus;

/**
* Context for a client gametest containing various helpful functions while a singleplayer game is open.
*
* <p>Functions in this class can only be called on the client gametest thread.
*/
@ApiStatus.NonExtendable
public interface TestSingleplayerContext extends AutoCloseable {
/**
* Gets the handle for the world save.
*
* @return The handle for the world save
*/
TestWorldSave getWorldSave();

/**
* Gets the handle for the client world.
*
* @return The handle for the client world
*/
TestClientWorldContext getClientWorld();

/**
* Gets the handle for the integrated server.
*
* @return The handle for the integrated server
*/
TestServerContext getServer();

/**
* Closes the singleplayer world.
*/
@Override
void close();
}
Loading

0 comments on commit 99ff640

Please sign in to comment.