summary refs log tree commit diff stats
path: root/src/main/java/ganarchy/friendcode
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/ganarchy/friendcode')
-rw-r--r--src/main/java/ganarchy/friendcode/client/FriendCodeScreen.java152
-rw-r--r--src/main/java/ganarchy/friendcode/client/I2PSamPinger.java6
-rw-r--r--src/main/java/ganarchy/friendcode/client/WaitingForFriendCodeScreen.java16
-rw-r--r--src/main/java/ganarchy/friendcode/util/KeyUtil.java19
4 files changed, 123 insertions, 70 deletions
diff --git a/src/main/java/ganarchy/friendcode/client/FriendCodeScreen.java b/src/main/java/ganarchy/friendcode/client/FriendCodeScreen.java
index 4bd4971..9c96bee 100644
--- a/src/main/java/ganarchy/friendcode/client/FriendCodeScreen.java
+++ b/src/main/java/ganarchy/friendcode/client/FriendCodeScreen.java
@@ -2,7 +2,8 @@ package ganarchy.friendcode.client;
 
 import ganarchy.friendcode.FriendCode;
 import ganarchy.friendcode.mixin.FriendCodeIntegratedServerExt;
-import ganarchy.friendcode.util.KeyUtil;import net.fabricmc.api.EnvType;
+import ganarchy.friendcode.util.KeyUtil;
+import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.gui.screen.OpenToLanScreen;
@@ -15,7 +16,8 @@ import net.minecraft.screen.ScreenTexts;
 import net.minecraft.server.network.ServerPlayerEntity;
 import net.minecraft.text.MutableText;
 import net.minecraft.text.Text;
-import net.minecraft.util.WorldSavePath;import net.minecraft.world.GameMode;
+import net.minecraft.util.WorldSavePath;
+import net.minecraft.world.GameMode;
 
 import java.io.IOException;
 
@@ -52,57 +54,57 @@ public class FriendCodeScreen extends Screen {
         // 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;
-                }
-            )
+                .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;
-                }
-            )
+                .onOffBuilder(this.allowCommands)
+                .build(
+                    this.width / 2 + 5,
+                    100,
+                    150,
+                    20,
+                    ALLOW_COMMANDS_TEXT,
+                    (button, allowCommands) -> {
+                        this.allowCommands = allowCommands;
+                    }
+                )
         );
 
         // friend code type button
         this.addDrawableChild(
             CyclingButtonWidget
-            .builder(CodeType::getSimpleTranslatableName)
-            .values(CodeType.SESSION, CodeType.WORLD)
-            .initially(this.codeType)
-            .build(
-                this.width / 2 - 155,
-                125,
-                310,
-                20,
-                CODE_TYPE_TEXT,
-                (button, codeType) -> {
-                    this.codeType = codeType;
-                }
-            )
-        ).active = false;
+                .builder(CodeType::getSimpleTranslatableName)
+                .values(CodeType.SESSION, CodeType.WORLD)
+                .initially(this.codeType)
+                .build(
+                    this.width / 2 - 155,
+                    125,
+                    310,
+                    20,
+                    CODE_TYPE_TEXT,
+                    (button, codeType) -> {
+                        this.codeType = codeType;
+                    }
+                )
+        );
 
         // start sharing
         this.addDrawableChild(new ButtonWidget(
@@ -112,13 +114,22 @@ public class FriendCodeScreen extends Screen {
             20,
             START_SHARING,
             button -> {
-                // FIXME
                 int i = NetworkUtils.findLocalPort();
-                var samPinger = openToFriends(this.client, this.codeType, this.gameMode, this.allowCommands, i);
-                MutableText text = samPinger != null ? Text.translatable("commands.publish.started", i) : Text.translatable("commands.publish.failed");
+                var samPinger = openToFriends(
+                    this.client, this.codeType, this.gameMode,
+                    this.allowCommands, i
+                );
+                MutableText text;
+                if (samPinger != null) {
+                    text = Text.translatable("commands.publish.started", i);
+                } else {
+                    text = Text.translatable("commands.publish.failed");
+                }
                 this.client.inGameHud.getChatHud().addMessage(text);
                 this.client.updateWindowTitle();
-                this.client.setScreen(new WaitingForFriendCodeScreen(samPinger));
+                this.client.setScreen(new WaitingForFriendCodeScreen(
+                    this.codeType, samPinger
+                ));
             }
         ));
 
@@ -133,41 +144,52 @@ public class FriendCodeScreen extends Screen {
         ));
     }
 
