summary refs log blame commit diff stats
path: root/src/main/java/ganarchy/friendcode/client/FriendCodeScreen.java
blob: 38703a5e938c02caefdeb1390202fccaf50d7fc9 (plain) (tree)












































































































































                                                                                                                                                       
package ganarchy.friendcode.client;

import ganarchy.friendcode.FriendCode;
import ganarchy.friendcode.mixin.FriendCodeIntegratedServerExt;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.OpenToLanScreen;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.CyclingButtonWidget;
import net.minecraft.client.util.NetworkUtils;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.screen.ScreenTexts;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.world.GameMode;

import java.io.IOException;

@Environment(EnvType.CLIENT)
public class FriendCodeScreen extends Screen {
    private static final Text ALLOW_COMMANDS_TEXT = Text.translatable("selectWorld.allowCommands");
    private static final Text GAME_MODE_TEXT = Text.translatable("selectWorld.gameMode");
    private static final Text OTHER_PLAYERS_TEXT = Text.translatable("lanServer.otherPlayers");
    private final Screen parent;
    private GameMode gameMode = GameMode.SURVIVAL;
    private boolean allowCommands;

    private static final Text START_SHARING = Text.translatable("friendcode.start");

    public FriendCodeScreen(Screen parent) {
        super(Text.translatable("friendcode.title"));
        this.parent = parent;
    }

    @Override
    protected void init() {
        // title button allows going back to LAN screen
        this.addDrawableChild(new ButtonWidget(
            this.width / 2 - 155,
            50,
            310,
            20,
            this.title,
            button -> this.client.setScreen(new OpenToLanScreen(this.parent))
        ));

        // game setting buttons
        this.addDrawableChild(
            CyclingButtonWidget
            .builder(GameMode::getSimpleTranslatableName)
            .values(GameMode.SURVIVAL, GameMode.SPECTATOR, GameMode.CREATIVE, GameMode.ADVENTURE)
            .initially(this.gameMode)
            .build(
                this.width / 2 - 155,
                100,
                150,
                20,
                GAME_MODE_TEXT,
                (button, gameMode) -> {
                    this.gameMode = gameMode;
                }
            )
        );
        this.addDrawableChild(
            CyclingButtonWidget
            .onOffBuilder(this.allowCommands)
            .build(
                this.width / 2 + 5,
                100,
                150,
                20,
                ALLOW_COMMANDS_TEXT,
                (button, allowCommands) -> {
                    this.allowCommands = allowCommands;
                }
            )
        );

        // start sharing
        this.addDrawableChild(new ButtonWidget(
            this.width / 2 - 155,
            this.height - 28,
            150,
            20,
            START_SHARING,
            button -> {
                // FIXME
                int i = NetworkUtils.findLocalPort();
                var samPinger = openToFriends(this.client, this.gameMode, this.allowCommands, i);
                MutableText text = samPinger != null ? Text.translatable("commands.publish.started", i) : Text.translatable("commands.publish.failed");
                this.client.inGameHud.getChatHud().addMessage(text);
                this.client.updateWindowTitle();
                this.client.setScreen(new WaitingForFriendCodeScreen(samPinger));
            }
        ));

        // go back to options
        this.addDrawableChild(new ButtonWidget(
            this.width / 2 + 5,
            this.height - 28,
            150,
            20,
            ScreenTexts.CANCEL,
            button -> this.client.setScreen(this.parent)
        ));
    }

    private static I2PSamPinger openToFriends(MinecraftClient client, GameMode gameMode, boolean allowCommands, int port) {
        try {
            client.loadBlockList();
            client.getServer().getNetworkIo().bind(null, port);
            FriendCode.LOGGER.info("Started serving on {}", port);
            ((FriendCodeIntegratedServerExt) client.getServer()).lanPort(port);
            // reuse LAN pinger machinery instead of rolling our own
            var lanPinger = new I2PSamPinger(client.getServer().getServerMotd(), "" + port);
            ((FriendCodeIntegratedServerExt) client.getServer()).lanPinger(lanPinger);
            lanPinger.start();
            ((FriendCodeIntegratedServerExt) client.getServer()).forcedGameMode(gameMode);
            client.getServer().getPlayerManager().setCheatsAllowed(allowCommands);
            int i = client.getServer().getPermissionLevel(client.player.getGameProfile());
            client.player.setClientPermissionLevel(i);
            for (ServerPlayerEntity serverPlayerEntity : client.getServer().getPlayerManager().getPlayerList()) {
                client.getServer().getCommandManager().sendCommandTree(serverPlayerEntity);
            }
            return lanPinger;
        }
        catch (IOException iOException) {
            return null;
        }
    }

    @Override
    public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
        this.renderBackground(matrices);
        FriendCodeScreen.drawCenteredText(matrices, this.textRenderer, OTHER_PLAYERS_TEXT, this.width / 2, 82, 0xFFFFFF);
        super.render(matrices, mouseX, mouseY, delta);
    }
}