mirror of
https://github.com/FabricMC/fabric.git
synced 2025-02-17 04:01:46 -05:00
Join a dedicated server in the automated client test. (#4057)
* Join a dedicated server in the automated client test. * Add missing header
This commit is contained in:
parent
6c0945c34f
commit
f14f8b05a9
5 changed files with 187 additions and 0 deletions
|
@ -18,6 +18,7 @@ package net.fabricmc.fabric.test.base.client;
|
|||
|
||||
import static net.fabricmc.fabric.test.base.client.FabricClientTestHelper.clickScreenButton;
|
||||
import static net.fabricmc.fabric.test.base.client.FabricClientTestHelper.closeScreen;
|
||||
import static net.fabricmc.fabric.test.base.client.FabricClientTestHelper.connectToServer;
|
||||
import static net.fabricmc.fabric.test.base.client.FabricClientTestHelper.enableDebugHud;
|
||||
import static net.fabricmc.fabric.test.base.client.FabricClientTestHelper.openGameMenu;
|
||||
import static net.fabricmc.fabric.test.base.client.FabricClientTestHelper.openInventory;
|
||||
|
@ -34,11 +35,15 @@ import java.nio.file.DirectoryStream;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import org.spongepowered.asm.mixin.MixinEnvironment;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.AccessibilityOnboardingScreen;
|
||||
import net.minecraft.client.gui.screen.ConfirmScreen;
|
||||
import net.minecraft.client.gui.screen.ReconfiguringScreen;
|
||||
import net.minecraft.client.gui.screen.TitleScreen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
|
||||
import net.minecraft.client.gui.screen.world.CreateWorldScreen;
|
||||
import net.minecraft.client.gui.screen.world.SelectWorldScreen;
|
||||
import net.minecraft.client.option.Perspective;
|
||||
|
@ -114,6 +119,7 @@ public class FabricApiAutoTestClient implements ClientModInitializer {
|
|||
// See if the player render events are working.
|
||||
setPerspective(Perspective.THIRD_PERSON_BACK);
|
||||
takeScreenshot("in_game_overworld_third_person");
|
||||
setPerspective(Perspective.FIRST_PERSON);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -126,6 +132,34 @@ public class FabricApiAutoTestClient implements ClientModInitializer {
|
|||
openGameMenu();
|
||||
takeScreenshot("game_menu");
|
||||
clickScreenButton("menu.returnToMenu");
|
||||
waitForScreen(TitleScreen.class);
|
||||
}
|
||||
|
||||
try (var server = new TestDedicatedServer()) {
|
||||
connectToServer(server);
|
||||
waitForWorldTicks(5);
|
||||
|
||||
final GameProfile profile = submitAndWait(MinecraftClient::getGameProfile);
|
||||
server.runCommand("op " + profile.getName());
|
||||
server.runCommand("gamemode creative " + profile.getName());
|
||||
|
||||
waitForWorldTicks(20);
|
||||
takeScreenshot("server_in_game");
|
||||
|
||||
{ // Test that we can enter and exit configuration
|
||||
server.runCommand("debugconfig config " + profile.getName());
|
||||
waitForScreen(ReconfiguringScreen.class);
|
||||
takeScreenshot("server_config");
|
||||
server.runCommand("debugconfig unconfig " + profile.getId());
|
||||
waitForWorldTicks(1);
|
||||
}
|
||||
|
||||
openGameMenu();
|
||||
takeScreenshot("server_game_menu");
|
||||
clickScreenButton("menu.disconnect");
|
||||
|
||||
waitForScreen(MultiplayerScreen.class);
|
||||
clickScreenButton("gui.back");
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -29,12 +29,15 @@ import net.minecraft.client.gui.screen.GameMenuScreen;
|
|||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
|
||||
import net.minecraft.client.gui.screen.ingame.InventoryScreen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.ConnectScreen;
|
||||
import net.minecraft.client.gui.screen.world.LevelLoadingScreen;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.gui.widget.ClickableWidget;
|
||||
import net.minecraft.client.gui.widget.CyclingButtonWidget;
|
||||
import net.minecraft.client.gui.widget.PressableWidget;
|
||||
import net.minecraft.client.gui.widget.Widget;
|
||||
import net.minecraft.client.network.ServerAddress;
|
||||
import net.minecraft.client.network.ServerInfo;
|
||||
import net.minecraft.client.option.Perspective;
|
||||
import net.minecraft.client.util.ScreenshotRecorder;
|
||||
import net.minecraft.text.Text;
|
||||
|
@ -155,6 +158,14 @@ public final class FabricClientTestHelper {
|
|||
});
|
||||
}
|
||||
|
||||
public static void connectToServer(TestDedicatedServer server) {
|
||||
submitAndWait(client -> {
|
||||
final var serverInfo = new ServerInfo("localhost", server.getConnectionAddress(), ServerInfo.ServerType.OTHER);
|
||||
ConnectScreen.connect(client.currentScreen, client, ServerAddress.parse(server.getConnectionAddress()), serverInfo, false, null);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private static void waitFor(String what, Predicate<MinecraftClient> predicate) {
|
||||
waitFor(what, predicate, Duration.ofSeconds(10));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* 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.test.base.client;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.minecraft.server.Main;
|
||||
import net.minecraft.server.dedicated.MinecraftDedicatedServer;
|
||||
|
||||
public class TestDedicatedServer implements Closeable {
|
||||
public static final AtomicReference<MinecraftDedicatedServer> DEDICATED_SERVER_REF = new AtomicReference<>();
|
||||
private static final Duration START_TIMEOUT = Duration.ofMinutes(5);
|
||||
|
||||
final ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
MinecraftDedicatedServer server;
|
||||
|
||||
public TestDedicatedServer() {
|
||||
assert DEDICATED_SERVER_REF.get() == null : "A dedicated server is already running";
|
||||
executor.execute(this::run);
|
||||
waitUntilReady();
|
||||
Objects.requireNonNull(server);
|
||||
}
|
||||
|
||||
public String getConnectionAddress() {
|
||||
return "localhost:" + server.getServerPort();
|
||||
}
|
||||
|
||||
public void runCommand(String command) {
|
||||
submitAndWait(server -> {
|
||||
server.enqueueCommand(command, server.getCommandSource());
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private void run() {
|
||||
setupServer();
|
||||
Main.main(new String[]{});
|
||||
}
|
||||
|
||||
private <T> CompletableFuture<T> submit(Function<MinecraftDedicatedServer, T> function) {
|
||||
return server.submit(() -> function.apply(server));
|
||||
}
|
||||
|
||||
private <T> T submitAndWait(Function<MinecraftDedicatedServer, T> function) {
|
||||
return submit(function).join();
|
||||
}
|
||||
|
||||
private void setupServer() {
|
||||
try {
|
||||
Files.writeString(Paths.get("eula.txt"), "eula=true");
|
||||
Files.writeString(Paths.get("server.properties"), "online-mode=false");
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void waitUntilReady() {
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
while (DEDICATED_SERVER_REF.get() == null) {
|
||||
if (System.currentTimeMillis() - startTime > START_TIMEOUT.toMillis()) {
|
||||
throw new RuntimeException("Timeout while waiting for the server to start");
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
server = DEDICATED_SERVER_REF.get();
|
||||
DEDICATED_SERVER_REF.set(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
server.stop(true);
|
||||
executor.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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.test.base.client.mixin;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.server.dedicated.MinecraftDedicatedServer;
|
||||
|
||||
import net.fabricmc.fabric.test.base.client.TestDedicatedServer;
|
||||
|
||||
@Mixin(MinecraftDedicatedServer.class)
|
||||
public abstract class MinecraftDedicatedServerMixin {
|
||||
@Inject(method = "setupServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/dedicated/MinecraftDedicatedServer;loadWorld()V"))
|
||||
private void captureServerInstance(CallbackInfoReturnable<Boolean> cir) {
|
||||
// Capture the server instance once the server is ready to be connected to
|
||||
TestDedicatedServer.DEDICATED_SERVER_REF.set((MinecraftDedicatedServer) (Object) this);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
"compatibilityLevel": "JAVA_21",
|
||||
"client": [
|
||||
"CyclingButtonWidgetAccessor",
|
||||
"MinecraftDedicatedServerMixin",
|
||||
"ScreenAccessor"
|
||||
],
|
||||
"injectors": {
|
||||
|
|
Loading…
Reference in a new issue