队伍系统
This commit is contained in:
parent
2952effbe2
commit
a3e26c3af3
@ -48,6 +48,8 @@ namespace RuntimeData
|
||||
[MemoryPackable]
|
||||
public partial class MapConfig
|
||||
{
|
||||
public const int NoTeamId = 0;
|
||||
|
||||
public uint Id;
|
||||
public uint Width;
|
||||
public uint Height;
|
||||
@ -67,7 +69,7 @@ namespace RuntimeData
|
||||
public uint selfCivId;
|
||||
public uint selfForceId;
|
||||
|
||||
// 联机用
|
||||
// 玩家位置槽位。旧名保留用于兼容现有序列化/联机消息。
|
||||
public List<MemberCiv> MultiCivs;
|
||||
private Dictionary<ulong, MemberCiv> _memberCivs;
|
||||
|
||||
@ -104,6 +106,9 @@ namespace RuntimeData
|
||||
selfForceId = forceId;
|
||||
MultiCivs = new List<MemberCiv>();
|
||||
_memberCivs = new Dictionary<ulong, MemberCiv>();
|
||||
PlayerSettlements = new List<PlayerSettlementInfo>();
|
||||
MatchLimits = new List<MatchLimitType>();
|
||||
EnsurePlayerSlots(NetMode.Single);
|
||||
}
|
||||
|
||||
// MemoryPack 反序列化之后的后处理
|
||||
@ -117,30 +122,128 @@ namespace RuntimeData
|
||||
MultiCivs ??= new List<MemberCiv>();
|
||||
PlayerSettlements ??= new List<PlayerSettlementInfo>();
|
||||
MatchLimits ??= new List<MatchLimitType>();
|
||||
EnsurePlayerSlots(NetMode.Multi);
|
||||
RefreshMultiCivsDict();
|
||||
}
|
||||
|
||||
public void EnsurePlayerSlots(NetMode netMode = NetMode.Multi)
|
||||
{
|
||||
MultiCivs ??= new List<MemberCiv>();
|
||||
var targetCount = (int)PlayerCount;
|
||||
|
||||
for (int i = 0; i < MultiCivs.Count; i++)
|
||||
{
|
||||
MultiCivs[i] ??= CreateDefaultPlayerSlot(i, netMode);
|
||||
}
|
||||
|
||||
while (MultiCivs.Count < targetCount)
|
||||
{
|
||||
MultiCivs.Add(CreateDefaultPlayerSlot(MultiCivs.Count, netMode));
|
||||
}
|
||||
|
||||
if (MultiCivs.Count > targetCount)
|
||||
{
|
||||
MultiCivs.RemoveRange(targetCount, MultiCivs.Count - targetCount);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MultiCivs.Count; i++)
|
||||
{
|
||||
NormalizePlayerSlot(MultiCivs[i], i);
|
||||
}
|
||||
|
||||
if (netMode == NetMode.Single) ApplySinglePlayerSlotDefaults();
|
||||
RefreshMultiCivsDict();
|
||||
}
|
||||
|
||||
private MemberCiv CreateDefaultPlayerSlot(int index, NetMode netMode)
|
||||
{
|
||||
var slot = new MemberCiv
|
||||
{
|
||||
Index = index,
|
||||
MemberId = 0,
|
||||
PlayerId = 0,
|
||||
CivId = 0,
|
||||
ForceId = 0,
|
||||
TeamId = NoTeamId,
|
||||
IsAI = true,
|
||||
IsReady = false,
|
||||
IsCivFixed = false
|
||||
};
|
||||
|
||||
if (netMode == NetMode.Single)
|
||||
{
|
||||
ApplySinglePlayerSlotDefault(slot, index);
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
private void ApplySinglePlayerSlotDefaults()
|
||||
{
|
||||
for (int i = 0; i < MultiCivs.Count; i++)
|
||||
{
|
||||
ClearPlayerSlotMember(MultiCivs[i], makeAi: i != 0);
|
||||
ApplySinglePlayerSlotDefault(MultiCivs[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplySinglePlayerSlotDefault(MemberCiv slot, int index)
|
||||
{
|
||||
slot.Index = index;
|
||||
slot.IsAI = index != 0;
|
||||
slot.IsReady = false;
|
||||
slot.PlayerId = 0;
|
||||
slot.TeamId = NoTeamId;
|
||||
slot.IsCivFixed = true;
|
||||
if (index == 0)
|
||||
{
|
||||
slot.CivId = selfCivId;
|
||||
slot.ForceId = selfForceId;
|
||||
return;
|
||||
}
|
||||
|
||||
slot.CivId = selfCivId == index ? 0u : (uint)index;
|
||||
slot.ForceId = selfCivId == index ? 0u : (uint)index;
|
||||
}
|
||||
|
||||
private void NormalizePlayerSlot(MemberCiv slot, int index)
|
||||
{
|
||||
slot.Index = index;
|
||||
if (slot.TeamId < NoTeamId) slot.TeamId = NoTeamId;
|
||||
if (slot.MemberId != 0) slot.IsAI = false;
|
||||
if (slot.MemberId == 0) slot.PlayerId = 0;
|
||||
}
|
||||
|
||||
// 根据房间成员信息更新 mapconfig 信息
|
||||
public bool UpdateLobbyMember(Dictionary<ulong, MemberInfo> memberInfos)
|
||||
{
|
||||
if (memberInfos == null) return false;
|
||||
MultiCivs ??= new List<MemberCiv>();
|
||||
EnsurePlayerSlots(NetMode.Multi);
|
||||
var changed = false;
|
||||
// 先剔除已离开 lobby 的成员,避免 MultiCivs 留下幽灵占位:
|
||||
// 旧版只 Add 不 Remove,会导致大厅 nP 跳号(1P/4P/5P/6P),
|
||||
// 以及开战时给离线幽灵创 PlayerData、占用 PlayerCount 名额、AI 补位变少。
|
||||
changed |= MultiCivs.RemoveAll(mc => mc == null || !memberInfos.ContainsKey(mc.MemberId)) > 0;
|
||||
// 先解绑已离开 lobby 的成员,避免槽位留下幽灵真人。
|
||||
foreach (var slot in MultiCivs)
|
||||
{
|
||||
if (slot == null || slot.MemberId == 0 || memberInfos.ContainsKey(slot.MemberId)) continue;
|
||||
ClearPlayerSlotMember(slot, makeAi: true, clearCiv: true);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
RefreshMultiCivsDict();
|
||||
foreach (var kv in memberInfos)
|
||||
{
|
||||
if (_memberCivs.ContainsKey(kv.Key)) continue;
|
||||
var civ = new MemberCiv();
|
||||
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);
|
||||
var slot = GetFirstAssignableSlot();
|
||||
if (slot == null)
|
||||
{
|
||||
LogSystem.LogError($"房间人数超过玩家槽位数量: member={kv.Key}, playerCount={PlayerCount}");
|
||||
continue;
|
||||
}
|
||||
|
||||
slot.MemberId = kv.Key;
|
||||
slot.PlayerId = 0;
|
||||
slot.IsAI = false;
|
||||
slot.IsReady = LobbyManager.Instance.Lobby.IsInLobby()
|
||||
&& kv.Key == LobbyManager.Instance.Lobby.GetLobbyOwnerId();
|
||||
changed = true;
|
||||
}
|
||||
changed |= EnsureLobbyOwnerReady();
|
||||
@ -148,6 +251,29 @@ namespace RuntimeData
|
||||
return changed;
|
||||
}
|
||||
|
||||
private MemberCiv GetFirstAssignableSlot()
|
||||
{
|
||||
foreach (var slot in MultiCivs)
|
||||
{
|
||||
if (slot == null || slot.MemberId != 0) continue;
|
||||
return slot;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void ClearPlayerSlotMember(MemberCiv slot, bool makeAi, bool clearCiv = false)
|
||||
{
|
||||
slot.MemberId = 0;
|
||||
slot.PlayerId = 0;
|
||||
slot.IsReady = false;
|
||||
slot.IsAI = makeAi;
|
||||
if (!clearCiv) return;
|
||||
slot.CivId = 0;
|
||||
slot.ForceId = 0;
|
||||
slot.IsCivFixed = false;
|
||||
}
|
||||
|
||||
private bool EnsureLobbyOwnerReady()
|
||||
{
|
||||
if (!LobbyManager.Instance.Lobby.IsInLobby()) return false;
|
||||
@ -174,6 +300,7 @@ namespace RuntimeData
|
||||
foreach (var memberCiv in MultiCivs)
|
||||
{
|
||||
if (memberCiv == null) continue;
|
||||
if (memberCiv.MemberId == 0) continue;
|
||||
_memberCivs[memberCiv.MemberId] = memberCiv;
|
||||
}
|
||||
}
|
||||
@ -189,6 +316,135 @@ namespace RuntimeData
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public MemberCiv GetPlayerSlot(int index)
|
||||
{
|
||||
EnsurePlayerSlots(NetMode.Multi);
|
||||
if (index < 0 || index >= MultiCivs.Count) return null;
|
||||
return MultiCivs[index];
|
||||
}
|
||||
|
||||
public bool SetPlayerSlotTeam(int index, int teamId)
|
||||
{
|
||||
var slot = GetPlayerSlot(index);
|
||||
if (slot == null) return false;
|
||||
teamId = Math.Max(NoTeamId, teamId);
|
||||
if (slot.TeamId == teamId) return false;
|
||||
slot.TeamId = teamId;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetPlayerSlotAI(int index, bool isAI)
|
||||
{
|
||||
var slot = GetPlayerSlot(index);
|
||||
if (slot == null) return false;
|
||||
if (isAI)
|
||||
{
|
||||
var changed = slot.MemberId != 0 || !slot.IsAI;
|
||||
ClearPlayerSlotMember(slot, makeAi: true);
|
||||
return changed;
|
||||
}
|
||||
|
||||
if (!slot.IsAI) return false;
|
||||
slot.IsAI = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetPlayerSlotCiv(int index, uint civId, uint forceId)
|
||||
{
|
||||
var slot = GetPlayerSlot(index);
|
||||
if (slot == null) return false;
|
||||
if (slot.CivId == civId && slot.ForceId == forceId && slot.IsCivFixed) return false;
|
||||
slot.CivId = civId;
|
||||
slot.ForceId = forceId;
|
||||
slot.IsCivFixed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetMemberSlot(ulong memberId, int index)
|
||||
{
|
||||
if (memberId == 0) return false;
|
||||
EnsurePlayerSlots(NetMode.Multi);
|
||||
if (index < 0 || index >= MultiCivs.Count) return false;
|
||||
|
||||
var current = GetMemberCiv(memberId);
|
||||
var target = MultiCivs[index];
|
||||
if (target.MemberId != 0 && target.MemberId != memberId) return false;
|
||||
if (current == target) return false;
|
||||
|
||||
if (current != null) ClearPlayerSlotMember(current, makeAi: true, clearCiv: true);
|
||||
target.MemberId = memberId;
|
||||
target.PlayerId = 0;
|
||||
target.IsAI = false;
|
||||
target.IsReady = false;
|
||||
EnsureLobbyOwnerReady();
|
||||
RefreshMultiCivsDict();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryGetTeamIdByPlayerId(uint playerId, out int teamId)
|
||||
{
|
||||
teamId = NoTeamId;
|
||||
if (playerId == 0 || MultiCivs == null) return false;
|
||||
foreach (var slot in MultiCivs)
|
||||
{
|
||||
if (slot == null || slot.PlayerId != playerId) continue;
|
||||
teamId = slot.TeamId;
|
||||
return teamId != NoTeamId;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool ArePlayersInSameTeam(uint playerIdA, uint playerIdB)
|
||||
{
|
||||
if (playerIdA == 0 || playerIdB == 0 || playerIdA == playerIdB) return false;
|
||||
return TryGetTeamIdByPlayerId(playerIdA, out var teamA)
|
||||
&& TryGetTeamIdByPlayerId(playerIdB, out var teamB)
|
||||
&& teamA != NoTeamId
|
||||
&& teamA == teamB;
|
||||
}
|
||||
|
||||
public void ApplyTeamDiplomacy(MapData mapData)
|
||||
{
|
||||
if (mapData?.PlayerMap?.PlayerDataList == null) return;
|
||||
EnsurePlayerSlots(mapData.Net?.Mode ?? NetMode.Multi);
|
||||
BindSlotPlayerIdsByIndex(mapData);
|
||||
|
||||
foreach (var player in mapData.PlayerMap.PlayerDataList)
|
||||
{
|
||||
if (player == null) continue;
|
||||
foreach (var target in mapData.PlayerMap.PlayerDataList)
|
||||
{
|
||||
if (target == null || player.Id == target.Id) continue;
|
||||
if (!ArePlayersInSameTeam(player.Id, target.Id)) continue;
|
||||
if (player.GetCountryDiplomacyInfo(target.Id, out var info))
|
||||
{
|
||||
ApplyTeammateDiplomacy(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void BindSlotPlayerIdsByIndex(MapData mapData)
|
||||
{
|
||||
if (mapData?.PlayerMap?.PlayerDataList == null || MultiCivs == null) return;
|
||||
for (int i = 0; i < MultiCivs.Count; i++)
|
||||
{
|
||||
if (i >= mapData.PlayerMap.PlayerDataList.Count) break;
|
||||
if (MultiCivs[i] == null) continue;
|
||||
MultiCivs[i].PlayerId = mapData.PlayerMap.PlayerDataList[i].Id;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ApplyTeammateDiplomacy(CountryDiplomacyInfo info)
|
||||
{
|
||||
if (info == null) return;
|
||||
info.IsTeammate = true;
|
||||
info.DiplomacyState = DiplomacyState.League;
|
||||
info.IsLeagueRequest = false;
|
||||
info.IsLeagueRupture = false;
|
||||
}
|
||||
|
||||
// 主从端一致的更新某一个成员信息
|
||||
public bool UpdateMemberCiv(MemberCiv civ)
|
||||
@ -230,10 +486,14 @@ namespace RuntimeData
|
||||
var ownerId = lobby.IsInLobby() ? lobby.GetLobbyOwnerId() : 0;
|
||||
var next = new MemberCiv
|
||||
{
|
||||
Index = memberCiv.Index,
|
||||
MemberId = memberCiv.MemberId,
|
||||
PlayerId = memberCiv.PlayerId,
|
||||
CivId = memberCiv.CivId,
|
||||
ForceId = memberCiv.ForceId,
|
||||
TeamId = memberCiv.TeamId,
|
||||
IsAI = memberCiv.IsAI,
|
||||
IsCivFixed = memberCiv.IsCivFixed,
|
||||
IsReady = memberId == ownerId || isReady
|
||||
};
|
||||
return UpdateMemberCiv(next);
|
||||
@ -268,6 +528,11 @@ namespace RuntimeData
|
||||
if (!LobbyManager.Instance.Lobby.IsInLobby()) return false;
|
||||
var memberInfos = LobbyManager.Instance.Lobby.GetAllMemberInfo();
|
||||
if (!HasSameLobbyMembers(memberInfos)) return false;
|
||||
foreach (var slot in MultiCivs)
|
||||
{
|
||||
if (slot == null) return false;
|
||||
if (slot.MemberId == 0 && !slot.IsAI) return false;
|
||||
}
|
||||
|
||||
var ownerId = LobbyManager.Instance.Lobby.GetLobbyOwnerId();
|
||||
foreach (var memberId in memberInfos.Keys)
|
||||
@ -299,31 +564,42 @@ namespace RuntimeData
|
||||
|
||||
private bool ApplyMemberCivLocal(MemberCiv civ)
|
||||
{
|
||||
MultiCivs ??= new List<MemberCiv>();
|
||||
foreach (var memberCiv in MultiCivs)
|
||||
EnsurePlayerSlots(NetMode.Multi);
|
||||
var memberCiv = civ.MemberId != 0 ? GetMemberCiv(civ.MemberId) : null;
|
||||
var targetIndex = civ.Index;
|
||||
var targetSlot = targetIndex >= 0 && targetIndex < MultiCivs.Count ? MultiCivs[targetIndex] : null;
|
||||
|
||||
if (memberCiv != null && targetSlot != null && memberCiv != targetSlot && targetSlot.MemberId == 0)
|
||||
{
|
||||
if (memberCiv == null) continue;
|
||||
if (memberCiv.MemberId != civ.MemberId) continue;
|
||||
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;
|
||||
ClearPlayerSlotMember(memberCiv, makeAi: true, clearCiv: true);
|
||||
memberCiv = targetSlot;
|
||||
}
|
||||
|
||||
MultiCivs.Add(new MemberCiv
|
||||
{
|
||||
MemberId = civ.MemberId,
|
||||
CivId = civ.CivId,
|
||||
ForceId = civ.ForceId,
|
||||
PlayerId = civ.PlayerId,
|
||||
IsReady = civ.IsReady
|
||||
});
|
||||
memberCiv ??= targetSlot;
|
||||
if (memberCiv == null) return false;
|
||||
|
||||
var nextMemberId = civ.MemberId;
|
||||
var nextIsAI = nextMemberId == 0 && civ.IsAI;
|
||||
if (nextMemberId != 0) nextIsAI = false;
|
||||
|
||||
if (memberCiv.MemberId == nextMemberId
|
||||
&& memberCiv.CivId == civ.CivId
|
||||
&& memberCiv.ForceId == civ.ForceId
|
||||
&& memberCiv.PlayerId == civ.PlayerId
|
||||
&& memberCiv.TeamId == civ.TeamId
|
||||
&& memberCiv.IsAI == nextIsAI
|
||||
&& memberCiv.IsCivFixed == civ.IsCivFixed
|
||||
&& memberCiv.IsReady == civ.IsReady) return false;
|
||||
|
||||
memberCiv.MemberId = nextMemberId;
|
||||
memberCiv.CivId = civ.CivId;
|
||||
memberCiv.ForceId = civ.ForceId;
|
||||
memberCiv.PlayerId = civ.PlayerId;
|
||||
memberCiv.TeamId = civ.TeamId;
|
||||
memberCiv.IsAI = nextIsAI;
|
||||
memberCiv.IsCivFixed = civ.IsCivFixed;
|
||||
memberCiv.IsReady = civ.IsReady;
|
||||
NormalizePlayerSlot(memberCiv, memberCiv.Index);
|
||||
RefreshMultiCivsDict();
|
||||
return true;
|
||||
}
|
||||
@ -331,13 +607,13 @@ namespace RuntimeData
|
||||
public bool HasSameLobbyMembers(Dictionary<ulong, MemberInfo> memberInfos)
|
||||
{
|
||||
if (memberInfos == null) return false;
|
||||
MultiCivs ??= new List<MemberCiv>();
|
||||
if (MultiCivs.Count != memberInfos.Count) return false;
|
||||
EnsurePlayerSlots(NetMode.Multi);
|
||||
|
||||
var seen = new HashSet<ulong>();
|
||||
foreach (var memberCiv in MultiCivs)
|
||||
{
|
||||
if (memberCiv == null) return false;
|
||||
if (memberCiv.MemberId == 0) continue;
|
||||
if (!memberInfos.ContainsKey(memberCiv.MemberId)) return false;
|
||||
if (!seen.Add(memberCiv.MemberId)) return false;
|
||||
}
|
||||
@ -364,6 +640,7 @@ namespace RuntimeData
|
||||
// 从 MapData 中重绑定 MemberCiv 的 Player 信息
|
||||
public bool ReBindPlayerInfoFromMapData(MapData mapData)
|
||||
{
|
||||
EnsurePlayerSlots(mapData.Net.Mode);
|
||||
RefreshMultiCivsDict();
|
||||
if (mapData.Net.Mode == NetMode.Single)
|
||||
{
|
||||
@ -384,13 +661,21 @@ namespace RuntimeData
|
||||
{
|
||||
foreach (var member in MultiCivs)
|
||||
{
|
||||
foreach (var player in mapData.PlayerMap.PlayerDataList)
|
||||
if (member.Index >= 0 && member.Index < mapData.PlayerMap.PlayerDataList.Count)
|
||||
{
|
||||
if (player.PlayerCivId != member.CivId || player.PlayerForceId != member.ForceId) continue;
|
||||
member.PlayerId = player.Id;
|
||||
member.PlayerId = mapData.PlayerMap.PlayerDataList[member.Index].Id;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var player in mapData.PlayerMap.PlayerDataList)
|
||||
{
|
||||
if (player.PlayerCivId != member.CivId || player.PlayerForceId != member.ForceId) continue;
|
||||
member.PlayerId = player.Id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (member.PlayerId == 0)
|
||||
if (member.MemberId != 0 && member.PlayerId == 0)
|
||||
{
|
||||
LogSystem.LogError($"联机模式指定地图中找不到指定的阵营信息, 启动游戏失败, " +
|
||||
$"地图 ID : {Id} 文明 ID : {member.CivId} 势力 ID : {member.ForceId}");
|
||||
@ -398,12 +683,20 @@ namespace RuntimeData
|
||||
}
|
||||
}
|
||||
}
|
||||
ApplyTeamDiplomacy(mapData);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ClearMultiCivs()
|
||||
{
|
||||
MultiCivs?.Clear();
|
||||
if (MultiCivs != null)
|
||||
{
|
||||
foreach (var slot in MultiCivs)
|
||||
{
|
||||
ClearPlayerSlotMember(slot, makeAi: true, clearCiv: true);
|
||||
slot.TeamId = NoTeamId;
|
||||
}
|
||||
}
|
||||
_memberCivs?.Clear();
|
||||
}
|
||||
|
||||
@ -449,10 +742,14 @@ namespace RuntimeData
|
||||
[MemoryPackable]
|
||||
public partial class MemberCiv
|
||||
{
|
||||
public int Index;
|
||||
public ulong MemberId;
|
||||
public uint PlayerId;
|
||||
public uint CivId;
|
||||
public uint ForceId;
|
||||
public int TeamId;
|
||||
public bool IsAI;
|
||||
public bool IsCivFixed;
|
||||
public bool IsReady;
|
||||
}
|
||||
|
||||
@ -1009,7 +1306,7 @@ namespace RuntimeData
|
||||
if (pidA == pidB) return true;
|
||||
if (!PlayerMap.GetPlayerDataByPlayerID(pidA, out var pA)) return false;
|
||||
pA.GetCountryDiplomacyInfo(pidB,out var dipInfo);
|
||||
return dipInfo.DiplomacyState == DiplomacyState.League;
|
||||
return dipInfo != null && (dipInfo.IsTeammate || dipInfo.DiplomacyState == DiplomacyState.League);
|
||||
}
|
||||
|
||||
public bool SameUnionByUnitId(uint uidA, uint uidB)
|
||||
@ -1025,7 +1322,9 @@ namespace RuntimeData
|
||||
if (pidA == pidB) return true;
|
||||
if (!PlayerMap.GetPlayerDataByPlayerID(pidA, out var pA)) return false;
|
||||
pA.GetCountryDiplomacyInfo(pidB,out var dipInfo);
|
||||
return dipInfo.DiplomacyState is DiplomacyState.League or DiplomacyState.LeagueRupture ;
|
||||
return dipInfo != null
|
||||
&& (dipInfo.IsTeammate
|
||||
|| dipInfo.DiplomacyState is DiplomacyState.League or DiplomacyState.LeagueRupture);
|
||||
}
|
||||
|
||||
//-------------- 查询方法方法 -------------------//
|
||||
@ -1558,6 +1857,7 @@ namespace RuntimeData
|
||||
action.Param.MapData = this;
|
||||
action.Param.RefreshParams();
|
||||
}
|
||||
MapConfig?.ApplyTeamDiplomacy(this);
|
||||
}
|
||||
|
||||
// 当场上有小兵受伤前
|
||||
@ -2304,10 +2604,26 @@ namespace RuntimeData
|
||||
// 游戏是否结束
|
||||
public bool CheckIfGameEnd(out bool isWin)
|
||||
{
|
||||
isWin = MatchSettlement.IsWin(PlayerMap.SelfPlayerId);
|
||||
isWin = IsPlayerOrTeammateWin(PlayerMap.SelfPlayerId);
|
||||
return MatchSettlement.IsFinished;
|
||||
}
|
||||
|
||||
public bool IsPlayerOrTeammateWin(uint playerId)
|
||||
{
|
||||
if (MatchSettlement == null) return false;
|
||||
if (MatchSettlement.IsWin(playerId)) return true;
|
||||
if (MapConfig == null || PlayerMap?.PlayerDataList == null) return false;
|
||||
|
||||
foreach (var player in PlayerMap.PlayerDataList)
|
||||
{
|
||||
if (player == null || player.Id == playerId) continue;
|
||||
if (!MapConfig.ArePlayersInSameTeam(playerId, player.Id)) continue;
|
||||
if (MatchSettlement.IsWin(player.Id)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// // 游戏是否结束
|
||||
// public bool CheckIfGameEnd(out bool isWin)
|
||||
// {
|
||||
|
||||
@ -305,7 +305,11 @@ namespace RuntimeData
|
||||
{
|
||||
if (memberCiv == null || memberCiv.PlayerId == 0) continue;
|
||||
if (!lobbyMemberSet.Contains(memberCiv.MemberId)) continue;
|
||||
if (Players.ContainsKey(memberCiv.MemberId)) continue;
|
||||
if (Players.TryGetValue(memberCiv.MemberId, out var mappedPlayerId))
|
||||
{
|
||||
if (mappedPlayerId != memberCiv.PlayerId) Players[memberCiv.MemberId] = memberCiv.PlayerId;
|
||||
continue;
|
||||
}
|
||||
if (Players.ContainsValue(memberCiv.PlayerId)) continue;
|
||||
Players[memberCiv.MemberId] = memberCiv.PlayerId;
|
||||
}
|
||||
|
||||
@ -118,47 +118,44 @@ namespace RuntimeData
|
||||
|
||||
if (netMode == NetMode.Single)
|
||||
{
|
||||
for (int i = 0; i < map.MapConfig.PlayerCount; i++)
|
||||
map.MapConfig.EnsurePlayerSlots(NetMode.Single);
|
||||
for (int i = 0; i < map.MapConfig.MultiCivs.Count; i++)
|
||||
{
|
||||
PlayerData player;
|
||||
//处理player到底是谁的问题。目前临时使用的方案,今后要改。目前civ一定=force,所以可以这么做
|
||||
if (i == 0)
|
||||
player = new PlayerData(map.MapConfig.selfCivId,map.MapConfig.selfForceId,idGenerator);
|
||||
else if (map.MapConfig.selfCivId == i)
|
||||
player = new PlayerData((uint)0,(uint)0,idGenerator);
|
||||
else
|
||||
player = new PlayerData((uint)i,(uint)i,idGenerator);
|
||||
var slot = map.MapConfig.MultiCivs[i];
|
||||
var player = new PlayerData(slot.CivId, slot.ForceId, idGenerator);
|
||||
PlayerDataList.Add(player);
|
||||
_playerDataDict[player.Id] = player;
|
||||
slot.PlayerId = player.Id;
|
||||
}
|
||||
}
|
||||
if (netMode == NetMode.Multi)
|
||||
{
|
||||
map.MapConfig.EnsurePlayerSlots(NetMode.Multi);
|
||||
// 这里 civList 要包含所有 civId (civId = civEnum - 1,目前 17 个 civ → 0..16)
|
||||
var civList = new List<uint>();
|
||||
for (int i = 0; i < 17; i++) civList.Add((uint)i);
|
||||
|
||||
foreach (var multiCiv in map.MapConfig.MultiCivs)
|
||||
foreach (var slot in map.MapConfig.MultiCivs)
|
||||
{
|
||||
var player = new PlayerData(multiCiv.CivId, multiCiv.CivId, idGenerator);
|
||||
var civId = slot.CivId;
|
||||
var forceId = slot.ForceId;
|
||||
if (slot.MemberId == 0 && slot.IsAI && !slot.IsCivFixed)
|
||||
{
|
||||
var idx = civList.Count > 0 ? UnityEngine.Random.Range(0, civList.Count) : 0;
|
||||
civId = civList.Count > 0 ? civList[idx] : 0u;
|
||||
forceId = civId;
|
||||
slot.CivId = civId;
|
||||
slot.ForceId = forceId;
|
||||
}
|
||||
civList.Remove(civId);
|
||||
var player = new PlayerData(civId, forceId, idGenerator);
|
||||
PlayerDataList.Add(player);
|
||||
_playerDataDict[player.Id] = player;
|
||||
civList.Remove(multiCiv.CivId);
|
||||
multiCiv.PlayerId = player.Id;
|
||||
}
|
||||
|
||||
for (int i = map.MapConfig.MultiCivs.Count; i < map.MapConfig.PlayerCount; i++)
|
||||
{
|
||||
int idx = UnityEngine.Random.Range(0, civList.Count);//map.Net.GetRandom().Next
|
||||
var civId = civList[idx];
|
||||
var player = new PlayerData(civId, civId, idGenerator);
|
||||
PlayerDataList.Add(player);
|
||||
_playerDataDict[player.Id] = player;
|
||||
civList.RemoveAt(idx);
|
||||
slot.PlayerId = player.Id;
|
||||
}
|
||||
}
|
||||
|
||||
SelfPlayerId = PlayerDataList[0].Id;
|
||||
if (PlayerDataList.Count > 0) SelfPlayerId = PlayerDataList[0].Id;
|
||||
foreach (var self in PlayerDataList)
|
||||
{
|
||||
foreach (var target in PlayerDataList)
|
||||
@ -167,6 +164,7 @@ namespace RuntimeData
|
||||
self.DiplomacyData.AddCountryDiplomacyInfo(target.Id);
|
||||
}
|
||||
}
|
||||
map.MapConfig.ApplyTeamDiplomacy(map);
|
||||
}
|
||||
|
||||
public PlayerMapData(PlayerMapData copyData)
|
||||
@ -520,6 +518,13 @@ namespace RuntimeData
|
||||
{
|
||||
if (player.Id == Id) continue;
|
||||
this.GetCountryDiplomacyInfo(player.Id, out var selfToPlayer);
|
||||
if (selfToPlayer.IsTeammate)
|
||||
{
|
||||
selfToPlayer.DiplomacyState = DiplomacyState.League;
|
||||
selfToPlayer.IsLeagueRequest = false;
|
||||
selfToPlayer.IsLeagueRupture = false;
|
||||
continue;
|
||||
}
|
||||
// 回合结束处理联盟破裂标记
|
||||
if (selfToPlayer.DiplomacyState == DiplomacyState.LeagueRupture) selfToPlayer.IsLeagueRupture = true;
|
||||
// 回合结束处理AI 冷静期计数
|
||||
@ -916,6 +921,18 @@ namespace RuntimeData
|
||||
if (player.Id == Id) continue;
|
||||
this.GetCountryDiplomacyInfo(player.Id, out var selfToPlayer);
|
||||
player.GetCountryDiplomacyInfo(Id, out var playerToSelf);
|
||||
if (selfToPlayer.IsTeammate || playerToSelf.IsTeammate)
|
||||
{
|
||||
selfToPlayer.IsTeammate = true;
|
||||
playerToSelf.IsTeammate = true;
|
||||
selfToPlayer.DiplomacyState = DiplomacyState.League;
|
||||
playerToSelf.DiplomacyState = DiplomacyState.League;
|
||||
selfToPlayer.IsLeagueRequest = false;
|
||||
playerToSelf.IsLeagueRequest = false;
|
||||
selfToPlayer.IsLeagueRupture = false;
|
||||
playerToSelf.IsLeagueRupture = false;
|
||||
continue;
|
||||
}
|
||||
// 如果没有外交关系,且没有见过面,则设置为无外交关系
|
||||
if (!MeetPlayers.Contains(player.Id)) selfToPlayer.DiplomacyState = DiplomacyState.NoDiplomacy;
|
||||
// 如果没有外交关系,且见过面,则设置为中立
|
||||
@ -1029,6 +1046,7 @@ namespace RuntimeData
|
||||
{
|
||||
if (otherPlayer.Id == Id) continue;
|
||||
if (!this.GetCountryDiplomacyInfo(otherPlayer.Id, out var selfToOther)) continue;
|
||||
if (selfToOther.IsTeammate) continue;
|
||||
if (selfToOther.DiplomacyState != DiplomacyState.League
|
||||
&& selfToOther.DiplomacyState != DiplomacyState.LeagueRupture) continue;
|
||||
|
||||
|
||||
@ -224,6 +224,7 @@ namespace TH1_Logic.Action
|
||||
//Step #6 处理break结盟
|
||||
if (_actionId.PlayerActionType == PlayerActionType.BreakAlly)
|
||||
{
|
||||
if (dipInfo.IsTeammate || dipInfo2.IsTeammate) return false;
|
||||
//Step #1 设置双方的外交状态为背盟
|
||||
dipInfo.DiplomacyState = DiplomacyState.LeagueRupture;
|
||||
dipInfo2.DiplomacyState = DiplomacyState.LeagueRupture;
|
||||
@ -352,10 +353,12 @@ namespace TH1_Logic.Action
|
||||
if (_actionId.PlayerActionType == PlayerActionType.BreakAlly)
|
||||
{
|
||||
actionParams.PlayerData.GetCountryDiplomacyInfo(actionParams.TargetPlayerData.Id, out var dipInfo);
|
||||
if (dipInfo.IsTeammate) return false;
|
||||
//如果没有结盟 return
|
||||
if (dipInfo.DiplomacyState != DiplomacyState.League) return false;
|
||||
//如果对方率先break,return
|
||||
actionParams.TargetPlayerData.GetCountryDiplomacyInfo(actionParams.PlayerData.Id,out var dipInfo2);
|
||||
if (dipInfo2.IsTeammate) return false;
|
||||
if (dipInfo2.DiplomacyState == DiplomacyState.LeagueRupture) return false;
|
||||
return true;
|
||||
}
|
||||
@ -446,10 +449,12 @@ namespace TH1_Logic.Action
|
||||
//Step #8 判断能否break结盟
|
||||
{
|
||||
actionParams.PlayerData.GetCountryDiplomacyInfo(actionParams.TargetPlayerData.Id, out var dipInfo);
|
||||
if (dipInfo.IsTeammate) return false;
|
||||
//如果没有结盟 return
|
||||
if (dipInfo.DiplomacyState != DiplomacyState.League) return false;
|
||||
//如果对方率先break,return
|
||||
actionParams.TargetPlayerData.GetCountryDiplomacyInfo(actionParams.PlayerData.Id,out var dipInfo2);
|
||||
if (dipInfo2.IsTeammate) return false;
|
||||
if (dipInfo2.DiplomacyState == DiplomacyState.LeagueRupture) return false;
|
||||
return true;
|
||||
}
|
||||
@ -488,6 +493,7 @@ namespace TH1_Logic.Action
|
||||
//Step #3 计算breakAlly按钮的情况
|
||||
if (_actionId.PlayerActionType == PlayerActionType.BreakAlly)
|
||||
{
|
||||
if (dipInfo.IsTeammate || dipInfo2.IsTeammate) return ActionShowState.Unavailable;
|
||||
return ActionShowState.Available;
|
||||
}
|
||||
|
||||
@ -597,4 +603,4 @@ namespace TH1_Logic.Action
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1702,6 +1702,18 @@ namespace Logic
|
||||
if (!originPlayer.GetCountryDiplomacyInfo(targetPlayer.Id, out var player1ToPlayer2)) return;
|
||||
|
||||
if (!targetPlayer.GetCountryDiplomacyInfo(originPlayer.Id, out var player2ToPlayer1)) return;
|
||||
if ((player1ToPlayer2.IsTeammate || player2ToPlayer1.IsTeammate) && state != DiplomacyState.League)
|
||||
{
|
||||
player1ToPlayer2.IsTeammate = true;
|
||||
player2ToPlayer1.IsTeammate = true;
|
||||
player1ToPlayer2.DiplomacyState = DiplomacyState.League;
|
||||
player2ToPlayer1.DiplomacyState = DiplomacyState.League;
|
||||
player1ToPlayer2.IsLeagueRequest = false;
|
||||
player2ToPlayer1.IsLeagueRequest = false;
|
||||
player1ToPlayer2.IsLeagueRupture = false;
|
||||
player2ToPlayer1.IsLeagueRupture = false;
|
||||
return;
|
||||
}
|
||||
player1ToPlayer2.DiplomacyState = state;
|
||||
player2ToPlayer1.DiplomacyState = state;
|
||||
if (state == DiplomacyState.War)
|
||||
|
||||
@ -122,10 +122,14 @@ public class UIOutsideMultiplayMemberRowMono : MonoBehaviour
|
||||
|
||||
var next = new MemberCiv
|
||||
{
|
||||
Index = t.Index,
|
||||
MemberId = selfMemberId,
|
||||
PlayerId = t.PlayerId,
|
||||
CivId = Table.Instance.TransCivEnumToCivId(civ),
|
||||
ForceId = Table.Instance.TransForceEnumToForceId(force),
|
||||
TeamId = t.TeamId,
|
||||
IsAI = false,
|
||||
IsCivFixed = true,
|
||||
IsReady = false
|
||||
};
|
||||
|
||||
|
||||
@ -307,6 +307,7 @@ namespace TH1_UI.View.Outside
|
||||
|
||||
|
||||
var memberList = _lobby.GetAllMemberInfo();
|
||||
Main.Instance.MapConfig.EnsurePlayerSlots(NetMode.Multi);
|
||||
var multiCivs = Main.Instance.MapConfig.MultiCivs;
|
||||
// 按 MultiCivs 顺序渲染(与游戏内 PlayerDataList 中真人玩家顺序一致),
|
||||
// 这样大厅显示的全局位置与进入游戏后的 nP 编号对齐。
|
||||
@ -729,6 +730,7 @@ namespace TH1_UI.View.Outside
|
||||
Main.Instance.MapConfig.AIDiff = diff;
|
||||
Main.Instance.MapConfig.GameMode = gameMode;
|
||||
Main.Instance.MapConfig.WaterType = waterType;
|
||||
Main.Instance.MapConfig.EnsurePlayerSlots(NetMode.Multi);
|
||||
if (resetGuestReady) Main.Instance.MapConfig.ResetGuestReadyStates();
|
||||
|
||||
// CREATIVE 下持久化 MapSize 选择(独立 key,不与单机冲突)
|
||||
@ -790,6 +792,7 @@ namespace TH1_UI.View.Outside
|
||||
Main.Instance.MapConfig.PlayerCount = playerCount;
|
||||
Main.Instance.MapConfig.Width = mapSize;
|
||||
Main.Instance.MapConfig.Height = mapSize;
|
||||
Main.Instance.MapConfig.EnsurePlayerSlots(NetMode.Multi);
|
||||
if (_lobby.IsLobbyOwner()) Main.Instance.MapConfig.ResetGuestReadyStates();
|
||||
// 触发房主→成员的整包广播(hash 比对幂等,不会刷屏)
|
||||
Main.Instance.MapConfig.CheckMapConfigChanged();
|
||||
|
||||
@ -294,6 +294,7 @@ namespace TH1_UI.View.Outside
|
||||
Main.Instance.MapConfig.selfForceId = Table.Instance.TransForceEnumToForceId(_selectEmpire.Force);
|
||||
Main.Instance.MapConfig.AIDiff = diff;
|
||||
Main.Instance.MapConfig.WaterType = waterType;
|
||||
Main.Instance.MapConfig.EnsurePlayerSlots(NetMode.Single);
|
||||
|
||||
// Save the selected empire for next time
|
||||
SaveLastSelectedEmpire(_selectEmpire);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user