-    private static I2PSamPinger openToFriends(MinecraftClient client, CodeType codeType, GameMode gameMode, boolean allowCommands, int port) {
+    private static I2PSamPinger openToFriends(
+        MinecraftClient client, CodeType codeType, GameMode gameMode,
+        boolean allowCommands, int port
+    ) {
         try {
+            var server = client.getServer();
             String privateKey = null;
             if (codeType == CodeType.WORLD) {
-                // FIXME this currently does nothing.
-                var worldDir = client.getServer().submit(() -> client.getServer().getSavePath(WorldSavePath.ROOT)).join();
+                var worldDir = server.submit(() -> {
+                    return server.getSavePath(WorldSavePath.ROOT);
+                }).join();
                 var keyFile = worldDir.resolve("friendcode.key");
                 privateKey = KeyUtil.readKeyFile(keyFile);
             }
             client.loadBlockList();
-            client.getServer().getNetworkIo().bind(null, port);
+            server.getNetworkIo().bind(null, port);
             FriendCode.LOGGER.info("Started serving on {}", port);
-            ((FriendCodeIntegratedServerExt) client.getServer()).lanPort(port);
+            ((FriendCodeIntegratedServerExt) server).lanPort(port);
             // reuse LAN pinger machinery instead of rolling our own
-            var lanPinger = new I2PSamPinger(client.getServer().getServerMotd(), "" + port, privateKey);
-            ((FriendCodeIntegratedServerExt) client.getServer()).lanPinger(lanPinger);
+            var lanPinger = new I2PSamPinger(
+                server.getServerMotd(), "" + port, privateKey
+            );
+            ((FriendCodeIntegratedServerExt) server).lanPinger(lanPinger);
             lanPinger.start();
-            ((FriendCodeIntegratedServerExt) client.getServer()).forcedGameMode(gameMode);
-            client.getServer().getPlayerManager().setCheatsAllowed(allowCommands);
-            int i = client.getServer().getPermissionLevel(client.player.getGameProfile());
+            ((FriendCodeIntegratedServerExt) server).forcedGameMode(gameMode);
+            server.getPlayerManager().setCheatsAllowed(allowCommands);
+            int i = server.getPermissionLevel(client.player.getGameProfile());
             client.player.setClientPermissionLevel(i);
-            for (ServerPlayerEntity serverPlayerEntity : client.getServer().getPlayerManager().getPlayerList()) {
-                client.getServer().getCommandManager().sendCommandTree(serverPlayerEntity);
+            for (var player : server.getPlayerManager().getPlayerList()) {
+                server.getCommandManager().sendCommandTree(player);
             }
             return lanPinger;
-        }
-        catch (IOException iOException) {
+        } catch (IOException iOException) {
             return null;
         }
     }
 
     @Override
-    public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
+    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);
+        FriendCodeScreen.drawCenteredText(
+            matrices, this.textRenderer, OTHER_PLAYERS_TEXT,
+            this.width / 2, 82, 0xFFFFFF
+        );
         super.render(matrices, mouseX, mouseY, delta);
     }
 }
diff --git a/src/main/java/ganarchy/friendcode/client/I2PSamPinger.java b/src/main/java/ganarchy/friendcode/client/I2PSamPinger.java
index e0824b9..9bc46e2 100644
--- a/src/main/java/ganarchy/friendcode/client/I2PSamPinger.java
+++ b/src/main/java/ganarchy/friendcode/client/I2PSamPinger.java
@@ -95,7 +95,7 @@ public class I2PSamPinger extends LanServerPinger implements LanSendPing {
         return this.status;
     }
 
