联机准备代码

This commit is contained in:
wuwenbo 2026-05-19 15:41:54 +08:00
parent 9bc559cfc0
commit af2be3447c
5 changed files with 129 additions and 12 deletions

View File

@ -138,13 +138,33 @@ namespace RuntimeData
civ.MemberId = kv.Key;
civ.CivId = 0;
civ.ForceId = 0;
civ.IsReady = LobbyManager.Instance.Lobby.IsInLobby()
&& kv.Key == LobbyManager.Instance.Lobby.GetLobbyOwnerId();
MultiCivs.Add(civ);
changed = true;
}
changed |= EnsureLobbyOwnerReady();
RefreshMultiCivsDict();
return changed;
}
private bool EnsureLobbyOwnerReady()
{
if (!LobbyManager.Instance.Lobby.IsInLobby()) return false;
var ownerId = LobbyManager.Instance.Lobby.GetLobbyOwnerId();
if (ownerId == 0) return false;
var changed = false;
foreach (var memberCiv in MultiCivs)
{
if (memberCiv == null || memberCiv.MemberId != ownerId || memberCiv.IsReady) continue;
memberCiv.IsReady = true;
changed = true;
}
return changed;
}
// 内部刷新
private void RefreshMultiCivsDict()
{
@ -174,6 +194,10 @@ namespace RuntimeData
public bool UpdateMemberCiv(MemberCiv civ)
{
if (civ == null) return false;
var lobby = LobbyManager.Instance.Lobby;
if (lobby.IsInLobby() && civ.MemberId == lobby.GetLobbyOwnerId())
civ.IsReady = true;
if (LobbyManager.Instance.Lobby.IsInLobby() && !LobbyManager.Instance.Lobby.IsLobbyOwner())
{
var selfMemberId = LobbyManager.Instance.Lobby.GetSelfMemberId();
@ -197,6 +221,82 @@ namespace RuntimeData
return ApplyMemberCivLocal(civ);
}
public bool UpdateMemberReady(ulong memberId, bool isReady)
{
var memberCiv = GetMemberCiv(memberId);
if (memberCiv == null) return false;
var lobby = LobbyManager.Instance.Lobby;
var ownerId = lobby.IsInLobby() ? lobby.GetLobbyOwnerId() : 0;
var next = new MemberCiv
{
MemberId = memberCiv.MemberId,
PlayerId = memberCiv.PlayerId,
CivId = memberCiv.CivId,
ForceId = memberCiv.ForceId,
IsReady = memberId == ownerId || isReady
};
return UpdateMemberCiv(next);
}
public bool SetSelfReady(bool isReady)
{
if (!LobbyManager.Instance.Lobby.IsInLobby()) return false;
return UpdateMemberReady(LobbyManager.Instance.Lobby.GetSelfMemberId(), isReady);
}
public bool ToggleSelfReady()
{
if (!LobbyManager.Instance.Lobby.IsInLobby()) return false;
var selfMemberId = LobbyManager.Instance.Lobby.GetSelfMemberId();
return UpdateMemberReady(selfMemberId, !IsMemberReady(selfMemberId));
}
public bool IsMemberReady(ulong memberId)
{
if (LobbyManager.Instance.Lobby.IsInLobby()
&& memberId == LobbyManager.Instance.Lobby.GetLobbyOwnerId())
{
return true;
}
return GetMemberCiv(memberId)?.IsReady ?? false;
}
public bool AreAllLobbyMembersReady()
{
if (!LobbyManager.Instance.Lobby.IsInLobby()) return false;
var memberInfos = LobbyManager.Instance.Lobby.GetAllMemberInfo();
if (!HasSameLobbyMembers(memberInfos)) return false;
var ownerId = LobbyManager.Instance.Lobby.GetLobbyOwnerId();
foreach (var memberId in memberInfos.Keys)
{
if (memberId == ownerId) continue;
if (!IsMemberReady(memberId)) return false;
}
return true;
}
public bool ResetGuestReadyStates()
{
if (!LobbyManager.Instance.Lobby.IsInLobby() || !LobbyManager.Instance.Lobby.IsLobbyOwner()) return false;
MultiCivs ??= new List<MemberCiv>();
var ownerId = LobbyManager.Instance.Lobby.GetLobbyOwnerId();
var changed = false;
foreach (var memberCiv in MultiCivs)
{
if (memberCiv == null) continue;
var shouldReady = memberCiv.MemberId == ownerId;
if (memberCiv.IsReady == shouldReady) continue;
memberCiv.IsReady = shouldReady;
changed = true;
}
return changed;
}
private bool ApplyMemberCivLocal(MemberCiv civ)
{
MultiCivs ??= new List<MemberCiv>();
@ -204,10 +304,14 @@ namespace RuntimeData
{
if (memberCiv == null) continue;
if (memberCiv.MemberId != civ.MemberId) continue;
if (memberCiv.CivId == civ.CivId && memberCiv.ForceId == civ.ForceId) return false;
if (memberCiv.CivId == civ.CivId
&& memberCiv.ForceId == civ.ForceId
&& memberCiv.PlayerId == civ.PlayerId
&& memberCiv.IsReady == civ.IsReady) return false;
memberCiv.CivId = civ.CivId;
memberCiv.ForceId = civ.ForceId;
memberCiv.PlayerId = civ.PlayerId;
memberCiv.IsReady = civ.IsReady;
RefreshMultiCivsDict();
return true;
}
@ -217,7 +321,8 @@ namespace RuntimeData
MemberId = civ.MemberId,
CivId = civ.CivId,
ForceId = civ.ForceId,
PlayerId = civ.PlayerId
PlayerId = civ.PlayerId,
IsReady = civ.IsReady
});
RefreshMultiCivsDict();
return true;
@ -348,6 +453,7 @@ namespace RuntimeData
public uint PlayerId;
public uint CivId;
public uint ForceId;
public bool IsReady;
}

