Files
Game/src/main/java/uno/mloluyu/network/NetworkManager.java
2025-09-26 09:31:46 +08:00

270 lines
9.6 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package uno.mloluyu.network;
import com.badlogic.gdx.Gdx;
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 String localPlayerId;
private String localCharacter;
private final Map<String, float[]> playerPositions = new HashMap<>();
private final Map<String, String> playerCharacters = new HashMap<>();
// 存储远程玩家的攻击类型attackType
private final Map<String, String> playerAttacks = new HashMap<>();
// 攻击方向playerId -> "R" 或 "L"
private final Map<String, String> playerAttackDirs = new HashMap<>();
// 伤害事件targetId -> 累积伤害(本帧内可能多次)
private final Map<String, Integer> damageEvents = new HashMap<>();
// 伤害方向targetId -> dirSign (-1 / 0 / 1)
private final Map<String, Integer> damageDirs = new HashMap<>();
private final Map<String, float[]> respawnEvents = new HashMap<>();
public static NetworkManager getInstance() {
if (instance == null) {
instance = new 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", "房主模式:服务器已启动");
}
public void joinRoom(String ip) {// 加入房间
isHost = false;
client = new ConnectClient(ip, 11455);
Gdx.app.log("Network", "客户端模式:连接到房主 " + ip);
}
public void sendPosition(float x, float y) {// 发送位置消息
String msg = "POS:" + localPlayerId + "," + x + "," + y;
if (isHost && server != null) {
server.broadcastToOthers(null, msg);
receiveMessage(msg);
} else if (client != null) {
client.sendMessage(msg);
}
}
public void sendCharacterSelection(String character) {// 发送角色选择消息
this.localCharacter = character;
String msg = "SELECT:" + localPlayerId + "," + character;
if (isHost && server != null) {
server.broadcastToOthers(null, msg);
receiveMessage(msg);
} else if (client != null) {
client.sendMessage(msg);
}
}
/**
* 本地玩家所选角色(仅本地缓存,远程映射存于 playerCharacters
* 供界面或后续同步逻辑查询。
*/
public String getLocalCharacter() {
return localCharacter;
}
public void receiveMessage(String 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 });
} 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 if (message.startsWith("ATTACK:")) {
String[] parts = message.substring(7).split(",");
// ATTACK:playerId,attackType,dir
if (parts.length >= 2) {
String playerId = parts[0];
String attackType = parts[1];
String dir = parts.length >= 3 ? parts[2] : "R"; // 兼容旧版本无方向
playerAttacks.put(playerId, attackType);
playerAttackDirs.put(playerId, dir);
Gdx.app.log("Network", "攻击同步: " + playerId + " -> " + attackType + " dir=" + dir);
} else {
Gdx.app.error("Network", "攻击消息格式错误: " + message);
}
} else if (message.startsWith("DAMAGE:")) {
// DAMAGE:targetId,amount,(dir)
String[] parts = message.substring(7).split(",");
if (parts.length >= 2) {
String targetId = parts[0];
try {
int amount = Integer.parseInt(parts[1]);
damageEvents.merge(targetId, amount, Integer::sum);
int dir = 0;
if (parts.length >= 3) {
try {
dir = Integer.parseInt(parts[2]);
} catch (NumberFormatException ignore) {
}
damageDirs.put(targetId, dir);
}
Gdx.app.log("Network", "收到伤害: " + targetId + " -" + amount + (dir != 0 ? (" dir=" + dir) : ""));
} catch (NumberFormatException e) {
Gdx.app.error("Network", "伤害数值解析失败: " + message);
}
} else {
Gdx.app.error("Network", "伤害消息格式错误: " + message);
}
} else if (message.startsWith("RESPAWN:")) {
// RESPAWN:playerId,x,y
String[] parts = message.substring(8).split(",");
if (parts.length == 3) {
try {
String pid = parts[0];
float x = Float.parseFloat(parts[1]);
float y = Float.parseFloat(parts[2]);
respawnEvents.put(pid, new float[] { x, y });
Gdx.app.log("Network", "收到重生: " + pid + " -> (" + x + "," + y + ")");
} catch (NumberFormatException e) {
Gdx.app.error("Network", "重生坐标解析失败: " + message);
}
} else {
Gdx.app.error("Network", "重生消息格式错误: " + message);
}
} else {
Gdx.app.log("Network", "未知消息类型: " + message);
}
}
public Map<String, float[]> getPlayerPositions() {
return playerPositions;
}
/**
* 获取远程玩家的未处理攻击类型映射
*/
public Map<String, String> getPlayerAttacks() {
return playerAttacks;
}
public Map<String, String> getPlayerAttackDirs() {
return playerAttackDirs;
}
/**
* 发送攻击消息给其他玩家
*/
public void sendAttack(String attackType, String dir) {
if (localPlayerId == null)
return;
String msg = "ATTACK:" + localPlayerId + "," + attackType + "," + dir; // 新格式包含方向
Gdx.app.log("Network", "发送攻击消息: " + msg);
if (isHost && server != null) {
server.broadcastToOthers(null, msg);
receiveMessage(msg);
} else if (client != null) {
client.sendMessage(msg);
}
}
// 兼容旧代码(若仍有地方调用)默认使用 R
public void sendAttack(String attackType) {
sendAttack(attackType, "R");
}
public Map<String, String> getPlayerCharacters() {
return playerCharacters;
}
public Map<String, Integer> getDamageEvents() {
return damageEvents;
}
public Map<String, Integer> getDamageDirs() {
return damageDirs;
}
public void sendDamage(String targetId, int amount, int dirSign) {
String msg = "DAMAGE:" + targetId + "," + amount + "," + dirSign; // 含方向
if (isHost && server != null) {
server.broadcastToOthers(null, msg);
receiveMessage(msg); // 本地也应用
} else if (client != null) {
client.sendMessage(msg);
}
}
// 兼容旧调用不带方向使用0表示沿用被击者朝向逻辑
public void sendDamage(String targetId, int amount) {
sendDamage(targetId, amount, 0);
}
public void sendRespawn(String playerId, float x, float y) {
String msg = "RESPAWN:" + playerId + "," + x + "," + y;
if (isHost && server != null) {
server.broadcastToOthers(null, msg);
receiveMessage(msg);
}
}
public Map<String, float[]> getRespawnEvents() {
return respawnEvents;
}
public boolean isHost() {
return isHost;
}
public boolean isConnected() {
return server != null || client != null;
}
public void disconnect() {
if (server != null) {
server.dispose();
server = null;
}
if (client != null) {
client.disconnect();
client = null;
}
playerPositions.clear();
playerCharacters.clear();
playerAttacks.clear();
playerAttackDirs.clear();
damageEvents.clear();
damageDirs.clear();
Gdx.app.log("Network", "已断开连接");
}
}