This commit is contained in:
2026-07-20 22:32:52 +08:00
parent 61b9b9a3e6
commit 9977ce1fc9
17 changed files with 254 additions and 109 deletions
+2 -1
View File
@@ -1,4 +1,4 @@
public class ConstEventString
{
public const string SyncGameData_Rotate = "SyncGameData_Rotate";
@@ -12,5 +12,6 @@ public class ConstEventString
public const string SyncGameData_ChangeCannonMultiple = "SyncGameData_ChangeCannonMultiple";
public const string SyncGameData_ChangeWing = "SyncGameData_ChangeWing";
public const string SyncGameData_BotFireAngle = "SyncGameData_BotFireAngle";
public const string SyncGameData_RequestSyncFish = "SyncGameData_RequestSyncFish";
}
+2 -2
View File
@@ -1514,7 +1514,7 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 22400762, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0.0000076293945
value: 0
objectReference: {fileID: 0}
- target: {fileID: 22426080, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3}
propertyPath: m_AnchorMax.x
@@ -10465,7 +10465,7 @@ MonoBehaviour:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2075409194}
m_Enabled: 1
m_Enabled: 0
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e9c0efceac103ba4098e5aa4b6f717e2, type: 3}
m_Name:
@@ -240,6 +240,10 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
EventCenter.Instance.AddEventListener<SyncGameData>(
ConstEventString.SyncGameData_CreateFish, CreateFish);
// 监听新玩家"请求同步鱼"事件:房主收到后广播场上活鱼
EventCenter.Instance.AddEventListener<SyncGameData>(
ConstEventString.SyncGameData_RequestSyncFish, OnRequestSyncFish);
}
@@ -260,6 +264,8 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
{
EventCenter.Instance.RemoveEventListener<SyncGameData>(
ConstEventString.SyncGameData_CreateFish, CreateFish);
EventCenter.Instance.RemoveEventListener<SyncGameData>(
ConstEventString.SyncGameData_RequestSyncFish, OnRequestSyncFish);
// 释放 NativeArray,避免内存泄漏
DisposeNativeArrays();
@@ -1133,6 +1139,12 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
if (string.IsNullOrEmpty(mc.guid)) continue;
if (string.IsNullOrEmpty(mc.lastMoveLineId)) continue;
// ⭐ 跳过鱼阵鱼:鱼阵鱼 guid 是 原guid+i,单条广播会让新玩家收到后走
// SpawnFishArray 又生成 N 条,导致鱼阵指数爆炸(16×16=256)。
// 鱼阵鱼的同步需要鱼阵级别的广播(发鱼阵配置+原guid+数量),
// 这里不处理,鱼阵鱼不同步只影响视觉阵型,不影响游戏核心逻辑。
if (mc.isyz) continue;
// 总时长,用于过滤快死的鱼(避免新玩家刚进入就看到鱼死)
float totalTime = mc.monsterData.moveLine.moveTime;
if (totalTime <= 0f) continue;
@@ -1162,6 +1174,18 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
Debug.Log($"[CreateFishManager] 广播场上活鱼: {count} 条 (房主,新玩家加入同步)");
}
/// <summary>
/// 房主收到新玩家"请求同步鱼"事件后,广播场上活鱼。
/// 新玩家资源加载完成才会发请求,保证收到广播时 spawnDic 已初始化。
/// 非房主收到直接忽略。
/// </summary>
private void OnRequestSyncFish(SyncGameData syncGameData)
{
// 仅房主响应,且不响应自己发的请求(syncGameData.sitPos 是发送者座位)
if (!fangzhu) return;
BroadcastExistingFishes();
}
#endregion
#region 创建鱼
@@ -1175,8 +1199,17 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
// ⭐ 场景卸载/CloseSpawnSystem 后 spawnDic 会变 null,此时收到的广播直接忽略
if (spawnDic == null) return;
var rotateData = FrameDataParser.Parse<FrameData_CreateFish>(syncGameData.frameData);
if (rotateData != null)
SpawnFishMainThread(rotateData, syncGameData.time);
if (rotateData == null) return;
// ⭐ guid 去重:房主广播活鱼给新玩家时,服务器会广播给所有客户端(含房主自己)。
// 老玩家已存在该 guid 的鱼 → 跳过,避免重复 Spawn 同一条鱼。
// 仅本地无该 guid 的客户端(新加入玩家)才会真正 Spawn。
if (!string.IsNullOrEmpty(rotateData.guid) &&
fishDatas_hashCodekey != null &&
fishDatas_hashCodekey.ContainsKey(rotateData.guid))
return;
SpawnFishMainThread(rotateData, syncGameData.time);
}
/// <summary>
/// 主线程实例化鱼对象(单体鱼 / 鱼阵分发)。
@@ -1796,6 +1829,7 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
// sitData.tMP_GoldNum.text = sitData.goldNum.ToString();
// AudioManager.Instance.PlayerFX(audioID);
//};
bool dieFishCalled = false; // Boss case 内部已调用 DieFish,底部跳过
switch (monster.fishenum)
{
@@ -1835,6 +1869,10 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
var bossCtrl = (MonsterControl_BossBase)monster;
bossCtrl.v3 = sitData.transform.position;
bossCtrl.JiaFen = onScoreAdd; // 先设置 JiaFen,DieFish 的 lambda 才能捕获到
monster.DieFish(killFish); // Boss 重写 action_effect_DieAward,捕获上面的 JiaFen
dieFishCalled = true;
if (bossCtrl.isToUI)
{
bossCtrl.currEffect_DieAward = Instantiate(
@@ -1847,7 +1885,6 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
monster.effect_DieAward != null ? monster.effect_DieAward : dieFXPrefabAwardTmp);
}
bossCtrl.action_effect_DieAward?.Invoke(bossCtrl.currEffect_DieAward);
bossCtrl.JiaFen = onScoreAdd;
}
@@ -1938,10 +1975,10 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
var bossCtrl = (MonsterControl_BossBase)monster;
bossCtrl.v3 = sitData.transform.position;
bossCtrl.JiaFen = onScoreAdd; // 先设置 JiaFen
monster.DieFish(killFish); // Boss 重写 action_effect_DieAward
dieFishCalled = true;
//bossCtrl.currEffect_DieAward = Instantiate(
// monster.effect_DieAward != null ? monster.effect_DieAward : dieFXPrefabAwardTmp,
// currGameType.subPanelParent.parent);
if (bossCtrl.isToUI)
{
bossCtrl.currEffect_DieAward = Instantiate(
@@ -1954,14 +1991,14 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
monster.effect_DieAward != null ? monster.effect_DieAward : dieFXPrefabAwardTmp);
}
bossCtrl.action_effect_DieAward?.Invoke(bossCtrl.currEffect_DieAward);
bossCtrl.JiaFen = onScoreAdd;
}
break;
default:
break;
}
monster.DieFish(killFish);
if (!dieFishCalled)
monster.DieFish(killFish);
MonsterDieList.Instance.SmallHuangYiHuang(
monster.transform.position,
@@ -296,6 +296,30 @@ public class GameManager : MonoSingleton<GameManager>
WebSocketManager.Instance.Connect(SocketType.game, action);
});
}
/// <summary>
/// 快速加入:用 /api/Room/QuickJoin 返回的 url 直接连 game socket(无需再调 Assign)
/// </summary>
/// <param name="url">QuickJoin 返回的房间专属 socket 地址</param>
/// <param name="action">连接成功后的回调(一般是 JoinRoom(roomId, userId, -1))</param>
public void StartGameQuickJoin(string url, Action action)
{
switch (gameData.currGameType)
{
case GameType.FLZY:
case GameType.YYSC:
case GameType.XJMH:
case GameType.HHWK:
if (!string.IsNullOrEmpty(url))
WebSocketManager.Instance.Connect(SocketType.game, url, action);
else
WebSocketManager.Instance.Connect(SocketType.game, action);
break;
default:
WebSocketManager.Instance.Connect(SocketType.game, action);
break;
}
}
// Start is called before the first frame update
public Button btn_Skip;
public VideoClip startVideoClip;
+1
View File
@@ -165,6 +165,7 @@ namespace Assets.MyGame.Scripts.Net
dic_API[APIType.Hall_GetChessRoomPartitionCount] = "/api/Hall/GetChessRoomPartitionCount";
dic_API[APIType.Hall_SendBroadcast] = "/api/Hall/SendBroadcast";
dic_API[APIType.Room_Assign] = "/api/Room/Assign";
dic_API[APIType.Room_QuickJoin] = "/api/Room/QuickJoin";
dic_API[APIType.Hall_UseVipExp] = "/api/Hall/UseVipExp";
// ---------------- Customer ----------------
@@ -208,4 +208,12 @@ namespace Assets.MyGame.Scripts.Net.APIRequest.Params
{
public string roomId;
}
/// <summary>快速加入房间(GET /api/Room/QuickJoin?gameType=&level=)</summary>
[Serializable]
public class RoomQuickJoinParam : RequestParamBase
{
public int gameType;
public int level;
}
}
@@ -320,6 +320,20 @@ namespace Assets.MyGame.Scripts.Net
}, callback);
}
/// <summary>
/// 快速加入房间(GET /api/Room/QuickJoin?gameType=&level=)
/// 返回:QuickJoinResponse(roomId + url)
/// 后端自动分配房间和座位,客户端拿到后用 url 连 socket,再调 JoinRoom(roomId, userId, -1)
/// </summary>
public static void RoomQuickJoin(int gameType, int level, Action<QuickJoinResponse> callback)
{
APIManager.Response<QuickJoinResponse>(APIType.Room_QuickJoin, new RoomQuickJoinParam
{
gameType = gameType,
level = level
}, callback);
}
/// <summary>
/// 使用VIP经验包(GET /api/Hall/UseVipExp)
/// 返回:string
@@ -304,4 +304,18 @@ namespace Assets.MyGame.Scripts.Net.APIResponses
public long taskFinishTime;
public int exp; // 奖励经验
}
/// <summary>
/// 快速加入房间返回数据
/// /api/Room/QuickJoin?gameType=&level=
/// 示例: {"data":{"roomId":"11107","webSocketUrl":"ws://8.137.163.153/fishinghub?instance=1"},"code":0,"info":null}
/// </summary>
[Serializable]
public class QuickJoinResponse
{
/// <summary>房间ID</summary>
public string roomId;
/// <summary>房间专属 socket 地址(如 ws://xxx/fishinghub?instance=1)</summary>
public string webSocketUrl;
}
}
+3
View File
@@ -342,6 +342,9 @@ namespace Assets.MyGame.Scripts.Net
/// <summary>获取房间专属 socket 地址(GET /api/Room/Assign?roomId=)</summary>
Room_Assign,
/// <summary>快速加入房间(GET /api/Room/QuickJoin?gameType=&level=)</summary>
Room_QuickJoin,
/// <summary>使用VIP经验包(GET /api/Hall/UseVipExp)</summary>
Hall_UseVipExp,
@@ -51,7 +51,9 @@ namespace Assets.MyGame.Scripts.Net.WebResponses
changeTurret=7,
freezeFish=8,
changeCannonMultiple=9,
changeWing=10
changeWing=10,
/// <summary>新玩家资源加载完成,请求房主广播场上活鱼</summary>
requestSyncFish=11
}
[Serializable]
public class FireCannonSendData
@@ -443,29 +443,32 @@ namespace Assets.MyGame.Scripts.Net
//WebSocketManager.Instance.Close(SocketType.game);
break;
case "ChangeControllerUser":
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;
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":
{
@@ -567,8 +570,13 @@ namespace Assets.MyGame.Scripts.Net
case "UsePropNotice":
{
var data = JsonConvert.DeserializeObject<WebSocketResponseBase<Dictionary<string, object>>>(msg).arguments[0];
// { userId, propNumber }
Debug.Log($"[FishGameHub] 使用道具: userId={data["userId"]}, prop={data["propNumber"]}");
var userId = data["userId"]?.ToString();
string propNumber = data["propNumber"]?.ToString();
Debug.Log($"[FishGameHub] 使用道具: userId={userId}, prop={propNumber}");
var panel = CreateFishManager.Instance.currGameType;
if (panel != null)
panel.OnUsePropNotice(userId, propNumber);
}
break;
@@ -44,27 +44,11 @@ namespace Assets.MyGame.Scripts.Net
var selectRoomPanel = var1.subUIManager.Get<UIHome_BY_SelectRoomLevelPanel>(UIPanel.SelectRoomLeavePenel);
if (selectRoomPanel != null && selectRoomPanel.isMySelectRoom)
selectRoomPanel.panel_UIHome_BY_MySelectRoomPenel.Show(msg);
else
{
var v = JsonConvert.DeserializeObject<WebSocketResponseBase<List<GetRoomList>>>(msg).arguments[0];
foreach (var item in v)
{
if (item.currentOnlinePlayerCount < item.maxPlayerCount)
{
WebSocketSendList.GetRoomInfo(item.roomId);
break;
//if (item)
//{
//UIHome_BY_SelectRoomLevelPanel.StartGame(item);
//}
}
}
// 手动选座:显示房间列表给玩家选
selectRoomPanel.panel_UIHome_BY_MySelectRoomPenel.Show(msg);
}
// 快速加入分支已迁移到 OnSelectRoom → /api/Room/QuickJoin,不再走 GetRoomList
}
/// <summary>
/// 加入房间 room
@@ -274,6 +258,9 @@ 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;
default:
break;
}
@@ -260,6 +260,11 @@ public partial class WebSocketSendList
_syncLv2Append.Add(sgd);
return;
case FrameDataType.requestSyncFish:
// ⭐ 新玩家加载完成的"请求同步鱼":立即发送,房主尽快响应广播
SendImmediate(BuildJson(sgd));
return;
default:
_syncLv3Append.Add(sgd);
return;
@@ -286,12 +286,9 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
targetSit.isBot = false;
targetSit.ShowWaiting();
}
// ⭐ 房主:新真人玩家加入时,把当前场上所有活鱼广播一遍,
// 让新玩家立即同步看到场上鱼状态(不用等房主下次出鱼)
if (CreateFishManager.Instance != null && CreateFishManager.Instance.fangzhu)
{
CreateFishManager.Instance.BroadcastExistingFishes();
}
// ⭐ 新玩家同步走"主动请求"流程:
// 新玩家资源加载完毕后会主动发 requestSyncFish,
// 房主收到后才广播场上活鱼(避免新玩家还没加载完就收包丢失)
}
JoinGame(roomJoinNotice.position, roomJoinNotice.gold, roomJoinNotice.diamond, roomJoinNotice.cannonMultiple, 0, roomJoinNotice.userId, roomJoinNotice.cannonId, roomJoinNotice.wingsId);
@@ -550,19 +547,17 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
}
toggle_BaoZou.onValueChanged.AddListener(on =>
{
// UI 开关只是触发,但最终状态以 currGameType 为准
CreateFishManager.Instance.currGameType.isFrenzy = on;
SetFrenzy(on);
if (on)
if (!on) return;
if (_localBaoZouCount <= 0)
{
currFrenzyTime = frenzyDuration;
// ⭐ 激活时本地扣减一张(暂无扣减 API,仅 UI 显示)
if (_localBaoZouCount > 0)
{
_localBaoZouCount--;
UpdateSkillPropsUI();
}
toggle_BaoZou.SetIsOnWithoutNotify(false);
return;
}
// 只发请求,效果等 UsePropNotice 回调触发
WebSocketSendList.UseProp(
GameManager.Instance.gameData.currRoomData.roomId,
GameManager.Instance.user.BaseInfo.number,
"40006", 0);
});
toggle_SkillAuto.onValueChanged.AddListener(on =>
{
@@ -574,38 +569,17 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
}
});
toggle_BingFeng.onValueChanged.AddListener(on => {
if (on)
if (!on) return;
if (_localBingFengCount <= 0)
{
// 开始冰冻
currBingFengTime = bingFengDuration;
// ⭐ 激活时本地扣减一张(暂无扣减 API,仅 UI 显示)
if (_localBingFengCount > 0)
{
_localBingFengCount--;
UpdateSkillPropsUI();
}
if (bingFengEffect != null)
{
if (_bingFengInstance == null)
_bingFengInstance = Instantiate(bingFengEffect);
_bingFengInstance.SetActive(true);
}
CreateFishManager.Instance.FreezeAllFish();
PauseAllFishAnimations();
SyncFreeze(true);
}
else
{
// 手动关闭 → 解冻
if (_bingFengInstance != null)
_bingFengInstance.SetActive(false);
if (CreateFishManager.Instance.isFrozen)
{
CreateFishManager.Instance.UnfreezeAllFish();
ResumeAllFishAnimations();
SyncFreeze(false);
}
toggle_BingFeng.SetIsOnWithoutNotify(false);
return;
}
// 只发请求,效果等 UsePropNotice 回调触发
WebSocketSendList.UseProp(
GameManager.Instance.gameData.currRoomData.roomId,
GameManager.Instance.user.BaseInfo.number,
"40007", 0);
});
@@ -716,7 +690,23 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
// ⭐ 进度条加载完毕:房主创建一批初始鱼(进度 0.2~0.8),屏幕开局就有鱼
// 只在房主端调用,通过 SyncGameData 广播给所有客户端
CreateFishManager.Instance.CreateInitialFishes(Random.Range(10, 21));
// 非房主(后加入的真人玩家):发"请求同步鱼"让房主广播场上活鱼
// 这里只发请求,实际接收广播在 CreateFishManager.CreateFish(已做 guid 去重)
if (CreateFishManager.Instance.fangzhu)
{
CreateFishManager.Instance.CreateInitialFishes(Random.Range(10, 21));
}
else
{
var req = new SyncGameData
{
sitPos = GameManager.Instance.gameData.roomJoinNotice.position,
frameType = FrameDataType.requestSyncFish,
time = BeijingTimeManager.Instance.CurrentTimestampMs,
frameData = null
};
WebSocketSendList.SyncGameData(req);
}
JinDuTiao.SetProgress(1);
await Task.Delay(300);
@@ -2034,6 +2024,39 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
WebSocketSendList.SyncGameData(sgd);
}
/// <summary>
/// UsePropNotice 回调:服务器确认道具使用后,激活对应效果
/// </summary>
public void OnUsePropNotice(string userId, string propNumber)
{
switch (propNumber)
{
case "40006": // 暴走
_localBaoZouCount--;
UpdateSkillPropsUI();
CreateFishManager.Instance.currGameType.isFrenzy = true;
SetFrenzy(true);
currFrenzyTime = frenzyDuration;
toggle_BaoZou.SetIsOnWithoutNotify(true);
break;
case "40007": // 冰封
_localBingFengCount--;
UpdateSkillPropsUI();
currBingFengTime = bingFengDuration;
toggle_BingFeng.SetIsOnWithoutNotify(true);
if (bingFengEffect != null)
{
if (_bingFengInstance == null)
_bingFengInstance = Instantiate(bingFengEffect);
_bingFengInstance.SetActive(true);
}
CreateFishManager.Instance.FreezeAllFish();
PauseAllFishAnimations();
break;
}
}
public void SyncGameData_FreezeFish(SyncGameData sync)
{
if (sync.sitPos == currSitData.posID) return; // 自己发的不管
@@ -260,7 +260,7 @@ public class UIHome_BY_EmailPanel : SubUIBase
{
Destroy(propPrefabParent.GetChild(i-1).gameObject);
}
if (item.rewardGold>=0)
if (item.rewardGold>0)
{
GameObject obj = Instantiate(propPrefab, propPrefabParent);
ResourceRequest request = Resources.LoadAsync<Sprite>("gold");
@@ -301,7 +301,7 @@ public class UIHome_BY_EmailPanel : SubUIBase
}
}
if (item.rewardDiamond>=0)
if (item.rewardDiamond>0)
{
GameObject obj = Instantiate(propPrefab, propPrefabParent);
@@ -114,11 +114,29 @@ public class UIHome_BY_SelectRoomLevelPanel : SubUIBase
}
public void OnSelectRoom(int leave)
{
//这里有问题 玩的人多了就不能完了
WebSocketSendList.GetRoomListFish(leave, 1);
//WebSocketManager.Instance.Send(SocketType.room, "{\"type\":1,\"target\":\"GetRoomList\",\"invocationId\":\"1\",\"arguments\":[\""+GameManager.Instance.user.id+"\","+(int)GameManager.Instance.gameData.currGameType+","+leave+",1]}");
//这里想websocket发送链接请求
//panel_UIHome_BY_MySelectRoomPenel.Show(json);
if (isMySelectRoom)
{
// 手动选座:走原 WebSocket 流程(GetRoomList → MySelectRoomPanel 显示列表)
WebSocketSendList.GetRoomListFish(leave, 1);
}
else
{
// ⭐ 快速加入:调 /api/Room/QuickJoin 拿 roomId + webSocketUrl → 连 socket → JoinRoom(-1)
int gameType = (int)GameManager.Instance.gameData.currGameType;
APIRequestList.RoomQuickJoin(gameType, leave, (resp) =>
{
if (resp == null || string.IsNullOrEmpty(resp.roomId))
{
UIManager.Instance.ShowBoardError("快速加入失败,请稍后重试");
return;
}
// 用 QuickJoin 返回的 webSocketUrl 直接连接 game socket,然后 JoinRoom(-1) 让服务器分配座位
GameManager.Instance.StartGameQuickJoin(resp.webSocketUrl, () =>
{
WebSocketSendList.JoinRoom(resp.roomId, GameManager.Instance.user.id, -1);
});
});
}
}
public static void StartGame(RoomChangeResponse o)
{