From 659827bcc372d8f404a20a9283b09d20a4aa8ab3 Mon Sep 17 00:00:00 2001 From: wangsj <3305688534@qq.com> Date: Wed, 24 Sep 2025 20:07:32 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=80=E4=B8=AA=E9=87=8C=E7=A8=8B=E7=A2=91?= =?UTF-8?q?=EF=BC=88=E5=8F=AF=E4=BB=A5=E8=81=94=E6=9C=BA=E4=BA=86=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/uno/mloluyu/characters/Alice.java | 34 +++-- .../java/uno/mloluyu/characters/Fighter.java | 88 ++++++------ .../desktop/CharacterSelectScreen.java | 17 ++- .../java/uno/mloluyu/desktop/GameScreen.java | 83 +++++++---- .../desktop/NetworkSettingsScreen.java | 40 +++--- .../uno/mloluyu/network/ConnectClient.java | 48 +++---- .../uno/mloluyu/network/ConnectServer.java | 124 ++++------------ .../uno/mloluyu/network/NetworkManager.java | 136 +++++++++++------- .../uno/mloluyu/characters/Alice.class | Bin 2346 -> 2412 bytes .../mloluyu/characters/Fighter$Action.class | Bin 1724 -> 1724 bytes .../uno/mloluyu/characters/Fighter.class | Bin 10807 -> 11445 bytes .../uno/mloluyu/characters/Reimu.class | Bin 2358 -> 1984 bytes .../desktop/CharacterSelectScreen.class | Bin 7118 -> 7599 bytes .../uno/mloluyu/desktop/GameScreen.class | Bin 3684 -> 3951 bytes .../desktop/NetworkSettingsScreen$1.class | Bin 3094 -> 2796 bytes .../desktop/NetworkSettingsScreen.class | Bin 5650 -> 5583 bytes .../uno/mloluyu/network/ConnectClient.class | Bin 4049 -> 4074 bytes .../network/ConnectServer$Player.class | Bin 1403 -> 0 bytes .../uno/mloluyu/network/ConnectServer.class | Bin 6909 -> 5598 bytes .../uno/mloluyu/network/NetworkManager.class | Bin 3395 -> 5466 bytes 20 files changed, 282 insertions(+), 288 deletions(-) delete mode 100644 target/classes/uno/mloluyu/network/ConnectServer$Player.class diff --git a/src/main/java/uno/mloluyu/characters/Alice.java b/src/main/java/uno/mloluyu/characters/Alice.java index 3ca864e..c2109fa 100644 --- a/src/main/java/uno/mloluyu/characters/Alice.java +++ b/src/main/java/uno/mloluyu/characters/Alice.java @@ -9,7 +9,7 @@ import com.badlogic.gdx.graphics.g2d.TextureAtlas; public class Alice extends Fighter { public Alice() { - super(new TextureAtlas(Gdx.files.internal("src/main/resources/character/alice/精灵1.2.atlas"))); + super("Alice", new TextureAtlas(Gdx.files.internal("src/main/resources/character/alice/精灵1.2.atlas"))); // 设置角色属性 speed = 350f; // 更快的移动速度 @@ -20,22 +20,27 @@ public class Alice extends Fighter { @Override protected void loadAnimations() { - // 加载基础动作动画 - loadAnimationFromAtlas(Action.IDLE, "stand/stand", 15, true); - loadAnimationFromAtlas(Action.WALK, "walkFront/walkFront", 9, true); - loadAnimationFromAtlas(Action.JUMP, "jump/jump", 8, false); - loadAnimationFromAtlas(Action.FALL, "hitSpin/hitSpin", 5, false); + // 基础动作 + loadLoopingAnimation(Action.IDLE, "stand/stand", 15); + loadLoopingAnimation(Action.WALK, "walkFront/walkFront", 9); + loadOneShotAnimation(Action.JUMP, "jump/jump", 8); + loadOneShotAnimation(Action.FALL, "hitSpin/hitSpin", 5); - // 加载攻击动作动画 - loadAnimationFromAtlas(Action.ATTACK1, "attackAa/attackAa", 6, false); - loadAnimationFromAtlas(Action.ATTACK2, "attackAb/attackAb", 6, false); - loadAnimationFromAtlas(Action.ATTACK3, "attackAc/attackAc", 6, false); - loadAnimationFromAtlas(Action.ATTACK4, "attackAd/attackAd", 6, false); + // 攻击动作 + loadOneShotAnimation(Action.ATTACK1, "attackAa/attackAa", 6); + loadOneShotAnimation(Action.ATTACK2, "attackAb/attackAb", 6); + loadOneShotAnimation(Action.ATTACK3, "attackAc/attackAc", 6); + loadOneShotAnimation(Action.ATTACK4, "attackAd/attackAd", 6); - // 加载受击动画 - loadAnimationFromAtlas(Action.HIT, "hitSpin/hitSpin", 5, false); + // // 特殊动作(可扩展) + // loadOneShotAnimation(Action.SPECIAL1, "special/special1", 6); + // loadOneShotAnimation(Action.SPECIAL2, "special/special2", 6); - // 设置帧间隔(动作速度) + // 受击与死亡 + loadOneShotAnimation(Action.HIT, "hitSpin/hitSpin", 5); + // loadOneShotAnimation(Action.DEATH, "death/death", 8); + + // 帧速率调整 setFrameDuration(Action.IDLE, 0.04f); setFrameDuration(Action.WALK, 0.08f); setFrameDuration(Action.ATTACK1, 0.07f); @@ -50,6 +55,7 @@ public class Alice extends Fighter { if (currentAction != Action.ATTACK1 && currentAction != Action.ATTACK2 && currentAction != Action.ATTACK3 && + currentAction != Action.ATTACK4 && currentAction != Action.SPECIAL1 && currentAction != Action.SPECIAL2 && currentAction != Action.DEFEND && diff --git a/src/main/java/uno/mloluyu/characters/Fighter.java b/src/main/java/uno/mloluyu/characters/Fighter.java index 3e9e589..a8f0791 100644 --- a/src/main/java/uno/mloluyu/characters/Fighter.java +++ b/src/main/java/uno/mloluyu/characters/Fighter.java @@ -1,21 +1,14 @@ package uno.mloluyu.characters; -import uno.mloluyu.util.SimpleFormatter; - import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.graphics.g2d.Animation; -import com.badlogic.gdx.graphics.g2d.SpriteBatch; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import com.badlogic.gdx.graphics.g2d.TextureRegion; -import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.graphics.g2d.*; import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Disposable; +import uno.mloluyu.util.SimpleFormatter; import java.util.EnumMap; -/** - * 格斗角色父类,封装所有角色共有的动画和状态管理逻辑 - */ public abstract class Fighter implements Disposable { public enum Action { @@ -51,10 +44,10 @@ public abstract class Fighter implements Disposable { protected float scaleX = 1.0f; protected float scaleY = 1.0f; - public Fighter() { - } + public Fighter() {} - public Fighter(TextureAtlas atlas) { + public Fighter(String name, TextureAtlas atlas) { + this.name = name; this.atlas = atlas; for (Action action : Action.values()) { frameDurations.put(action, DEFAULT_FRAME_DURATION); @@ -85,6 +78,14 @@ public abstract class Fighter implements Disposable { animations.put(action, animation); } + protected void loadLoopingAnimation(Action action, String prefix, int count) { + loadAnimationFromAtlas(action, prefix, count, true); + } + + protected void loadOneShotAnimation(Action action, String prefix, int count) { + loadAnimationFromAtlas(action, prefix, count, false); + } + protected void setFrameDuration(Action action, float duration) { frameDurations.put(action, duration); Animation anim = animations.get(action); @@ -103,23 +104,12 @@ public abstract class Fighter implements Disposable { } protected void handleAnimationTransitions() { - if (!isAnimationFinished) - return; + if (!isAnimationFinished) return; switch (currentAction) { - case ATTACK1: - case ATTACK2: - case ATTACK3: - case SPECIAL1: - case SPECIAL2: - case HIT: - changeAction(Action.IDLE); - break; - case JUMP: - changeAction(Action.FALL); - break; - default: - break; + case ATTACK1, ATTACK2, ATTACK3, SPECIAL1, SPECIAL2, HIT -> changeAction(Action.IDLE); + case JUMP -> changeAction(Action.FALL); + default -> {} } } @@ -150,8 +140,7 @@ public abstract class Fighter implements Disposable { } public boolean changeAction(Action newAction) { - if (isActionUninterruptible(currentAction)) - return false; + if (isActionUninterruptible(currentAction)) return false; if (currentAction != newAction) { currentAction = newAction; stateTime = 0f; @@ -182,18 +171,17 @@ public abstract class Fighter implements Disposable { protected void handleMoveState() { if (!isActionUninterruptible(currentAction) && - currentAction != Action.JUMP && - currentAction != Action.FALL && - currentAction != Action.DEFEND && - !currentAction.name().startsWith("ATTACK") && - !currentAction.name().startsWith("SPECIAL")) { + currentAction != Action.JUMP && + currentAction != Action.FALL && + currentAction != Action.DEFEND && + !currentAction.name().startsWith("ATTACK") && + !currentAction.name().startsWith("SPECIAL")) { changeAction(Action.WALK); } } public boolean attack(int attackType) { - if (!canAttack()) - return false; + if (!canAttack()) return false; Action attackAction = switch (attackType) { case 1 -> Action.ATTACK1; @@ -212,13 +200,24 @@ public abstract class Fighter implements Disposable { } public void takeHit(int damage) { - if (currentAction == Action.DEATH) - return; + if (currentAction == Action.DEATH) return; health = Math.max(0, health - damage); changeAction(health == 0 ? Action.DEATH : Action.HIT); } + public void setPosition(float x, float y) { + hitbox.setPosition(x, y); + } + + public void setFacingRight(boolean facingRight) { + this.isFacingRight = facingRight; + } + + public String getName() { + return name; + } + public Rectangle getHitbox() { return hitbox; } @@ -235,12 +234,6 @@ public abstract class Fighter implements Disposable { return health; } - @Override - public void dispose() { - if (atlas != null) - atlas.dispose(); - } - public Action getCurrentAction() { return currentAction; } @@ -260,4 +253,9 @@ public abstract class Fighter implements Disposable { public float getCenterY() { return hitbox.y + hitbox.height / 2; } + + @Override + public void dispose() { + if (atlas != null) atlas.dispose(); + } } diff --git a/src/main/java/uno/mloluyu/desktop/CharacterSelectScreen.java b/src/main/java/uno/mloluyu/desktop/CharacterSelectScreen.java index 365f128..ea414ed 100644 --- a/src/main/java/uno/mloluyu/desktop/CharacterSelectScreen.java +++ b/src/main/java/uno/mloluyu/desktop/CharacterSelectScreen.java @@ -1,5 +1,8 @@ package uno.mloluyu.desktop; +import java.util.UUID; +import uno.mloluyu.network.NetworkManager; + import com.badlogic.gdx.Gdx; import com.badlogic.gdx.ScreenAdapter; import com.badlogic.gdx.graphics.Color; @@ -141,6 +144,7 @@ public class CharacterSelectScreen extends ScreenAdapter { } } + // 点击确认按钮 // 点击确认按钮 if (isHovered(mouseX, mouseY, BUTTON_X, CONFIRM_Y, BUTTON_WIDTH, BUTTON_HEIGHT)) { if (selectedIndex != -1) { @@ -155,12 +159,19 @@ public class CharacterSelectScreen extends ScreenAdapter { case "Reimu": fighter = new Reimu(); break; - // case "弓箭手": - // fighter = new Archer(); - // break; } if (fighter != null) { + if (multiplayerMode) { + // 设置唯一玩家 ID 并发送角色选择 + if (NetworkManager.getInstance().getLocalPlayerId() == null) { + String playerId = UUID.randomUUID().toString(); + NetworkManager.getInstance().setLocalPlayerId(playerId); + Gdx.app.log("Network", "设置玩家ID: " + playerId); + } + NetworkManager.getInstance().sendCharacterSelection(selectedCharacter); + } + game.setScreen(new GameScreen(game, fighter)); } } diff --git a/src/main/java/uno/mloluyu/desktop/GameScreen.java b/src/main/java/uno/mloluyu/desktop/GameScreen.java index 21f3ab9..45d26c3 100644 --- a/src/main/java/uno/mloluyu/desktop/GameScreen.java +++ b/src/main/java/uno/mloluyu/desktop/GameScreen.java @@ -1,30 +1,41 @@ package uno.mloluyu.desktop; +import java.util.HashMap; +import java.util.Map; + import com.badlogic.gdx.Gdx; import com.badlogic.gdx.ScreenAdapter; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; + +import uno.mloluyu.characters.Alice; import uno.mloluyu.characters.Fighter; +import uno.mloluyu.characters.Reimu; import uno.mloluyu.network.NetworkManager; import uno.mloluyu.util.ClearScreen; +import uno.mloluyu.versatile.FighterController; public class GameScreen extends ScreenAdapter { private final MainGame game; private final Fighter player; private SpriteBatch batch; private ShapeRenderer shapeRenderer; - + private FighterController controller; + private final Map otherPlayers = new HashMap<>(); + public GameScreen(MainGame game, Fighter player) { this.game = game; this.player = player; + this.controller = new FighterController(player); } @Override public void show() { batch = new SpriteBatch(); shapeRenderer = new ShapeRenderer(); + Gdx.input.setInputProcessor(controller); } @Override @@ -33,7 +44,7 @@ public class GameScreen extends ScreenAdapter { // 更新角色状态 player.update(delta); - + controller.update(delta); // 发送本机玩家位置 if (NetworkManager.getInstance().isConnected()) { NetworkManager.getInstance().sendPosition(player.getX(), player.getY()); @@ -42,40 +53,56 @@ public class GameScreen extends ScreenAdapter { // 渲染角色 batch.begin(); player.render(batch); - + batch.end(); // 渲染其他玩家位置(联机模式) if (NetworkManager.getInstance().isConnected()) { renderOtherPlayers(); } - - batch.end(); } - + private void renderOtherPlayers() { - // 获取其他玩家位置并渲染 - for (String position : NetworkManager.getInstance().getOtherPlayerPositions()) { - String[] coords = position.split(","); - if (coords.length == 2) { - try { - float x = Float.parseFloat(coords[0]); - float y = Float.parseFloat(coords[1]); - - // 使用形状渲染器绘制其他玩家标记 - shapeRenderer.begin(ShapeRenderer.ShapeType.Filled); - shapeRenderer.setColor(Color.RED); - shapeRenderer.circle(x, y, 20); // 红色圆圈表示其他玩家 - shapeRenderer.end(); - - // 在批处理中绘制文字 - batch.begin(); - // 这里可以添加玩家名字显示 - batch.end(); - - } catch (NumberFormatException e) { - Gdx.app.error("GameScreen", "解析玩家位置失败: " + position); + Map positions = NetworkManager.getInstance().getPlayerPositions(); + Map characters = NetworkManager.getInstance().getPlayerCharacters(); + + batch.begin(); + for (Map.Entry entry : positions.entrySet()) { + String playerId = entry.getKey(); + float[] pos = entry.getValue(); + + // 跳过本机玩家(可选) + // if (playerId.equals(NetworkManager.getInstance().getLocalPlayerId())) + // continue; + + // 获取角色名 + String characterName = characters.get(playerId); + if (characterName == null || pos == null) + continue; + + // 获取或创建 Fighter 实例 + Fighter fighter = otherPlayers.get(playerId); + if (fighter == null) { + switch (characterName) { + case "Alice": + fighter = new Alice(); + break; + case "Reimu": + fighter = new Reimu(); + default: + fighter = new Alice(); + break; + }; + if (fighter != null) { + otherPlayers.put(playerId, fighter); } } + + // 设置位置并渲染 + if (fighter != null) { + fighter.setPosition(pos[0], pos[1]); + fighter.render(batch); + } } + batch.end(); } @Override @@ -86,4 +113,4 @@ public class GameScreen extends ScreenAdapter { // 断开网络连接 NetworkManager.getInstance().disconnect(); } -} +} \ No newline at end of file diff --git a/src/main/java/uno/mloluyu/desktop/NetworkSettingsScreen.java b/src/main/java/uno/mloluyu/desktop/NetworkSettingsScreen.java index 1f31de7..5bd640a 100644 --- a/src/main/java/uno/mloluyu/desktop/NetworkSettingsScreen.java +++ b/src/main/java/uno/mloluyu/desktop/NetworkSettingsScreen.java @@ -8,8 +8,7 @@ import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.SpriteBatch; -import uno.mloluyu.network.ConnectClient; -import uno.mloluyu.network.ConnectServer; +import uno.mloluyu.network.NetworkManager; import static uno.mloluyu.util.Font.loadChineseFont; import uno.mloluyu.util.ClearScreen; @@ -24,7 +23,7 @@ public class NetworkSettingsScreen extends ScreenAdapter { private static final int BUTTON_X = 760; private static final int CREATE_ROOM_Y = 500; private static final int JOIN_ROOM_Y = 380; - private static final int EXIT_Y = 260; // 退出按钮位置 + private static final int EXIT_Y = 260; public NetworkSettingsScreen(MainGame game) { this.game = game; @@ -48,7 +47,6 @@ public class NetworkSettingsScreen extends ScreenAdapter { renderButtons(mouseX, mouseY); renderTexts(); - handleInput(mouseX, mouseY); } @@ -56,7 +54,7 @@ public class NetworkSettingsScreen extends ScreenAdapter { shapeRenderer.begin(ShapeRenderer.ShapeType.Filled); drawButton(CREATE_ROOM_Y, mouseX, mouseY); drawButton(JOIN_ROOM_Y, mouseX, mouseY); - drawButton(EXIT_Y, mouseX, mouseY); // 新增退出按钮 + drawButton(EXIT_Y, mouseX, mouseY); shapeRenderer.end(); } @@ -65,37 +63,36 @@ public class NetworkSettingsScreen extends ScreenAdapter { font.draw(batch, "联机设置", BUTTON_X + 100, 650); drawButtonText(CREATE_ROOM_Y, "创建房间"); drawButtonText(JOIN_ROOM_Y, "加入房间"); - drawButtonText(EXIT_Y, "返回"); // 新增退出按钮文字 + drawButtonText(EXIT_Y, "返回"); batch.end(); } private void handleInput(int mouseX, int mouseY) { if (Gdx.input.justTouched()) { + // 创建房间 if (isHovered(mouseX, mouseY, BUTTON_X, CREATE_ROOM_Y)) { Gdx.app.log("Network", "创建房间按钮被点击!"); - new Thread(new ConnectServer(11455)).start(); - // 添加服务器启动提示信息 - Gdx.app.log("Network", "服务器已启动,等待玩家连接..."); - System.out.println("服务器已启动,等待玩家连接..."); + NetworkManager.getInstance().createRoom(); + NetworkManager.getInstance().joinRoom("127.0.0.1"); - // 创建联机模式标识并传递到角色选择界面 + Gdx.app.log("Network", "已连接到本地服务器,等待其他玩家加入..."); CharacterSelectScreen characterSelectScreen = new CharacterSelectScreen(game); - characterSelectScreen.setMultiplayerMode(true); // 设置为联机模式 + characterSelectScreen.setMultiplayerMode(true); game.setScreen(characterSelectScreen); + } - } else if (isHovered(mouseX, mouseY, BUTTON_X, JOIN_ROOM_Y)) { + // 加入房间 + else if (isHovered(mouseX, mouseY, BUTTON_X, JOIN_ROOM_Y)) { Gdx.app.log("Network", "加入房间按钮被点击!"); - // 使用LibGDX的输入对话框避免AWT线程问题 + Gdx.input.getTextInput(new com.badlogic.gdx.Input.TextInputListener() { @Override public void input(String ip) { if (ip != null && !ip.trim().isEmpty()) { - new Thread(() -> new ConnectClient(ip.trim(), 11455)).start(); + NetworkManager.getInstance().joinRoom(ip.trim()); Gdx.app.log("Network", "正在连接到服务器 " + ip.trim() + "..."); - System.out.println("正在连接到服务器 " + ip.trim() + "..."); - // 使用postRunnable确保在主线程中执行屏幕切换 Gdx.app.postRunnable(() -> { CharacterSelectScreen characterSelectScreen = new CharacterSelectScreen(game); characterSelectScreen.setMultiplayerMode(true); @@ -109,10 +106,12 @@ public class NetworkSettingsScreen extends ScreenAdapter { Gdx.app.log("Network", "用户取消输入 IP"); } }, "请输入服务器 IP 地址", "", "加入房间"); + } - } else if (isHovered(mouseX, mouseY, BUTTON_X, EXIT_Y)) { + // 返回主菜单 + else if (isHovered(mouseX, mouseY, BUTTON_X, EXIT_Y)) { Gdx.app.log("Network", "退出按钮被点击!"); - game.setScreen(new MainMenuScreen(game)); // 或者 Gdx.app.exit(); 直接退出游戏 + game.setScreen(new MainMenuScreen(game)); } } } @@ -139,5 +138,4 @@ public class NetworkSettingsScreen extends ScreenAdapter { font.dispose(); shapeRenderer.dispose(); } - -} \ No newline at end of file +} diff --git a/src/main/java/uno/mloluyu/network/ConnectClient.java b/src/main/java/uno/mloluyu/network/ConnectClient.java index 105739d..a06dbe8 100644 --- a/src/main/java/uno/mloluyu/network/ConnectClient.java +++ b/src/main/java/uno/mloluyu/network/ConnectClient.java @@ -8,7 +8,7 @@ import java.io.OutputStream; import java.nio.charset.StandardCharsets; /** - * 客户端连接类(实例方式) + * 客户端连接类 */ public class ConnectClient { private Socket socket; @@ -20,48 +20,40 @@ public class ConnectClient { // 启动接收线程 new Thread(this::receiveMessages).start(); - - // 示例:发送一条欢迎消息 - sendMessage("你好,我是客户端玩家"); - } catch (Exception e) { Gdx.app.error("Client", "连接失败: " + e.getMessage(), e); } } - // ... 现有代码 ... + private void receiveMessages() { + try { + byte[] buffer = new byte[1024]; + while (true) { + int read = socket.getInputStream().read(buffer); + if (read == -1) + break; -private void receiveMessages() { - try { - byte[] buffer = new byte[1024]; - while (true) { - int read = socket.getInputStream().read(buffer); - if (read == -1) break; - String message = new String(buffer, 0, read, StandardCharsets.UTF_8); - Gdx.app.log("Client", "收到服务器消息: " + message); - - // 处理位置消息 - if (message.startsWith("POS:")) { - String positionData = message.substring(4); - // 通知网络管理器更新其他玩家位置 - NetworkManager.getInstance().updatePlayerPosition(positionData); + String message = new String(buffer, 0, read, StandardCharsets.UTF_8); + Gdx.app.log("Client", "收到服务器消息: " + message); + + // 主线程处理消息,避免线程冲突 + Gdx.app.postRunnable(() -> { + NetworkManager.getInstance().receiveMessage(message); + }); } + } catch (Exception e) { + Gdx.app.error("Client", "接收消息异常: " + e.getMessage(), e); + } finally { + disconnect(); } - } catch (Exception e) { - Gdx.app.error("Client", "接收消息异常: " + e.getMessage(), e); - } finally { - disconnect(); } -} - -// ... 现有代码 ... - public void sendMessage(String message) { try { OutputStream out = socket.getOutputStream(); out.write(message.getBytes(StandardCharsets.UTF_8)); out.flush(); + Gdx.app.log("Client", "发送消息: " + message); } catch (Exception e) { Gdx.app.error("Client", "发送消息失败: " + e.getMessage(), e); } diff --git a/src/main/java/uno/mloluyu/network/ConnectServer.java b/src/main/java/uno/mloluyu/network/ConnectServer.java index 2f16cb6..6919971 100644 --- a/src/main/java/uno/mloluyu/network/ConnectServer.java +++ b/src/main/java/uno/mloluyu/network/ConnectServer.java @@ -6,41 +6,16 @@ import com.badlogic.gdx.net.ServerSocket; import com.badlogic.gdx.net.Socket; import java.io.OutputStream; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; -/** - * 支持两个玩家连接的服务器类 - */ public class ConnectServer implements Runnable { private final int port; private ServerSocket serverSocket; - private final List connectedPlayers = new ArrayList<>(); + private final List connectedSockets = new ArrayList<>(); private static final int MAX_PLAYERS = 2; - // 玩家内部类,存储Socket和玩家名字 - private static class Player { - Socket socket; - String playerName; - - Player(Socket socket) { - this.socket = socket; - this.playerName = "玩家" + (int) (Math.random() * 1000); // 默认随机名字 - } - - String getPlayerName() { - return playerName; - } - - void setPlayerName(String name) { - this.playerName = name; - } - - Socket getSocket() { - return socket; - } - } - public ConnectServer(int port) { this.port = port; } @@ -51,106 +26,65 @@ public class ConnectServer implements Runnable { Gdx.app.log("Server", "服务器已启动,等待玩家连接..."); try { - while (connectedPlayers.size() < MAX_PLAYERS) { + while (connectedSockets.size() < MAX_PLAYERS) { Socket socket = serverSocket.accept(null); - Player player = new Player(socket); - connectedPlayers.add(player); - Gdx.app.log("Server", "玩家连接成功: " + socket.getRemoteAddress() + ",默认名字: " + player.getPlayerName()); - new Thread(() -> handlePlayer(player)).start(); + connectedSockets.add(socket); + Gdx.app.log("Server", "玩家连接成功: " + socket.getRemoteAddress()); + new Thread(() -> handlePlayer(socket)).start(); } Gdx.app.log("Server", "已连接两个玩家,游戏准备开始!"); - // 输出当前所有玩家名字 - for (int i = 0; i < connectedPlayers.size(); i++) { - Gdx.app.log("Server", "玩家" + (i + 1) + ": " + connectedPlayers.get(i).getPlayerName()); - } - } catch (Exception e) { Gdx.app.error("Server", "连接异常: " + e.getMessage(), e); } } - // ... 现有代码 ... - - private void handlePlayer(Player player) { + private void handlePlayer(Socket socket) { try { byte[] buffer = new byte[1024]; while (true) { - int read = player.getSocket().getInputStream().read(buffer); + int read = socket.getInputStream().read(buffer); if (read == -1) break; - String message = new String(buffer, 0, read); - Gdx.app.log("Server", "收到玩家" + player.getPlayerName() + "的消息: " + message); - // 处理设置玩家名字的消息 - if (message.startsWith("SET_NAME:")) { - String newName = message.substring(8); - player.setPlayerName(newName); - Gdx.app.log("Server", "玩家名字已更新为: " + newName); - } - // 处理位置消息并广播 - else if (message.startsWith("POS:")) { - String positionData = message.substring(4); - // 广播给其他玩家 - broadcastToOtherPlayers(player, "POS:" + positionData); - } + String message = new String(buffer, 0, read, StandardCharsets.UTF_8); + Gdx.app.log("Server", "收到消息: " + message); + + broadcastToOthers(socket, message); + + Gdx.app.postRunnable(() -> { + NetworkManager.getInstance().receiveMessage(message); + }); } } catch (Exception e) { Gdx.app.error("Server", "玩家通信异常: " + e.getMessage(), e); } finally { - player.getSocket().dispose(); - connectedPlayers.remove(player); - Gdx.app.log("Server", "玩家" + player.getPlayerName() + "断开连接"); + socket.dispose(); + connectedSockets.remove(socket); + Gdx.app.log("Server", "玩家断开连接"); } } - // 新增广播方法 - private void broadcastToOtherPlayers(Player sender, String message) { - for (Player player : connectedPlayers) { - if (player != sender) { + public void broadcastToOthers(Socket sender, String message) { + for (Socket socket : connectedSockets) { + if (socket != sender) { try { - OutputStream out = player.getSocket().getOutputStream(); - out.write(message.getBytes(java.nio.charset.StandardCharsets.UTF_8)); + OutputStream out = socket.getOutputStream(); + out.write(message.getBytes(StandardCharsets.UTF_8)); out.flush(); + Gdx.app.log("Server", "广播消息到 " + socket.getRemoteAddress() + ": " + message); } catch (Exception e) { - Gdx.app.error("Server", "广播消息失败: " + e.getMessage(), e); + Gdx.app.error("Server", "广播失败: " + e.getMessage(), e); } } } } - // ... 现有代码 ... - - // 获取当前服务器所有玩家名字的方法 - public List getPlayerNames() { - List names = new ArrayList<>(); - for (Player player : connectedPlayers) { - names.add(player.getPlayerName()); - } - return names; - } - - // 根据索引获取特定玩家名字的方法 - public String getPlayerName(int index) { - if (index >= 0 && index < connectedPlayers.size()) { - return connectedPlayers.get(index).getPlayerName(); - } - return null; - } - - // 设置玩家名字的方法 - public void setPlayerName(int index, String name) { - if (index >= 0 && index < connectedPlayers.size()) { - connectedPlayers.get(index).setPlayerName(name); - Gdx.app.log("Server", "玩家" + index + "名字设置为: " + name); - } - } - public void dispose() { - for (Player player : connectedPlayers) { - player.getSocket().dispose(); + for (Socket socket : connectedSockets) { + socket.dispose(); } - connectedPlayers.clear(); + connectedSockets.clear(); if (serverSocket != null) { serverSocket.dispose(); diff --git a/src/main/java/uno/mloluyu/network/NetworkManager.java b/src/main/java/uno/mloluyu/network/NetworkManager.java index 453c044..405dd53 100644 --- a/src/main/java/uno/mloluyu/network/NetworkManager.java +++ b/src/main/java/uno/mloluyu/network/NetworkManager.java @@ -1,18 +1,20 @@ package uno.mloluyu.network; import com.badlogic.gdx.Gdx; -import java.util.ArrayList; -import java.util.List; -/** - * 网络管理器,协调服务器和客户端通信 - */ +import java.util.HashMap; +import java.util.Map; + public class NetworkManager { private static NetworkManager instance; private ConnectServer server; private ConnectClient client; private boolean isHost = false; - private List playerPositions = new ArrayList<>(); + + private String localPlayerId; + private String localCharacter; + private final Map playerPositions = new HashMap<>(); + private final Map playerCharacters = new HashMap<>(); public static NetworkManager getInstance() { if (instance == null) { @@ -21,67 +23,91 @@ public class NetworkManager { return instance; } - /** - * 创建房间(作为主机) - */ + public void setLocalPlayerId(String id) { + this.localPlayerId = id; + } + + public String getLocalPlayerId() { + return localPlayerId; + } + public void createRoom() { isHost = true; server = new ConnectServer(11455); new Thread(server).start(); - Gdx.app.log("Network", "房间创建成功,等待其他玩家加入..."); + Gdx.app.log("Network", "房主模式:服务器已启动"); } - /** - * 加入房间(作为客户端) - */ public void joinRoom(String ip) { isHost = false; client = new ConnectClient(ip, 11455); - Gdx.app.log("Network", "正在加入房间: " + ip); + Gdx.app.log("Network", "客户端模式:连接到房主 " + ip); } - /** - * 发送玩家位置信息 - */ public void sendPosition(float x, float y) { + String msg = "POS:" + localPlayerId + "," + x + "," + y; + Gdx.app.log("Network", "发送位置消息: " + msg); if (isHost && server != null) { - // 主机直接广播位置 - broadcastMessage("POS:" + x + "," + y); + server.broadcastToOthers(null, msg); + receiveMessage(msg); // 房主自己也处理 } else if (client != null) { - // 客户端发送位置到服务器 - client.sendMessage("POS:" + x + "," + y); + client.sendMessage(msg); } } - /** - * 广播消息(主机使用) - */ - private void broadcastMessage(String message) { - // 这里需要实现广播逻辑 - Gdx.app.log("Network", "广播消息: " + message); + public void sendCharacterSelection(String character) { + this.localCharacter = character; + String msg = "SELECT:" + localPlayerId + "," + character; + Gdx.app.log("Network", "发送角色选择消息: " + msg); + if (isHost && server != null) { + server.broadcastToOthers(null, msg); + receiveMessage(msg); + } else if (client != null) { + client.sendMessage(msg); + } } - /** - * 获取其他玩家位置 - */ - public List getOtherPlayerPositions() { + public void receiveMessage(String message) { + Gdx.app.log("Network", "收到消息: " + message); + + if (message.startsWith("POS:")) { + String[] parts = message.substring(4).split(","); + if (parts.length == 3) { + String playerId = parts[0]; + try { + float x = Float.parseFloat(parts[1]); + float y = Float.parseFloat(parts[2]); + playerPositions.put(playerId, new float[]{x, y}); + Gdx.app.log("Network", "位置更新: " + playerId + " -> " + x + "," + y); + } catch (NumberFormatException e) { + Gdx.app.error("Network", "位置解析失败: " + message); + } + } else { + Gdx.app.error("Network", "位置消息格式错误: " + message); + } + } else if (message.startsWith("SELECT:")) { + String[] parts = message.substring(7).split(","); + if (parts.length == 2) { + String playerId = parts[0]; + String character = parts[1]; + playerCharacters.put(playerId, character); + Gdx.app.log("Network", "角色选择: " + playerId + " -> " + character); + } else { + Gdx.app.error("Network", "角色选择消息格式错误: " + message); + } + } else if (message.equals("READY")) { + Gdx.app.log("Network", "收到准备信号"); + } else { + Gdx.app.log("Network", "未知消息类型: " + message); + } + } + + public Map getPlayerPositions() { return playerPositions; } - /** - * 断开连接 - */ - public void disconnect() { - if (server != null) { - server.dispose(); - server = null; - } - if (client != null) { - client.disconnect(); - client = null; - } - playerPositions.clear(); - Gdx.app.log("Network", "网络连接已断开"); + public Map getPlayerCharacters() { + return playerCharacters; } public boolean isHost() { @@ -92,15 +118,17 @@ public class NetworkManager { return server != null || client != null; } - public void updatePlayerPosition(String positionData) { - // 简单实现:直接存储位置数据 - playerPositions.add(positionData); - - // 限制位置列表大小,避免内存泄漏 - if (playerPositions.size() > 10) { - playerPositions.remove(0); + public void disconnect() { + if (server != null) { + server.dispose(); + server = null; } - - Gdx.app.log("Network", "更新其他玩家位置: " + positionData); + if (client != null) { + client.disconnect(); + client = null; + } + playerPositions.clear(); + playerCharacters.clear(); + Gdx.app.log("Network", "已断开连接"); } } diff --git a/target/classes/uno/mloluyu/characters/Alice.class b/target/classes/uno/mloluyu/characters/Alice.class index e44b5e9d13eb1a2f4f222514d0d0cc400cd4d8e4..3e5e47603ec70205bd06aaec0590ebc82267a4d6 100644 GIT binary patch literal 2412 zcma)7TW=Fb6#gc0V#gVXS+3!dkaCL+WE*oQ7;uxA7#s*mNJ^lW$$GIjS?{{*HH4Oy z(iVCb?|rTOhEz3bg4#-`>SO-^f1naSqEgi}ySC#hM2alUo;mZK%Qth*@n8S`_5wfx z-v`meu)A#8YQeP4^8K=^<%J_OS9eNk(lj(ZhyX*^8iLrF9nN^^aJQ)aKGef-OXlg+img?vwyXUx%erKI*C$077Gv=zj{h%QVwPbX=465}{5Pg?VyTB?q6^hs5_a9yFz zkJ4wJu3y zisO=pynJJHEQB;Y*j%|#ROKR5y~2^Hr+UrOC-SyiPgOd&%5lwekVIQyh69PGx1%!B2ON%!6q*?UqOk~H!jYfJx(O<+JIM#Yu^k=QL;nf;u!&}p zf_`kqo8AedHBS3DeFHdFkN!99$ylSiEH7fb zf?K{cUBPuA^dEN`TX2SmoTcOk=sC{OFM$*d&@o)V3@&1pX59(}txDlDvZuoNhmHfX9;?+e zUS-oAdydCHptGJ%M?IaE=4XLt^-N^h0qKSa-3<|%!S)c~OMF%JuhLf literal 2346 zcma)7+fx%)82=p-NC-!X>!soaY*8VxWhHozv8I7QG*~nULT&9~vnC6hO}g1Aw)SFM z+dh@|zIO8FOs7oIX*=UXANvpZC-~IApfjC*XE%g6$P6!Mzw>>+?{>b+{{7z{&jBRx zLjY|IhiX7@1-4 zr^|}^)<&wG}@@BbUXlfz9tQKrhDH>W;EyVKbw7%@rY(43iqS}cr>(z42*7WK|W~z{hsV`TbzkIYd zJQN!e(tQ_pV{ZU^81}v1GRHo=!4NboO4$-7!`Z>?qPQniQ&9I!j`CLKmh}BuPd}200>9(ouBTl68XPZOQ5qjw7_Csq%eU{_d<{ z>DOwd1>K$&3#QJXWXqZ`XM}CYdxPnBiUyUgH@ihUxeXU**lCtUK4}>x;TUC$8e;^f z131NSYzxIkA0AC=Qi0ar zZI?@K%Q9RV+@|@>osyZ4%*fQ<<+$v|JDbd24dOk9-S>sLL{2P6ZBi0B$}#35uiTuR z3SyjUwpc4wRC!2whU1DWPbah4AhJ}LqT%E!GzN{YL|x-}U!nrZ>FH$Z>TnR(8FqQ~ zObT_KkkA~*bPF^V1P%8(bYUI3AfdN7=31a5L42?Q)z+b!gnr2JQ491`5Fc+q^Xt&O zgf4Js66%}CO#2i4FG8{?cR326CJk40CvA(8K3cQgPNDYPZaLC47Kxu+Y#x> z1nVl@(({qk+bU6f{aM%*NL#x@gZaH4tNh=OVt<}n~ zWZvgkmduXPvGmxrQJKQ09G~GK1E+Os6?D%4ZOiS3ADJib6pywvDJqTW>ePglbf?l? z!}D@wJmUBQU(&=EbZ4UC@-qyfoVya`Mxu*5bwhHIQ9K#T((M$j!>U}e9bRCxHAt2I z7@!42#?V1$fNqw12Tn%+L~w2uAtn4flr}uW{%1HCReIOZ7Y)y^p+6e^4gG5vh=%zZ zqQ8=E8{VPw0NDaK_M#gH5hhQ&Xy+(UX&Vo@5=Q4qx}T)4AHz-G|1^BBL{|}0&V{@E zPjP|hOG+}_*`QNOIvn(Q{0ZgiIytFKg*zJT8_LZlJ*&(&>D$VkCM`BpV@m!hbk~jH z5tGWIM=U885gVyppdS{npOWjL^8k)gf+~6uM<2#<1UX9f4sjPTfGP&@kP?54D1O9= zmeg08sh69nuhQemXPKi%t*m0Qj_V$EqmFTpnyn+@QPny|JZhDGKjq{ko1>BMTJiw7UrVFG-OZyNSh o`bvd%GB+Ttc)jLXxzb{#yR7EKu0M5?=ScK54fc&r~m)} diff --git a/target/classes/uno/mloluyu/characters/Fighter$Action.class b/target/classes/uno/mloluyu/characters/Fighter$Action.class index 454b83d73b6e0caf9f19fedaf2a43761ac7bda80..f122b8162432f44b21b8bb5d49b02b01da72d4eb 100644 GIT binary patch delta 39 vcmdnPyN7qfE>=-~1``GWhAaj_hBgKvhD8j*3>z5uCZA_DVdR_4!nOkdxW)+Y delta 39 vcmdnPyN7qfE>=-71``HxhAajNhBgLChD8ig3>z3kC!c3EVHBOr!nOkdyjuw% diff --git a/target/classes/uno/mloluyu/characters/Fighter.class b/target/classes/uno/mloluyu/characters/Fighter.class index 8e0b0e04f32f51586e8cf40fa19697d170292582..5a0857fcbf2322406604f2555ba6c4ae516cafa8 100644 GIT binary patch literal 11445 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 j{M+Tolz?>bWBWyT2A)27RMf*01i)_Rw= zQeXR8-uqhlEiXkCky@#h`q)2^U(sJssp_3wV;ogTyv&}NJ#+85ckaD^{rl_h0Me*N zaD`#evuw3u+NSrdr|ME9V>=Q$7&bR8hu3WLh?nBJU8x$T<{GvYuR8Xg$t%loJl zj1bnHC+eD4+2c-8BVP%e1vp#xg3t{#q1$ zxE4V_!{`MU8)1xObP=$O_c1`($}Qv<8SY%w5}YFL8vK*qS>L^8!1`~WK7NrD?$>2J6YizL`r>>plb;Buy+4nI3Mvhgui8hv;A$?9l7LMaTY}rE zdyc~`Hz-44<++TVRx9J;@N*e2#9{lwVs>$DL4@$7jFgBnxQspM3~l?|U9S4)IT3*&;{b;wsmwLgEi<#2UXmIzXoh}5 z9z=?EQoo>h0=1530h+2~DL@bFNC#-Uj>!N$ts@zr-8zN?G+IYrfKqjIh`3Ji#kL3{ zgmfq~+?;*Sd!F~}yw7=)zyJIFPXI}L zA3_Jiv6^M8Wz#lm4{EAb;ttnb-Knb6x>2r$5M=1z0g*9^C4w?^T{bMky}}TP#%39U zX}h3@(9ICn?6SJV3#MH(G__b*Rf`Ud3Z|Y2 zL&9MhojAfU5Z#4AY&MJljtP_F4C-@CcD&IQbY^RBl4XWh99b&t#Nw?6OB! zhAYusy5G)}>_Ti-l=h~Kt6siysoZr5Z_#!7S={I53Wc&*jy@KSziES*i|hJ(r4Uuz-@?+s7d_w>BWU0pnisti|Pd$pS5=$7l#P%fZqtt~P;|;iTbbmQ#%t@=xRvr= zsW*}r#0dF9#;5p={lcw=l6$7`+PmHDr znbNNZXdsa@bkQ23o#pL;bMZeQ&95V@M1F(PfhRch1V`ga{{~LPBMTci8IS*plN%U} zN8}B}e<9lroTc>$`2vl{{q#d{6k=ZW(hS-I6@3_@6PY5Bf7+j;ZxH8OvHxkrUW>0| zSb06t9o)nvlCLPKmYh~H5h>v7CzR_=aZ;IzbT!n|%B_|>r!2JOMdeOQ=1QSyI;`B? zM9~Yg;tP|C=?i70Lc&&Qm#7R-Vd8h>5DwxLttu6nz%h*DIP&Pn9V&R4PO3DLA7TJs zVGutc+E)5ntMm_ArLWWFiEEjsOLf*US;tLZnyzEqm*(n7`ckcq5nn3T5%ZB|?yw$Jy zM$(VSmKgId9R~#w8?>2jv^MTB&pf9tR({vJiX||6R5soM?*>06R{A uFX{GtTB`IF2A$+?PuWMZ|ywgAEih5dT1M6^LB%CrJI=U2$>Q#bwE`6soBt zQODjaO|xutjHbbnYC)W|u9|+PtES5?Op>O?+op1?vx_>-bkWT@-+Rt`p7XrVdEf85 zs!KKIukTJ?15nG*WpjgNz|36cnK+Ng?+b>U-GNY`ufNY3^hNfC!h4)8Grn05>Ycu@ z#`(-AW_9`^u3&FO4|;q=p`*Cz|4VCPjULfhz(T?*08Jr}9%vm1=>5L1%S+ejl zI-V7bemT#6wfLcLEC;0jLBSZ1`az{-5AY>5ob9!p5&R^82gVS(g1f{iMpU9bkn(-W zCs>;BF1}U$_UBq!WmR|zl@pvB<$^C!Fu|fIORJ3%up6U%Y>WxBx!7);8Ju23mC4-c$~@0v+B#?#|;N%FG%Fbr5GcE9iiUX|$#!HU;J zo5P~bu;_n8W^@#891{(P;Kd0!?VA|HTcX5CypOkW0jF^T@8DOQ#ck2$cbvx^T%Z9L zso?|KmSco-@FC0a5i4w?J0*q8b$r)Xe; z>!pD~qUYJfW+c*v9JWZzh>KFN5ZWDB`4{RE{zeayOdx53!^9`V0-84KPb4o%`UA5o zBqfhW!1JZBNxZZ{mdMi(HR2TfxU delta 961 zcmXAoYfMyE5XXPR#l7sh%idLX*+oE-t(8bEl#;Z5wn;zsW1BRh+i3fh`iMGr%}M5*IWzO0`Old%)be|y z@7jZ(e*s!$OJs)S(X*W(j|r>_4ro;iGS;?SqIRGUM=gq4&UGaBsl*it8yn%Y32i92DZ z!7ug1eXNxRA4{ddbUSI!0$FHFt2yjcOWKS(ry?zRvRLp>j1K?PKXBu~`Q|dolMd4x zDs(zE<;`y{WiFk`oI92o7&hOBQqp7o3MF$_xQVVhrKWn?|KT{fgz-{LIVDt5K@ADh zG`(v|k||W1-P3o3YnjSiBBa!#js*28=b1pkSZfm=nhDavELzpFP@~i8*G40YRqJ4h zu9xU!JzZ>I8L!jLPI~y56~+qx8Gi;J&nm)m6tId?o~M=w0GLiq`q6`8RSqwF#Te#Mq*-Tba#k%+VY@s=v%O#n{e1-sC8~oZv0K=56DP z4hD7*;$6jfj|Sd1!_nUYJ2n3<#rRO;KQjAcebR4yMVkxKithpG7^ZiO2f_(yF`pD| z_YNkn(3JBP#!MFN3Ky!@JT4_`+&z{%DlAK$hNalUkXp zlW|Vns_@;%k$be~Jk%C?Y(&JS(w3A;@cXCUCGQT=IyKarU`e!Zp3+@4BJ*|Y8IeYp zYEG8wG{uA;w5M0d=SQVFlC8||R-qI2xH3zc+z5F}nsqP0l0^#LmX+;UxkS3uQlzzR X)i1JC=l8t+l4Xlx(k;uydYafHLeR&1 diff --git a/target/classes/uno/mloluyu/desktop/GameScreen.class b/target/classes/uno/mloluyu/desktop/GameScreen.class index 3e2cfd7edb0aa41219bfe5e123df015cc44783ff..7b329b6cdc6f3ddb95fe21952998595b8bfe766b 100644 GIT binary patch literal 3951 zcma)9>w6Se8UM{@v$NR@5CSAwNNE}fgoI`TSipp0)4IJKKX)S8CUYb_Cl{TBEQLI*p)?5AHH^2GCf50z3kHz1a*(+JF4?KI$ob$fF z_x_$YZ@&H7H30YGZ!&xmwq^}8GMhHj*|}^aq1k5~GZQ(c&T6r^rD=u?KWXCTY-CzZ zq|Kxrk0cWpBHradLd`guCBdI01L=mVfsLrTAprX&1TtxLPB64pP{vcLrN)V5N1}Q% z#SLj|r&TAOlF&W8N_x^#Gbuf8N0NIJkyysk9qoQWOs+L{O3i5Fnvu{fA!yI-xYJoj zPur1LISVmDano=tGo2OyyDBt2M;%o%X$3_Gi=<>!OedvTW3G+1gmuF+>NzzcghWQv z3<>IDdeTsxtVL%HR^A@+KGUj^jKmyEH^ATLC+==_S? zDqy=N7{);}p@mR`W(6D2BB7>p*MyAC64sY2c|f&Ov?hcwn(H9p4h8GbAa-{us6{~R z?ouElC}W$1o#iQU8~26Kjt(JqhlFjFwp7(ti0M?Y25W_*bweA?&Q5FANp(6+=Qa+T zaWy@mTDthoANrk?&ahPGUcphNl&4qycFH_2Bf{{%8-5MB7YpUgS zju4_~4&gY4WjuIO6IvZ^1tU00A=ykqb(o;-7!F|!<1*eWp}ky=p*iPG>r7XP1ksY0trCpu1UkI8|@G#y-0NrN28yZ_x!Yz&|VZxMxQ+U5< zf|^4j)=X3!KdRsZh2u$qqAHk1oL$1Euf|MUcXZQW_&TF>naCbZ!DFK8YNxfNZU~H& zf+Nr+^i+w$Et{YRc1A(kEnx}^u~rNPruc63B6XsoQ`IK4w4+LpqU@kCM~$Chg}YTF z6n7M4agMAs&}(i5?O9Fh>BdrX5N%GdFgND}%Z4J$V6n&7<8gdg#)l}Xf>FUo@KFgt zjm>v1rZJ-{v3bN){y07<;}aFUyio8de44y`2`tqSiQ816*HHeP08ij^GCoUdO2P}b z3O}2SMUS;kV%UU)w6jO(ozID zr(jXktW0N&y78>by<`=uIs{tog<=z4EWLu)-wdnj++= zI}FK>d7}(dvGOsR%M>1@j!J=5Mu1aM@yOrvf9Y1MCHT54`88!!DYTFup zRO^-s?qWZx;S3r;qnH@DYZUVWSD$z~-IdRuyYhi|?>S?TYrT6WxLAeQ$lpyoxd6Y5 zx1(zjO742Ta2PG`wV-ouO^Y};Dzl6_7cpVoINn|6R_s`^QXCP z@xL5=mTPCYuJOA$eD5+g%%g)J&$}Ou^JrPd3k>a#`hxS=w2Uj<|D-QiJPZe~W4$Ld z99+UrYw)l*3WtN?KuvEr;P1`hYB=Z_niPgDNVt3>AD0;s1HT)CY5EGdj|DQo7z{Gu zkD!;H@8<{=-Kas${pyA&f zG~UJ$Dahes9cJ9Pjf(=58uD?Ir8>OomfTv&#|ShqYQ6XiUL$S|Wxs)6;Fm0iD5rLvdtSG0-=uA)d=J;z_? z!V>vCm;E{X!OgxmOV!y#3ju?=nDl*y2o|=$F00ViyuW<-Gbw%a&|kTVf$Jh|cq>r% EKd#aBEC2ui literal 3684 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 b=u5$6TnUEp89v9C*w`$Hw(u4GBpCk!Ni-7L diff --git a/target/classes/uno/mloluyu/desktop/NetworkSettingsScreen.class b/target/classes/uno/mloluyu/desktop/NetworkSettingsScreen.class index 7f00b39500e4f980586dd27945dfa6f38ee83e50..c15a4d25c6f1a81eb5093b17f77b4dceb3a7b1a2 100644 GIT binary patch delta 1502 zcmah}du&s66#h&)aCco$XzVn^$+|wsU zp2)WxySl#%z-=^iuO)1bS%)=4+L}mBeM5a=I22tTsasMwEiqRH!@-52 zIvM-XNw6*qMJI=sMT6l5Awsr4x8nbyWm=$vGP*E~U|CQX3PwX!k%+%G1+Nm!#U-Ny zMf?Pw%!}@ohYA zjyF9QZ`pb7z^2nLZH#xVi?35pbv}7|%M0<{YP@NCeBF*fAYj7V&9;H!sAXX35ge1@ zf!Bf~cvr@8yhl)$g`$=9HPJ;&Yl01-y2?m3=O_8+t~T7)f$fAAyprefIt-T_bV0@QEx5A{JC$9^?hfoRVjol$ z2Y6Htsdz1M^CsWKjOfIX*?BL+*N&sp3M3WpXqy5RCt6W`o$(Q!(VxJ5tTS@lPV~&q zYsY8Gm&(`5Qyus=39Tr)j$tZR;Y(mn=@^Z<6TN-m&Tx#_Ue3YDo&r^H@puTmnzwhd)S?Oc{iP(D$K?V%)?A9!TngyyEUl62A(&g7F)3t&*EXch&mi(w=@s) z5z#$MpIedKhI1-@W9dc8@192G zg7Sxoi~q@1bov!sss=9oN-q8?J?tnh5cmT~lulb+?h9M23oz)n4SZ%~Y!ZakDEwXDbtFR3*wkEMkm`t0Pr1G%j|MY4L-TJdI9DneQaC*x(vI;Ze8| zV;QSC++#P$DCw6`(l4WgEM(>6-N+!BoisAeK{j#LHRbNLH(-7JSRbYKrQp+9v=n@l zrl+8-?7T{(U<3{29(0J+?m;URT{gKi3srJ!)*1AQC#>7ZhBqHPnq|7ZwL5?8qAUp8=G*Z=?k delta 1519 zcmY*Ydr(wm6#t#wh0ET(!0ugE#a)C2!ChEb4VyG_luQI-NQF%F4`TA3zx?k@Sbcjmk2e&;*C^Eo z_OEOSx3spk`a{9!nsDT9|Lkxm6kHyy3r1E4BQkbkNP!c(2_{dKccBaod-RRHgt4BQ zE3gY%L!rR3mS9=p%w2} z53~dqu~;5&g-ofGE>YUGl15pBMun{6`P60BEQOrNkx@=rGKwinxYEi@6A2!1(c%#g zrkyuu!GsAgBU^N(M;&=w!$gchKC)1NN&H^NXVa}snLZ?=1nKa@jVbZ{B1~oLdeLKD z=a>c=(_zPraB&&=xCuVY5FXn@nX@3F9GSQoxtNV2+`>_F_)LY^Z_DlsB8l?@hx$=J zh^Gj>*jMOu*$n4wbXLPNy{PNQR`o@7`ygI6VhCEp5Oy}$e0vA5YXGlmcrD@I7x(w$ zEp?xUgF`sdQ1}Ym1Nf-6*refO{ij&N=Y3f5KYRzn=k>yqi2rspzJ3V94TS^vK|Q9P zP`3=?C(*8s@BA(9)=`FVdKCH(#@oT%jmYD*8Y-_si?E(|HY1G3`MU-8VjChD#3~%bYVH6~n9zl_EC9T`aR~Pz4LoIRwXtR3 zz*L;UStjr&?@BOUK(m-*_jmr)hva_zqv2m>JXyWy>{3V6OB&${T{RBh1_k$XL)$SK z9r3hNxgp@T#?$H+nMSitiRU-Oy?TBl$L3QKB{Pzqe-aFr_;w^o5NGT~o*o9$p-Sx} zF^g#$rT8>bx|;1|YreC>*<~knnVsxnPDbABP9C`jctFQU*D= z`Z36&F<8Sqa$%#f;)RUr%Jo;px-ZANY20WH?l_8GgPStrHR#rOwh}cMLD?X3iW!b^ zK39VF1YJXovUTkY@m43a>t@9t;m8eeV53;;a7@q9Pmr5(`I`$9Jj5^n|qk2n)JW5 z6{^-(n$yf`lT{jp>Y`TYv$>xK)GlAdc!-$E8g;=pc3cZAI_#a|&!w5|Hc#-R`q_+1 z4Nu!V!?Q}arZ(;5d6VZff-X6UuIQq^WOrY3X;Pqc*u20l!Lz9+k&I_?t?;vxJvJ|5 z%gMU-zTWi#3ijM0U{19@VDYK?EvLjd#*oRN^7%`>pK)A8{l7^E$#TsZX9vYisK}J7&5&|^;@WqM&RJ_=#c@KXxlf}q&4aZ?o`Vny1q22&dVdVP%-TS>8k&jqaHk zMH??c_@*|H?Kmpg(h7znyS%AbXGCz4DW(2!IJghDZeq9s;XT3Fma5Lj;7 zKPsZ=SV<=k`6@Bim~@BPDe z-FBf}*es)vVZ(3pgNwuSx8`~x-F=Z$V~e9_BHdFr&X3*bJ-0ZjTEMVF!9ytG^J2Pe zK{0koc$gm(5{2E^!~2CybE$$XJi?I9b3_|IYKRfb73@U?|5x~n)$-qs8Rj~;Bs|5C z%&)U#lY)9Y&9|8xq8p784s)+5aa|KU3`W1()xcoNtSQPWG25mm>38 zc@@ob0x$9{^0u5XURLl5iWuTUZ4IuVyVC3Gbo(oP0Z-85Yqi3NQVr>A3SQ@3Vn!Z= z(za|Yb_EGikAyykHFsLx*W~wgxaz&`7}S9)IEi=ppQ4jMyszLC`uRp_bIECZB;iA< zs>gYJ&Wcd5Efl12-L4h|1NfMrcKAI(_cGjS3r^z`1!thp$zg9O&}4-PrF>9IO{l|& zg3mOI)ZhtFe{LC{^B<*qc(HpYM8bb)0qY!+BmDE#zpcBuQp;% zF0)U27lSpIyW>eu4rt;|Q%$IJ>Z# z_8Y0obeboFaAXpQEaW2xJK;bnoCIVOMdlKa`zSV?N8wwjzdUr{est0E81d8y7Dk6% zCMco;Z=i=z#FM2-CupbiZ&EUW63ghNosrTKRf5WNs5XeVAxe1bHWJtp9?+;p(bhA;!~$W?{|FVD%R3>3G61_?;*98P!FX@MVVe(6O^Xps5Uk631F$ToTse; lU*Jo6+G&7`-khfVhw?$ph*c{a5ddd+NIl_W_OD65_sz? zcw;mXHC*@rzK8KGjQ{R7P;3KU%83&7-e3u zWz{l`YUQoZXOx2DJVUG*@NDpgU`Q5^nM%sFoGKx-Ma!|&62na9RIcn6L!=-pB8Gkp z#Sz6YLw_c_6$MF*V*pwVNsQ>Y$S{2DXq~HC9HST`S1xxdvJqT+p)J2#rj&s0026Uc zVv1qB!Rvw&VRH4_QZ-t6iaW|<7|pC@yXE`7FUO%{kRegD9I?@Al!d#=%XSd2G`YRS zUCZCMjS*F|h%ZOYxHK^g3Ucocsd?3%ymWDOS_K8)HtU@sb9lDbu2Q>p4l#h z4|{}Ra6@=%ReB0D)S&&;;C(dch0qMYTWOBah$2Sk=V-M}r#@yf_YLvf`~ecV@3=66 z@%sKDE&&HfeWv3+Ow*hUE>F-rNfc9`))JHwz)cm tB>okW=^-S7Tp)KIH|Xor-Jx+8_i2|T0T1v9PbgOmdHT`DNUR@R{x3niPX7P^ diff --git a/target/classes/uno/mloluyu/network/ConnectServer.class b/target/classes/uno/mloluyu/network/ConnectServer.class index 19a0529678049f8c3e4667eac4808fe2f5900b42..23e2460a4ebcd5d9000afc2320b95136812ef71f 100644 GIT binary patch delta 2777 zcmaJ@d0bT289jHlH_SX)MwAi-5e%}5+J;zgs~TGx76FwKP0|sbFak4l=7Cw7j-+iu z($HT2v!gCu{nKYzZt_gl{UzVn@X zAJ=ZWSnN6f`si~2R)|>xo`bH&P)mnl4h-j}l~wQX_xj6v%s^*Zbs%Ccm&1;%NL~}B)>UE#|G5PD~_C`Mr_isQDBa|rpWOVsE zjJ2U)i{EStnC)CeOn=af$X>0`uHklh!I_bCr;a?lS75UoaOa6i7LlDDudLG_Y%6Q% z2?qV!I*m#XwqlzOA6n!N*W9A5Fm!B3hJcfxVN;ddt|NdQ0**-F9z(!hP*~+gr#$Lf zyvl>Km!L}rP1RvAzQF+CiZ{LkaWQM-5p&tXP-Ms?ynOap9Cnd;tw6y!f5yLE7 z8~?2=-0XuL%^nDRT*qVhgh1N1aLC`<;*XdcLv?1m5snBfl}8=fa*t=W*MUzd*7pe% z$h)<9+pm+XI{u7~$I&97cZVY8l*b3B;-e7Qaj~y95v+MHM6BD}+$xEKnd<{=)I5I_;HHMAt;m}SsV}&)O<0yvZ zt={~c<9JrX2|`V4u*x*Telrx-5yMG2;LYJMMs$qgv>fr4dOYaImvlUbF}Yq}l=K3= zqT$N|>GDNy`Vt*q#n(88o#B8&BiZvydU=oxI6t_+gkk# zmI%x$Ao1y54_?BrHT+5-cOW%Azt%8!hQb{+{vajCrhbE$1-w*Ym32~DSZ01fp`7oU zRrKaio`#n&q2m=?Z%NJv*|$>kb;hbtO>FV`g(+Hb=jWOwr8H{!Q${F$Z1 zCljB^ME{=ghxb?H2oL^>ziarLT$hsXz(4R$8BDnp#a~j9p>%as$Io$JiiZEt;1;x` z!~w?7+&_Nm6an1AM&rbzvGM++6S4k@z9Aap*@E}O1zb#V35S)PbiIgIckO$5?BE+P zyqwnf$k@c*BMM_~-w@Gqgato?@Nw7plf#!!9Fi;3=7}_UM_Q3%ra-prOUWj%t2z|w z=;@Z{(^d#gx_uQhX2O9~q#&LDX308VVUiNFjrY`m?DOSDR~4N=xfsEE8>+dSQ#^ud z8=8(`nQuAQ4TAD|4={q&cAUo6=AzEPt3mE!BLA_wu7>NrFU zU84vC#ELjDOzLuQ7w+YSWXC)pilxw5OeV{_fvzkb%xo;8>+RgtVm|JqtrH8FbR%_@ zk3A@$2mEhWO)w&tzl*R0I~gMwla9M_4_Eino&-l;LW#x3p8!g%#`%K%0ttdYJ4LYXP&7f;nhNLt3b7(Gon!ykKWvS(0SzP; zXv2eiS_E@g8C;jJ-9<=48D?WK*LNx~QG>c1P)&p>}r~)h`#^v<-&CpE)8F}3ZIz7GT1Z-jZu6AO$}e1KbPa<1)mt=Izp%+M&dGjMxeqm zh}$zABRD4TJQ{0Diw~iubOfj9a%MV9ILsK%#PEEkGlsKjPSNFbQ{*M1_(o!|gP2p{ zjE|d99OAbqPp36S1^sP-eUtl@kh6IaZkQ4>ir`@_w~*WQ^t_8ots=|sCb_pVuA21n z6HR{@^>3go8oAC{1TR_wWljk zwpOp=HU3sm^M7RapYShw{*7yR-P%v8rx0&bW?>gDR;>(HFh56Xt&3y=sK3REu|%Y- M&J?M_C(@DmU%Uv1-v9sr literal 6909 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 gf_N9Oi{soC$;kY7a0gy-v9sr diff --git a/target/classes/uno/mloluyu/network/NetworkManager.class b/target/classes/uno/mloluyu/network/NetworkManager.class index 6ba80023a8dbfe109db94e31005b42ce156f942a..78ea3ba7db4e6aa73f659441e4ac70ca60c984aa 100644 GIT binary patch literal 5466 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 B9hd+B