View File

@ -340,7 +340,7 @@ namespace TH1_Logic.Steam
&& mapData.UnitMap != null;
}
// 只有房主会收到
// 成员房间配置变更(阵营/准备状态),只有房主会收到
private void OnReceivedChangeCiv(ChangeCivMessage message)
{
if (message == null)

View File

@ -195,7 +195,7 @@ namespace TH1_Logic.Steam
return true;
}
// 修改阵营 (成员 => 房主)
// 修改成员房间配置(阵营/准备状态,成员 => 房主)
public bool ChangeCiv(MemberCiv memberCiv)
{
if (memberCiv == null)

View File

@ -123,8 +123,10 @@ public class UIOutsideMultiplayMemberRowMono : MonoBehaviour
var next = new MemberCiv
{
MemberId = selfMemberId,
PlayerId = t.PlayerId,
CivId = Table.Instance.TransCivEnumToCivId(civ),
ForceId = Table.Instance.TransForceEnumToForceId(force)
ForceId = Table.Instance.TransForceEnumToForceId(force),
IsReady = false
};
var accepted = Main.Instance.MapConfig.UpdateMemberCiv(next);

View File

@ -491,7 +491,7 @@ namespace TH1_UI.View.Outside
// CREATIVE 模式下 MapSize 由玩家自由选择,不再被 PlayerCount 联动
if (GameMode != null && GameMode.SelectedIndex == 2)
{
SetMapConfig();
SetMapConfig(resetGuestReady: true);
RoomSettingOnPlayerCountClicked(Main.Instance.MapConfig.PlayerCount, Main.Instance.MapConfig.Width);
return;
}
@ -504,14 +504,14 @@ namespace TH1_UI.View.Outside
_ => 3
};
MapSize.Select(mapSizeIdx);
SetMapConfig();
SetMapConfig(resetGuestReady: true);
RoomSettingOnPlayerCountClicked(Main.Instance.MapConfig.PlayerCount,Main.Instance.MapConfig.Width);
}
public void OnDiffOptionClicked(uint idx)
{
if (!_lobby.IsLobbyOwner()) return;
SetMapConfig();
SetMapConfig(resetGuestReady: true);
RoomSettingOnDifficultyClicked(Main.Instance.MapConfig.AIDiff);
}
@ -519,7 +519,7 @@ namespace TH1_UI.View.Outside
{
if (!_lobby.IsLobbyOwner()) return;
if (GameMode != null && GameMode.SelectedIndex != 2) return;
SetMapConfig();
SetMapConfig(resetGuestReady: true);
Main.Instance.MapConfig.CheckMapConfigChanged();
}
@ -637,6 +637,12 @@ namespace TH1_UI.View.Outside
if (!_lobby.IsLobbyOwner())
return;
if (!Main.Instance.MapConfig.AreAllLobbyMembersReady())
{
Debug.Log("Cannot start multiplayer game: not all members are ready");
return;
}
//Step #2 如果是继续存档,直接开始
if(Main.Instance.HasMultiArchive() && ResumeToggle.isOn){
@ -670,7 +676,7 @@ namespace TH1_UI.View.Outside
ShowLoadingAndStartGame(false);
}
private void SetMapConfig()
private void SetMapConfig(bool resetGuestReady = false)
{
uint gameModeIdx = GameMode != null ? GameMode.SelectedIndex : 0;
@ -723,6 +729,7 @@ namespace TH1_UI.View.Outside
Main.Instance.MapConfig.AIDiff = diff;
Main.Instance.MapConfig.GameMode = gameMode;
Main.Instance.MapConfig.WaterType = waterType;
if (resetGuestReady) Main.Instance.MapConfig.ResetGuestReadyStates();
// CREATIVE 下持久化 MapSize 选择(独立 key不与单机冲突
if (gameMode == RuntimeData.GameMode.CREATIVE)
@ -783,6 +790,7 @@ namespace TH1_UI.View.Outside
Main.Instance.MapConfig.PlayerCount = playerCount;
Main.Instance.MapConfig.Width = mapSize;
Main.Instance.MapConfig.Height = mapSize;
if (_lobby.IsLobbyOwner()) Main.Instance.MapConfig.ResetGuestReadyStates();
// 触发房主→成员的整包广播hash 比对幂等,不会刷屏)
Main.Instance.MapConfig.CheckMapConfigChanged();
}
@ -790,6 +798,7 @@ namespace TH1_UI.View.Outside
public void RoomSettingOnDifficultyClicked(AIDifficult difficult)
{
Main.Instance.MapConfig.AIDiff = difficult;
if (_lobby.IsLobbyOwner()) Main.Instance.MapConfig.ResetGuestReadyStates();
Main.Instance.MapConfig.CheckMapConfigChanged();
}
@ -837,7 +846,7 @@ namespace TH1_UI.View.Outside
if (syncConfig)
{
SetMapConfig();
SetMapConfig(resetGuestReady: true);
// 复用既有房主→成员广播入口CheckMapConfigChanged 内部已调用)
RoomSettingOnPlayerCountClicked(Main.Instance.MapConfig.PlayerCount, Main.Instance.MapConfig.Width);
}
@ -846,7 +855,7 @@ namespace TH1_UI.View.Outside
public void OnWaterOptionClicked(uint idx)
{
if (!_lobby.IsLobbyOwner()) return;
SetMapConfig();
SetMapConfig(resetGuestReady: true);
Main.Instance.MapConfig.CheckMapConfigChanged();
}