联机bug
This commit is contained in:
parent
6f46f28d0e
commit
b7de699820
@ -3136,7 +3136,6 @@ RectTransform:
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 2439448078848170519}
|
||||
- {fileID: 6639640428677976138}
|
||||
- {fileID: 2289778642835842229}
|
||||
- {fileID: 2823495548145270491}
|
||||
- {fileID: 7559943356464538090}
|
||||
@ -3146,6 +3145,7 @@ RectTransform:
|
||||
- {fileID: 287912720796096540}
|
||||
- {fileID: 5266944002495899053}
|
||||
- {fileID: 748938986039668253}
|
||||
- {fileID: 6639640428677976138}
|
||||
m_Father: {fileID: 1937094061063432054}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
@ -3926,7 +3926,7 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastTarget: 0
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
|
||||
@ -140,7 +140,8 @@ namespace TH1_Core.Events
|
||||
OutsideMultiplayRoomPasswordWrong,
|
||||
OutsideMultiplayOpenHint,
|
||||
OutsideMultiplayCantStartCount,
|
||||
OutsideMultiplayRoomNotReady
|
||||
OutsideMultiplayRoomNotReady,
|
||||
OutsideMultiplayRoomAutoCancelReady
|
||||
}
|
||||
public struct ShowUINotifyCommon
|
||||
{
|
||||
@ -163,6 +164,10 @@ namespace TH1_Core.Events
|
||||
|
||||
public struct UpdateUIOutsideMultiplayRoomSetting { }
|
||||
public struct UpdateUIOutsideMultiplayLobbyList { }
|
||||
public struct ShowUIOutsideMultiplayLobbyNotify
|
||||
{
|
||||
public UINotifyCommonType UINotifyCommonType;
|
||||
}
|
||||
public struct ShowUIOutsideSelect { }
|
||||
|
||||
public struct HideUIOutsideSelect { }
|
||||
|
||||
@ -864,9 +864,12 @@ namespace RuntimeData
|
||||
}
|
||||
|
||||
|
||||
[MemoryPackable]
|
||||
public partial class MemberCiv
|
||||
[MemoryPackable(GenerateType.NoGenerate)]
|
||||
public partial class MemberCiv : IMemoryPackable<MemberCiv>
|
||||
{
|
||||
private const byte CurrentSerializedMemberCount = 9;
|
||||
private const byte LegacySerializedMemberCountWithoutTeam = 8;
|
||||
|
||||
public ulong MemberId;
|
||||
public uint PlayerId;
|
||||
public uint CivId;
|
||||
@ -876,6 +879,82 @@ namespace RuntimeData
|
||||
public int TeamId;
|
||||
public bool IsAI;
|
||||
public bool IsCivFixed;
|
||||
|
||||
public static void RegisterFormatter()
|
||||
{
|
||||
MemoryPackFormatterProvider.Register(new MemberCivFormatter());
|
||||
}
|
||||
|
||||
public static void Serialize(ref MemoryPackWriter writer, ref MemberCiv value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNullObjectHeader();
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteObjectHeader(CurrentSerializedMemberCount);
|
||||
writer.WriteUnmanaged(value.MemberId);
|
||||
writer.WriteUnmanaged(value.PlayerId);
|
||||
writer.WriteUnmanaged(value.CivId);
|
||||
writer.WriteUnmanaged(value.ForceId);
|
||||
writer.WriteUnmanaged(value.IsReady);
|
||||
writer.WriteUnmanaged(value.Index);
|
||||
writer.WriteUnmanaged(value.TeamId);
|
||||
writer.WriteUnmanaged(value.IsAI);
|
||||
writer.WriteUnmanaged(value.IsCivFixed);
|
||||
}
|
||||
|
||||
public static void Deserialize(ref MemoryPackReader reader, ref MemberCiv value)
|
||||
{
|
||||
if (!reader.TryReadObjectHeader(out var memberCount))
|
||||
{
|
||||
value = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (memberCount != CurrentSerializedMemberCount
|
||||
&& memberCount != LegacySerializedMemberCountWithoutTeam)
|
||||
{
|
||||
MemoryPackSerializationException.ThrowInvalidPropertyCount(
|
||||
typeof(MemberCiv),
|
||||
CurrentSerializedMemberCount,
|
||||
memberCount);
|
||||
}
|
||||
|
||||
value ??= new MemberCiv();
|
||||
value.MemberId = reader.ReadUnmanaged<ulong>();
|
||||
value.PlayerId = reader.ReadUnmanaged<uint>();
|
||||
value.CivId = reader.ReadUnmanaged<uint>();
|
||||
value.ForceId = reader.ReadUnmanaged<uint>();
|
||||
value.IsReady = reader.ReadUnmanaged<bool>();
|
||||
value.Index = reader.ReadUnmanaged<int>();
|
||||
if (memberCount == LegacySerializedMemberCountWithoutTeam)
|
||||
{
|
||||
value.TeamId = MapConfig.NoTeamId;
|
||||
value.IsAI = reader.ReadUnmanaged<bool>();
|
||||
value.IsCivFixed = reader.ReadUnmanaged<bool>();
|
||||
}
|
||||
else
|
||||
{
|
||||
value.TeamId = Math.Max(MapConfig.NoTeamId, reader.ReadUnmanaged<int>());
|
||||
value.IsAI = reader.ReadUnmanaged<bool>();
|
||||
value.IsCivFixed = reader.ReadUnmanaged<bool>();
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class MemberCivFormatter : MemoryPackFormatter<MemberCiv>
|
||||
{
|
||||
public override void Serialize(ref MemoryPackWriter writer, ref MemberCiv value)
|
||||
{
|
||||
MemberCiv.Serialize(ref writer, ref value);
|
||||
}
|
||||
|
||||
public override void Deserialize(ref MemoryPackReader reader, ref MemberCiv value)
|
||||
{
|
||||
MemberCiv.Deserialize(ref reader, ref value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -50,6 +50,7 @@ public class TextDataAssets : ScriptableObject
|
||||
[MultilingualField]public string OutsideMultiplayRoomMuteSuccess;
|
||||
[MultilingualField]public string OutsideMultiplayRoomPasswordWrong;
|
||||
[MultilingualField]public string OutsideMultiplayRoomNotReady;
|
||||
[MultilingualField]public string OutsideMultiplayRoomAutoCancelReady;
|
||||
|
||||
[MultilingualField]public string OutsideHistoryDropListNoLimitP;
|
||||
[MultilingualField]public string OutsideHistoryDropList2P;
|
||||
|
||||
@ -420,7 +420,13 @@ namespace TH1_Logic.Steam
|
||||
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.LobbyMembersNotSynced);
|
||||
return;
|
||||
}
|
||||
var selfMemberId = LobbyManager.Instance.Lobby.GetSelfMemberId();
|
||||
var wasReady = Main.Instance.MapConfig?.IsMemberReady(selfMemberId) ?? false;
|
||||
Main.Instance.MapConfig = message.Config;
|
||||
var isReady = Main.Instance.MapConfig.IsMemberReady(selfMemberId);
|
||||
if (wasReady && !isReady)
|
||||
EventManager.Publish(new ShowUIOutsideMultiplayLobbyNotify { UINotifyCommonType = UINotifyCommonType.OutsideMultiplayRoomAutoCancelReady });
|
||||
|
||||
if (Main.Instance.MapConfig.HasSameLobbyMembers(LobbyManager.Instance.Lobby.GetAllMemberInfo()))
|
||||
{
|
||||
GameNetSender.Instance.MarkLobbyDataSyncedFromHost();
|
||||
|
||||
@ -55,6 +55,8 @@ namespace TH1_Logic.Steam
|
||||
// 连接超时追踪
|
||||
private readonly Dictionary<CSteamID, float> _connectionTimeouts = new Dictionary<CSteamID, float>();
|
||||
private const float ConnectionTimeout = 30f; // 30秒超时
|
||||
private const float ExpectedDisconnectSuppressSeconds = 15f;
|
||||
private readonly Dictionary<CSteamID, float> _expectedDisconnectPeers = new Dictionary<CSteamID, float>();
|
||||
|
||||
// 重连尝试计数
|
||||
private readonly Dictionary<CSteamID, int> _retryCount = new Dictionary<CSteamID, int>();
|
||||
@ -166,6 +168,7 @@ namespace TH1_Logic.Steam
|
||||
public bool ConnectToPeer(CSteamID steamID)
|
||||
{
|
||||
if (LobbyManager.Instance.Lobby.IsLobbyOwner()) return false;
|
||||
_expectedDisconnectPeers.Remove(steamID);
|
||||
if (_connections.TryGetValue(steamID, out var existingConnection))
|
||||
{
|
||||
if (TryGetConnectionState(existingConnection, out var state) && IsActiveConnectionState(state))
|
||||
@ -333,6 +336,7 @@ namespace TH1_Logic.Steam
|
||||
// 断开与指定玩家的连接
|
||||
public void DisconnectFromPeer(CSteamID steamID)
|
||||
{
|
||||
MarkExpectedDisconnect(steamID);
|
||||
if (!_connections.TryGetValue(steamID, out var connection))
|
||||
return;
|
||||
|
||||
@ -346,6 +350,12 @@ namespace TH1_Logic.Steam
|
||||
LogSystem.LogInfo($"Disconnected from peer: {steamID}");
|
||||
}
|
||||
|
||||
public void MarkExpectedDisconnect(CSteamID steamID)
|
||||
{
|
||||
if (IsValidRemotePeer(steamID))
|
||||
_expectedDisconnectPeers[steamID] = Time.time + ExpectedDisconnectSuppressSeconds;
|
||||
}
|
||||
|
||||
// 断开所有连接
|
||||
public void DisconnectAll()
|
||||
{
|
||||
@ -361,6 +371,7 @@ namespace TH1_Logic.Steam
|
||||
_outgoingPeerQueues.Clear();
|
||||
_outgoingPeerOrder.Clear();
|
||||
_outgoingSequences.Clear();
|
||||
_expectedDisconnectPeers.Clear();
|
||||
_outgoingQueuedBytes = 0;
|
||||
_outgoingPeerRoundRobinIndex = 0;
|
||||
LogSystem.LogInfo("Disconnected from all peers");
|
||||
@ -458,6 +469,13 @@ namespace TH1_Logic.Steam
|
||||
case ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_None:
|
||||
// 检查具体的失败原因
|
||||
var endReason = info.m_info.m_eEndReason;
|
||||
if (TryConsumeExpectedDisconnect(remote))
|
||||
{
|
||||
LogSystem.LogInfo($"Expected P2P disconnect completed: {remote}, reason: {endReason}");
|
||||
HandleDisconnection(remote, info.m_hConn);
|
||||
break;
|
||||
}
|
||||
|
||||
LogSystem.LogError($"Connection failed - Reason: {endReason}");
|
||||
var failureReason = $"Connection failed: {remote}, reason: {endReason}";
|
||||
MarkConnectionFailure(failureReason);
|
||||
@ -509,6 +527,15 @@ namespace TH1_Logic.Steam
|
||||
return isTimeout ? NetworkPlayerTipType.P2PConnectionTimeout : NetworkPlayerTipType.P2PConnectionFailed;
|
||||
}
|
||||
|
||||
private bool TryConsumeExpectedDisconnect(CSteamID remote)
|
||||
{
|
||||
if (!IsValidRemotePeer(remote)) return false;
|
||||
if (!_expectedDisconnectPeers.TryGetValue(remote, out var suppressUntil)) return false;
|
||||
|
||||
_expectedDisconnectPeers.Remove(remote);
|
||||
return Time.time <= suppressUntil;
|
||||
}
|
||||
|
||||
private void MarkConnectionFailure(string reason)
|
||||
{
|
||||
_lastConnectionFailureTime = Time.time;
|
||||
|
||||
@ -787,6 +787,7 @@ namespace TH1_Logic.Steam
|
||||
}
|
||||
|
||||
LogSystem.LogInfo($"Kicking member: {memberId}");
|
||||
SimpleP2P.Instance.MarkExpectedDisconnect(new CSteamID(memberId));
|
||||
|
||||
// 房主写 LobbyData(只有房主有权限设 LobbyData),所有客户端都能 GetLobbyData 读到
|
||||
// 之前用的是 SetLobbyMemberData,那个 API 只能设自己的成员数据,写出去对方根本读不到 —— 协议不匹配
|
||||
@ -1615,6 +1616,14 @@ namespace TH1_Logic.Steam
|
||||
// 房主切换时内部处理
|
||||
private void OnHostChangedInternal(CSteamID oldOwner, CSteamID newOwner)
|
||||
{
|
||||
if (Main.Instance?.GameLogic != null && Main.Instance.GameLogic.GetCurState() == GameState.Menu)
|
||||
{
|
||||
LogSystem.LogInfo($"Lobby host transferred in menu(oldHost={oldOwner}, newHost={newOwner})");
|
||||
CheckConnectionStatus();
|
||||
ReconcilePreGameLobbyMembers();
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldOwner.m_SteamID == GetSelfMemberId())
|
||||
{
|
||||
LogSystem.LogWarning($"Local host ownership changed to {newOwner}, waiting local disconnect handling");
|
||||
@ -1626,6 +1635,28 @@ namespace TH1_Logic.Steam
|
||||
HandleLocalSteamSessionLost($"Host changed from {oldOwner} to {newOwner}");
|
||||
}
|
||||
|
||||
private void ReconcilePreGameLobbyMembers()
|
||||
{
|
||||
if (!IsInLobby()) return;
|
||||
if (Main.Instance?.GameLogic == null || Main.Instance.GameLogic.GetCurState() != GameState.Menu) return;
|
||||
if (Main.Instance.MapConfig == null) return;
|
||||
|
||||
if (IsLobbyOwner())
|
||||
{
|
||||
if (Main.Instance.MapConfig.UpdateLobbyMember(GetAllMemberInfo()))
|
||||
Main.Instance.MapConfig.CheckMapConfigChanged();
|
||||
else
|
||||
EventManager.Publish(new UpdateUIOutsideMultiplayRoomSetting());
|
||||
|
||||
GameNetSender.Instance.ClearLobbyDataSyncState();
|
||||
return;
|
||||
}
|
||||
|
||||
GameNetSender.Instance.MarkLobbyDataSyncRequired();
|
||||
GameNetSender.Instance.RequestLobbyData(true);
|
||||
EventManager.Publish(new UpdateUIOutsideMultiplayRoomSetting());
|
||||
}
|
||||
|
||||
// 房间准备完毕时内部处理
|
||||
private void OnLobbyReadyInternal()
|
||||
{
|
||||
@ -1649,6 +1680,7 @@ namespace TH1_Logic.Steam
|
||||
var members = EnumerateMembers().ToList();
|
||||
LogSystem.LogInfo($"Lobby members changed. Count: {members.Count}");
|
||||
UpdateMemberInfo();
|
||||
ReconcilePreGameLobbyMembers();
|
||||
OnMembersChangedEvent?.Invoke(members);
|
||||
}
|
||||
|
||||
|
||||
@ -328,6 +328,8 @@ namespace TH1_UI.View.Outside
|
||||
|
||||
//Step #5 订阅大厅列表更新事件
|
||||
EventManager.Subscribe<UpdateUIOutsideMultiplayLobbyList>(OnLobbyListUpdated);
|
||||
EventManager.Unsubscribe<ShowUIOutsideMultiplayLobbyNotify>(OnLobbyNotify);
|
||||
EventManager.Subscribe<ShowUIOutsideMultiplayLobbyNotify>(OnLobbyNotify);
|
||||
|
||||
}
|
||||
|
||||
@ -456,8 +458,8 @@ namespace TH1_UI.View.Outside
|
||||
CreateRoomButton.gameObject.SetActive(false);
|
||||
NoRoomHint.gameObject.SetActive(false);
|
||||
|
||||
var memberList = _lobby.GetAllMemberInfo();
|
||||
ReconcileRoomMembers();
|
||||
var memberList = _lobby.GetAllMemberInfo();
|
||||
var multiCivs = Main.Instance.MapConfig.MultiCivs;
|
||||
BuildRoomMemberRows(memberList, multiCivs);
|
||||
RenderRoomMemberRows(multiCivs);
|
||||
@ -846,7 +848,6 @@ namespace TH1_UI.View.Outside
|
||||
}
|
||||
if (slotLayoutChanged)
|
||||
{
|
||||
Main.Instance.MapConfig.ResetGuestReadyStates();
|
||||
Main.Instance.MapConfig.CheckMapConfigChanged();
|
||||
}
|
||||
}
|
||||
@ -1894,6 +1895,7 @@ namespace TH1_UI.View.Outside
|
||||
|
||||
//取消订阅大厅列表更新事件
|
||||
EventManager.Unsubscribe<UpdateUIOutsideMultiplayLobbyList>(OnLobbyListUpdated);
|
||||
EventManager.Unsubscribe<ShowUIOutsideMultiplayLobbyNotify>(OnLobbyNotify);
|
||||
}
|
||||
|
||||
|
||||
@ -1918,6 +1920,11 @@ namespace TH1_UI.View.Outside
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLobbyNotify(ShowUIOutsideMultiplayLobbyNotify evt)
|
||||
{
|
||||
ShowLobbyNotify(evt.UINotifyCommonType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 点击刷新大厅按钮
|
||||
/// </summary>
|
||||
@ -2080,6 +2087,9 @@ namespace TH1_UI.View.Outside
|
||||
case UINotifyCommonType.OutsideMultiplayRoomNotReady:
|
||||
ShowMultiplayInsideNotify(Table.Instance.TextDataAssets.OutsideMultiplayRoomNotReady);
|
||||
break;
|
||||
case UINotifyCommonType.OutsideMultiplayRoomAutoCancelReady:
|
||||
ShowMultiplayInsideNotify(Table.Instance.TextDataAssets.OutsideMultiplayRoomAutoCancelReady);
|
||||
break;
|
||||
default:
|
||||
EventManager.Publish(new ShowUINotifyCommon { UINotifyCommonType = type });
|
||||
break;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user