-    public String pubkey() {
+    public String publicKey() {
         return this.sam.publicKey();
     }
 
@@ -103,6 +103,10 @@ public class I2PSamPinger extends LanServerPinger implements LanSendPing {
         this.stopSam = true;
     }
 
+    public String privateKey() {
+        return this.sam.privateKey();
+    }
+
     public enum Status {
         IDLE,
         RUNNING,
diff --git a/src/main/java/ganarchy/friendcode/client/WaitingForFriendCodeScreen.java b/src/main/java/ganarchy/friendcode/client/WaitingForFriendCodeScreen.java
index 8429a41..79c12f7 100644
--- a/src/main/java/ganarchy/friendcode/client/WaitingForFriendCodeScreen.java
+++ b/src/main/java/ganarchy/friendcode/client/WaitingForFriendCodeScreen.java
@@ -1,5 +1,7 @@
 package ganarchy.friendcode.client;
 
+import ganarchy.friendcode.FriendCode;
+import ganarchy.friendcode.util.KeyUtil;
 import net.minecraft.client.gui.screen.LoadingDisplay;
 import net.minecraft.client.gui.screen.Screen;
 import net.minecraft.client.gui.widget.ButtonWidget;
@@ -8,6 +10,7 @@ import net.minecraft.screen.ScreenTexts;
 import net.minecraft.text.MutableText;
 import net.minecraft.text.Text;
 import net.minecraft.util.Util;
+import net.minecraft.util.WorldSavePath;
 import org.apache.commons.codec.binary.Base32;
 
 import java.nio.charset.StandardCharsets;
@@ -18,9 +21,11 @@ import java.util.Locale;
 
 public class WaitingForFriendCodeScreen extends Screen {
     private final I2PSamPinger samPinger;
+    private final CodeType codeType;
 
-    public WaitingForFriendCodeScreen(I2PSamPinger samPinger) {
+    public WaitingForFriendCodeScreen(CodeType codeType, I2PSamPinger samPinger) {
         super(Text.translatable("friendcode.opening"));
+        this.codeType = codeType;
         this.samPinger = samPinger;
     }
 
@@ -71,8 +76,15 @@ public class WaitingForFriendCodeScreen extends Screen {
                     break;
                 }
                 case RUNNING -> {
+                    if (codeType == CodeType.WORLD) {
+                        var worldDir = client.getServer().submit(() -> client.getServer().getSavePath(WorldSavePath.ROOT)).join();
+                        var keyFile = worldDir.resolve("friendcode.key");
+                        if (!KeyUtil.writeKeyFile(keyFile, samPinger.privateKey())) {
+                            FriendCode.LOGGER.error("Couldn't save world code. It will be regenerated next time.");
+                        }
+                    }
                     // convert from I2P base64 to URL-safe base64 so we don't have to write our own Base64 decoder
-                    final String pubkey_b64 = samPinger.pubkey().replace('~', '_');
+                    final String pubkey_b64 = samPinger.publicKey().replace('~', '_');
                     final byte[] pubkey = Base64.getUrlDecoder().decode(pubkey_b64.getBytes(StandardCharsets.UTF_8));
                     // a .b32.i2p is just a Base32-encoded SHA256
                     final String b32;
diff --git a/src/main/java/ganarchy/friendcode/util/KeyUtil.java b/src/main/java/ganarchy/friendcode/util/KeyUtil.java
index e8e07e5..ab5d614 100644
--- a/src/main/java/ganarchy/friendcode/util/KeyUtil.java
+++ b/src/main/java/ganarchy/friendcode/util/KeyUtil.java
@@ -3,12 +3,27 @@ package ganarchy.friendcode.util;
 import java.nio.file.Path;
 
 /**
-* Helper to deal with private keys.
-*/
+ * Helper to deal with private keys.
+ */
 public class KeyUtil {
+    /**
+     * Reads and decrypts a private key file.
+     *
+     * @param keyFile The path to the key file.
+     * @return The decrypted private key, or null if it doesn't exist.
+     */
     public static String readKeyFile(Path keyFile) {
         return null;
     }
+
+
+    /**
+     * Encrypts and writes a private key file.
+     *
+     * @param keyFile The path to the key file.
+     * @param key     The private key.
+     * @return Whether writing the key succeeded.
+     */
     public static boolean writeKeyFile(Path keyFile, String key) {
         return false;
     }