This commit is contained in:
2026-07-25 23:05:24 +08:00
parent 0c58becf41
commit a5d9a06030
11 changed files with 405 additions and 806 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ namespace Assets.MyGame.Scripts.Net
//public const string baseURL = "http://game5241.wzaxr.top";
#if UNITY_EDITOR
//public const string baseURL = "http://8.137.163.153";
public const string baseURL = "http://47.109.34.50";
public const string baseURL = "http://47.109.132.12";
#else
//public const string baseURL = "http://8.137.8.46";
@@ -44,7 +44,7 @@ namespace Assets.MyGame.Scripts.Net.WebResponses
none = 0,
rotateTurrect=1,
fireBullet=2,
createFish=3,
// createFish=3 已废弃:鱼创建改由服务端 OnFishSpawn 事件下发
changeAutoTarget=4,
randomDieFish=5,
changeTurretState=6,
@@ -52,8 +52,7 @@ namespace Assets.MyGame.Scripts.Net.WebResponses
freezeFish=8,
changeCannonMultiple=9,
changeWing=10,
/// <summary>新玩家资源加载完成,请求房主广播场上活鱼</summary>
requestSyncFish=11
// requestSyncFish=11 已废弃:鱼同步改由服务端 OnFishSpawn(type=sync) 事件下发
}
[Serializable]
public class FireCannonSendData
@@ -145,4 +144,93 @@ namespace Assets.MyGame.Scripts.Net.WebResponses
{
public int cannonMultiple;
}
// ================================================================
// OnFishSpawn 事件数据结构 (服务端出鱼,破坏性替代 createFish 帧同步)
// ================================================================
/// <summary>
/// 服务端出鱼事件 OnFishSpawn 的数据载体。
/// type:
/// "init" - 首次出鱼(玩家进入房间后服务端推送初始鱼)
/// "spawn" - 定时出鱼(游戏中持续刷怪)
/// "sync" - 重连/取消挂机同步(把当前场上活鱼推送给回归玩家)
/// </summary>
[Serializable]
public class OnFishSpawnData
{
/// <summary>"init" | "spawn" | "sync"</summary>
public string type;
/// <summary>服务器当前时间戳(毫秒)</summary>
public long timestamp;
/// <summary>本批次出鱼列表</summary>
public List<OnFishSpawnFishItem> fish;
}
/// <summary>
/// OnFishSpawn 单条鱼描述。
/// 客户端据此调用 SpawnFishMainThread 生成鱼实例。
/// </summary>
[Serializable]
public class OnFishSpawnFishItem
{
/// <summary>服务端分配的全局唯一鱼 ID(作为 guid 使用)</summary>
public long fishId;
/// <summary>鱼编号(配置 fishNumber)</summary>
public string fishNumber;
/// <summary>路径编号</summary>
public int routeId;
/// <summary>鱼阵编号(非鱼阵时为空字符串)</summary>
public string fishArrayNumber;
/// <summary>鱼阵的 Boss 鱼编号</summary>
public string bossFishNumber;
/// <summary>鱼阵普通鱼数量</summary>
public int fishCount;
/// <summary>鱼阵 Boss 数量</summary>
public int bossCount;
/// <summary>鱼过期时间戳(毫秒),到期自动移除</summary>
public long expireAt;
/// <summary>鱼剩余存活秒数(客户端做倒计时用)</summary>
public int remainingSeconds;
}
/// <summary>
/// 机器人退出房间通知数据 BotLeaveRoomNotice: { userId }
/// </summary>
[Serializable]
public class BotLeaveRoomNoticeData
{
public string userId;
}
/// <summary>
/// 玩家挂机/取消挂机通知数据: { userId }
/// </summary>
[Serializable]
public class PlayerAfkNoticeData
{
public string userId;
}
/// <summary>
/// 全局击杀公告 KillNotice 数据。
/// 真人击杀时只填基础字段;机器人模拟时额外填 fishName/multiplier/sceneName。
/// </summary>
[Serializable]
public class KillNoticeData
{
/// <summary>鱼编号</summary>
public string FishId;
/// <summary>玩家名</summary>
public string userName;
/// <summary>金币</summary>
public long gold;
// —— 机器人模拟时额外字段 ——
/// <summary>鱼名(机器人模拟时填充)</summary>
public string fishName;
/// <summary>倍数(机器人模拟时填充)</summary>
public int? multiplier;
/// <summary>场景名(机器人模拟时填充)</summary>
public string sceneName;
}
}
@@ -33,7 +33,7 @@ namespace Assets.MyGame.Scripts.Net
//private const string baseUrl = "ws://game5241.wzaxr.top";
#if UNITY_EDITOR
//private const string baseUrl = "ws://8.137.163.153";
private const string baseUrl = "ws://47.109.34.50";
private const string baseUrl = "ws://47.109.132.12";
#else
//private const string baseUrl = "ws://8.137.8.46";
@@ -453,31 +453,20 @@ namespace Assets.MyGame.Scripts.Net
break;
case "ChangeControllerUser":
{
// ⭐ 房主控制权移交:仅维护 roomOwnerSit,不再设置 fangzhu
// (鱼创建已由服务端 OnFishSpawn 统一下发,客户端无需房主出鱼)
var userId = JsonConvert.DeserializeObject<WebSocketResponseBase<string>>(msg).arguments[0];
if (userId == GameManager.Instance.user.id)
{
// 本地玩家成为房主:开启出鱼 + 同步本地房主引用
CreateFishManager.Instance.fangzhu = true;
if (SitPosData.localPlayerSit != null)
SitPosData.roomOwnerSit = SitPosData.localPlayerSit;
}
else if (userId != null && userId.StartsWith("bot_"))
{
// 房主是人机:人机无法真正发包,由本地首个非人机玩家代发
// 房主是人机:由本地首个非人机玩家代行房主显示职责
SitPosData.TransferRoomOwner();
CreateFishManager.Instance.fangzhu =
SitPosData.roomOwnerSit != null &&
SitPosData.roomOwnerSit.user == GameManager.Instance.user.id;
}
else
{
// ⭐ 只在 userId 非空且确实是真人玩家时才停止本地出鱼
// userId 为空(异常情况)时保持原状,避免误关出鱼导致 bot 退出后不出鱼
if (!string.IsNullOrEmpty(userId))
CreateFishManager.Instance.fangzhu = false;
}
}
break;
case "Exception":
{
@@ -590,18 +579,8 @@ namespace Assets.MyGame.Scripts.Net
break;
case "KillNotice":
{
var data = JsonConvert.DeserializeObject<WebSocketResponseBase<Dictionary<string, object>>>(msg).arguments[0];
if (data == null) break;
// { FishId, userName, gold }
string userName = data.TryGetValue("userName", out var un) ? un?.ToString() : "";
string fishId = data.TryGetValue("FishId", out var fi) ? fi?.ToString() : "";
long gold = data.TryGetValue("gold", out var g) ? Convert.ToInt64(g) : 0;
string roomName = GameManager.Instance.gameData.currRoomData?.roomName ?? "";
string roomLevel = GameManager.Instance.gameData.currRoomData?.roomLevel.ToString() ?? "";
string msgText = $"恭喜用户{userName} 在 {roomName} {roomLevel}场 捕获了{fishId}*{gold}倍";
//UIManager.Instance.ShowBoardGongGao(msgText);
}
// 全局击杀公告(真人击杀/机器人模拟)
WebSocketReponseList.KillNotice(msg);
break;
case "OnFishExpired":
@@ -612,49 +591,48 @@ namespace Assets.MyGame.Scripts.Net
break;
case "OnFishList":
{
var fishList = JsonConvert.DeserializeObject<WebSocketResponseBase<object[]>>(msg).arguments[0];
Debug.Log($"[FishGameHub] 鱼列表刷新, 数量={fishList?.Length}");
}
// 鱼列表刷新
WebSocketReponseList.OnFishList(msg);
break;
// ======== FishGameHub / FishRoomHub 补充事件 ========
case "BotLeaveRoomNotice":
{
// 机器人退出房间,数据 { userId }
var data = JsonConvert.DeserializeObject<WebSocketResponseBase<Dictionary<string, object>>>(msg).arguments[0];
string botUserId = data != null && data.TryGetValue("userId", out var buid) ? buid?.ToString() : "";
Debug.Log($"[FishGameHub] 机器人退出: {botUserId}");
WebSocketReponseList.BotLeaveRoom(botUserId);
}
// 机器人退出房间,数据 { userId }
WebSocketReponseList.BotLeaveRoomNotice(msg);
break;
case "HostDisconnect":
{
// 房主断线,其他玩家可接受机器人控制权
Debug.Log("[FishGameHub] 房主断线,可接受机器人控制权");
WebSocketReponseList.HostDisconnect();
}
// 房主断线,其他玩家可接受机器人控制权
WebSocketReponseList.HostDisconnectNotice(msg);
break;
case "OnSeatChange":
{
// 座位变更 { type, userId, position, showWaiting? }
var data = JsonConvert.DeserializeObject<WebSocketResponseBase<Dictionary<string, object>>>(msg).arguments[0];
if (data != null)
{
// 注意:JSON 字段可能是 long/double/string/bool 等任意类型,
// 直接 Convert.ToInt32(object) 对字符串会走 int.Parse 抛 FormatException。
// 这里统一通过 ToString() + TryParse 容错。
int seatType = data.TryGetValue("type", out var t) && int.TryParse(t?.ToString(), out var st) ? st : 0;
string userId = data.TryGetValue("userId", out var u) ? u?.ToString() : "";
int position = data.TryGetValue("position", out var p) && int.TryParse(p?.ToString(), out var pos) ? pos : -1;
bool showWaiting = data.TryGetValue("showWaiting", out var sw) && (sw is bool b ? b : (sw != null && bool.TryParse(sw.ToString(), out var bv) && bv));
Debug.Log($"[FishGameHub] 座位变更: type={seatType}, userId={userId}, position={position}, showWaiting={showWaiting}");
WebSocketReponseList.SeatChange(seatType, userId, position, showWaiting);
}
}
// 座位变更 { type, userId, position, showWaiting? }
WebSocketReponseList.OnSeatChange(msg);
break;
// ======== 新协议事件 ========
case "OnFishSpawn":
// ⭐ 服务端出鱼事件(破坏性替代 createFish 帧同步)
// type: "init"=首次出鱼 / "spawn"=定时出鱼 / "sync"=重连或取消挂机同步
WebSocketReponseList.OnFishSpawn(msg);
break;
case "FishFrozen":
// ⭐ 冰冻道具(40003)生效:鱼存活时间延长 15 秒,客户端写死 15s 倒计时
WebSocketReponseList.FishFrozen(msg);
break;
case "PlayerAfkNotice":
// 玩家挂机通知 { userId }
WebSocketReponseList.PlayerAfkNotice(msg);
break;
case "PlayerCancelAfkNotice":
// 玩家取消挂机通知 { userId }
WebSocketReponseList.PlayerCancelAfkNotice(msg);
break;
case "RoomChange":
@@ -233,9 +233,7 @@ namespace Assets.MyGame.Scripts.Net
// 与 RoomFireNotice(FireCannonSendData) 分开处理,仅用于存储角度到 botLastAngle
EventCenter.Instance.EventTrigger<SyncGameData>(ConstEventString.SyncGameData_BotFireAngle, syncGameData);
break;
case FrameDataType.createFish:
EventCenter.Instance.EventTrigger<SyncGameData>(ConstEventString.SyncGameData_CreateFish, syncGameData);
break;
// createFish=3 已废弃:鱼创建改由服务端 OnFishSpawn 事件下发
case FrameDataType.changeAutoTarget:
EventCenter.Instance.EventTrigger<SyncGameData>(ConstEventString.SyncGameData_ChangeTargetMonster, syncGameData);
break;
@@ -258,15 +256,123 @@ namespace Assets.MyGame.Scripts.Net
case FrameDataType.changeWing:
EventCenter.Instance.EventTrigger<SyncGameData>(ConstEventString.SyncGameData_ChangeWing, syncGameData);
break;
case FrameDataType.requestSyncFish:
EventCenter.Instance.EventTrigger<SyncGameData>(ConstEventString.SyncGameData_RequestSyncFish, syncGameData);
break;
// requestSyncFish=11 已废弃:鱼同步改由服务端 OnFishSpawn(type=sync) 下发
default:
break;
}
}
// ================================================================
// 新协议事件分发 (OnFishSpawn / PlayerAfk / FishFrozen / KillNotice 等)
// ================================================================
/// <summary>
/// 服务端出鱼事件 OnFishSpawn 处理。
/// 破坏性替代旧 createFish 帧同步:服务端统一出鱼,客户端只接收并生成。
/// </summary>
public static void OnFishSpawn(string msg)
{
var data = JsonConvert.DeserializeObject<WebSocketResponseBase<OnFishSpawnData>>(msg).arguments[0];
if (data == null) return;
EventCenter.Instance.EventTrigger<OnFishSpawnData>(ConstEventString.OnFishSpawn, data);
}
/// <summary>鱼列表刷新</summary>
public static void OnFishList(string msg)
{
var fishList = JsonConvert.DeserializeObject<WebSocketResponseBase<object[]>>(msg).arguments[0];
EventCenter.Instance.EventTrigger<object[]>(ConstEventString.OnFishList, fishList);
}
/// <summary>
/// 冰冻道具(40003)生效事件 FishFrozen。
/// 鱼存活时间延长 15 秒,客户端写死 15s 倒计时。
/// </summary>
public static void FishFrozen(string msg)
{
EventCenter.Instance.EventTrigger(ConstEventString.FishFrozen);
}
/// <summary>玩家挂机通知</summary>
public static void PlayerAfkNotice(string msg)
{
var data = JsonConvert.DeserializeObject<WebSocketResponseBase<PlayerAfkNoticeData>>(msg).arguments[0];
if (data == null) return;
EventCenter.Instance.EventTrigger<PlayerAfkNoticeData>(ConstEventString.PlayerAfkNotice, data);
}
/// <summary>玩家取消挂机通知</summary>
public static void PlayerCancelAfkNotice(string msg)
{
var data = JsonConvert.DeserializeObject<WebSocketResponseBase<PlayerAfkNoticeData>>(msg).arguments[0];
if (data == null) return;
EventCenter.Instance.EventTrigger<PlayerAfkNoticeData>(ConstEventString.PlayerCancelAfkNotice, data);
}
/// <summary>
/// 全局击杀公告 KillNotice。
/// 真人击杀/机器人模拟,机器人模拟时额外带 fishName/multiplier/sceneName。
/// </summary>
public static void KillNotice(string msg)
{
var data = JsonConvert.DeserializeObject<WebSocketResponseBase<KillNoticeData>>(msg).arguments[0];
if (data == null) return;
EventCenter.Instance.EventTrigger<KillNoticeData>(ConstEventString.KillNotice, data);
}
/// <summary>机器人退出房间通知</summary>
public static void BotLeaveRoomNotice(string msg)
{
var data = JsonConvert.DeserializeObject<WebSocketResponseBase<BotLeaveRoomNoticeData>>(msg).arguments[0];
if (data == null) return;
WebSocketReponseList.BotLeaveRoom(data.userId);
}
/// <summary>房主断线</summary>
public static void HostDisconnectNotice(string msg)
{
EventCenter.Instance.EventTrigger(ConstEventString.HostDisconnect);
WebSocketReponseList.HostDisconnect();
}
/// <summary>
/// 座位变更 OnSeatChange。
/// 数据: { type, userId, position, showWaiting? }
/// </summary>
public static void OnSeatChange(string msg)
{
var data = JsonConvert.DeserializeObject<WebSocketResponseBase<Dictionary<string, object>>>(msg).arguments[0];
if (data == null) return;
// JSON 字段可能是 long/double/string/bool 等任意类型,统一 ToString()+TryParse 容错
int seatType = data.TryGetValue("type", out var t) && int.TryParse(t?.ToString(), out var st) ? st : 0;
string userId = data.TryGetValue("userId", out var u) ? u?.ToString() : "";
int position = data.TryGetValue("position", out var p) && int.TryParse(p?.ToString(), out var pos) ? pos : -1;
bool showWaiting = data.TryGetValue("showWaiting", out var sw) && (sw is bool b ? b : (sw != null && bool.TryParse(sw.ToString(), out var bv) && bv));
WebSocketReponseList.SeatChange(seatType, userId, position, showWaiting);
}
/// <summary>
/// 房主控制权移交 ChangeControllerUser。
/// 仅维护 SitPosData.roomOwnerSit,不再设置 fangzhu(鱼创建已由服务端统一出鱼)。
/// </summary>
public static void ChangeControllerUser(string msg)
{
var userId = JsonConvert.DeserializeObject<WebSocketResponseBase<string>>(msg).arguments[0];
if (userId == GameManager.Instance.user.id)
{
// 本地玩家成为房主:同步本地房主引用
if (SitPosData.localPlayerSit != null)
SitPosData.roomOwnerSit = SitPosData.localPlayerSit;
}
else if (userId != null && userId.StartsWith("bot_"))
{
// 房主是人机:人机无法真正发包,由本地首个非人机玩家代行房主显示职责
SitPosData.TransferRoomOwner();
}
// 其他真人玩家成为房主时无需本地操作(roomOwnerSit 由 TransferRoomOwner/ShowPlayer 维护)
}
public static void LeaveRoomResult(string msg)
{
//WebSocketManager.Instance.isGame = false;
@@ -242,6 +242,26 @@ public partial class WebSocketSendList
var sendObj = new WebSocketSendList("ChangeGunMultiple", roomId, userId, multiple);
WebSocketManager.Instance.Send(SocketType.game, JsonConvert.SerializeObject(sendObj));
}
/// <summary>
/// 玩家挂机(对应服务端 SetPlayerAfkNEW)
/// 服务端会向房间组广播 PlayerAfkNotice 事件
/// </summary>
public static void SetPlayerAfk(string roomId, string userId)
{
var sendObj = new WebSocketSendList("SetPlayerAfkNEW", roomId, userId);
WebSocketManager.Instance.Send(SocketType.game, JsonConvert.SerializeObject(sendObj));
}
/// <summary>
/// 取消挂机(对应服务端 CancelPlayerAfkNEW)
/// 服务端会向房间组广播 PlayerCancelAfkNotice 事件,并通过 OnFishSpawn(type=sync) 同步当前鱼
/// </summary>
public static void CancelPlayerAfk(string roomId, string userId)
{
var sendObj = new WebSocketSendList("CancelPlayerAfkNEW", roomId, userId);
WebSocketManager.Instance.Send(SocketType.game, JsonConvert.SerializeObject(sendObj));
}
/// <summary>
/// 同步等级常量(秒)
@@ -284,17 +304,14 @@ public partial class WebSocketSendList
_syncLv1Append.Add(sgd);
return;
case FrameDataType.createFish:
// createFish=3 已废弃:鱼创建改由服务端 OnFishSpawn 下发
case FrameDataType.changeTurretState:
case FrameDataType.changeTurret:
case FrameDataType.freezeFish:
_syncLv2Append.Add(sgd);
return;
case FrameDataType.requestSyncFish:
// ⭐ 新玩家加载完成的"请求同步鱼":立即发送,房主尽快响应广播
SendImmediate(BuildJson(sgd));
return;
// requestSyncFish=11 已废弃:鱼同步改由服务端 OnFishSpawn(type=sync) 下发
default:
_syncLv3Append.Add(sgd);