Compare commits

...

5 Commits

Author SHA1 Message Date
319307fa84 序列化问题 2026-05-12 14:27:32 +08:00
ecd8255b72 Merge branch 'main' into wuwenbo/2v2 2026-05-11 17:25:14 +08:00
e77831bdc3 胜利条件添加队友 2026-05-11 17:21:58 +08:00
d51777bdbe gameconfig中玩家信息修改 2026-05-09 15:18:56 +08:00
ec04df6514 增加队友逻辑 2026-05-08 17:34:51 +08:00
12 changed files with 346 additions and 81 deletions

View File

@ -61,7 +61,7 @@ namespace RuntimeData
public MatchSettlementType MatchSettlement;
public List<PlayerSettlementInfo> PlayerSettlements;
// 单机用
// 兼容旧数据(已弃用)
public uint selfCivId;
public uint selfForceId;
@ -83,6 +83,12 @@ namespace RuntimeData
// 水域类型,默认为 Pangea
public Logic.MapWaterType WaterType = Logic.MapWaterType.Pangea;
// 单机用:真人玩家选择的 PlayerInfos 索引
public uint SelfPlayerInfoIndex;
// 存储着基于 Index 的玩家战前数据,包括真人和 AI
public List<PlayerInfo> PlayerInfos;
[MemoryPackConstructor]
public MapConfig()
{
@ -90,6 +96,7 @@ namespace RuntimeData
PlayerSettlements = new List<PlayerSettlementInfo>();
_memberCivs = new Dictionary<ulong, MemberCiv>();
MatchLimits = new List<MatchLimitType>();
PlayerInfos = new List<PlayerInfo>();
}
public MapConfig(uint width, uint height, uint playerCount,uint civId, uint forceId, AIDifficult aiDiff = AIDifficult.LUNATIC)
@ -98,10 +105,18 @@ namespace RuntimeData
Height = height;
PlayerCount = playerCount;
AIDiff = aiDiff;
SelfPlayerInfoIndex = 0;
selfCivId = civId;
selfForceId = forceId;
MultiCivs = new List<MemberCiv>();
_memberCivs = new Dictionary<ulong, MemberCiv>();
PlayerInfos = new List<PlayerInfo>();
EnsurePlayerInfosCount();
if (GetPlayerInfoByIndex(SelfPlayerInfoIndex, out var selfInfo))
{
selfInfo.CivId = civId;
selfInfo.ForceId = forceId;
}
}
// MemoryPack 反序列化之后的后处理
@ -112,26 +127,136 @@ namespace RuntimeData
// 旧存档兼容WaterType 字段不存在时默认为 Pangea
if (!System.Enum.IsDefined(typeof(Logic.MapWaterType), WaterType))
WaterType = Logic.MapWaterType.Pangea;
MultiCivs ??= new List<MemberCiv>();
PlayerInfos ??= new List<PlayerInfo>();
_memberCivs ??= new Dictionary<ulong, MemberCiv>();
RefreshMultiCivsDict();
EnsurePlayerInfosCount();
NormalizeMemberPlayerInfoIndexes();
}
public void EnsurePlayerInfosCount()
{
PlayerInfos ??= new List<PlayerInfo>();
if (PlayerCount == 0)
{
PlayerInfos.Clear();
SelfPlayerInfoIndex = 0;
return;
}
for (int i = 0; i < PlayerCount; i++)
{
if (i >= PlayerInfos.Count)
{
PlayerInfos.Add(new PlayerInfo { Index = (uint)i, CivId = (uint)i, ForceId = (uint)i });
}
else
{
PlayerInfos[i] ??= new PlayerInfo();
PlayerInfos[i].Index = (uint)i;
}
}
if (PlayerInfos.Count > PlayerCount)
{
PlayerInfos.RemoveRange((int)PlayerCount, PlayerInfos.Count - (int)PlayerCount);
}
if (SelfPlayerInfoIndex >= PlayerCount) SelfPlayerInfoIndex = 0;
// 旧数据迁移:若旧字段有效,补到 SelfPlayerInfoIndex 对应的 PlayerInfo
if (GetPlayerInfoByIndex(SelfPlayerInfoIndex, out var selfInfo))
{
if (selfCivId != 0 || selfForceId != 0)
{
selfInfo.CivId = selfCivId;
selfInfo.ForceId = selfForceId;
}
}
// 旧联机数据迁移MemberCiv 可能还带着 Civ/Force迁移到其索引对应 PlayerInfo
if (MultiCivs == null) return;
foreach (var member in MultiCivs)
{
if (member == null) continue;
if (member.PlayerInfoIndex >= PlayerCount) continue;
if (member.CivId == 0 && member.ForceId == 0) continue;
if (!GetPlayerInfoByIndex(member.PlayerInfoIndex, out var info)) continue;
info.CivId = member.CivId;
info.ForceId = member.ForceId;
}
}
public bool GetPlayerInfoByIndex(uint index, out PlayerInfo info)
{
info = null;
EnsurePlayerInfosCount();
if (index >= PlayerInfos.Count) return false;
info = PlayerInfos[(int)index];
info ??= new PlayerInfo { Index = index, CivId = index, ForceId = index };
PlayerInfos[(int)index] = info;
return true;
}
private void NormalizeMemberPlayerInfoIndexes()
{
if (MultiCivs == null || MultiCivs.Count == 0) return;
EnsurePlayerInfosCount();
if (PlayerCount == 0) return;
var used = new HashSet<uint>();
for (int i = 0; i < MultiCivs.Count; i++)
{
var member = MultiCivs[i];
if (member == null) continue;
if (member.PlayerInfoIndex < PlayerCount && !used.Contains(member.PlayerInfoIndex))
{
used.Add(member.PlayerInfoIndex);
continue;
}
member.PlayerInfoIndex = uint.MaxValue;
}
for (int i = 0; i < MultiCivs.Count; i++)
{
var member = MultiCivs[i];
if (member == null || member.PlayerInfoIndex != uint.MaxValue) continue;
uint fallback = 0;
while (fallback < PlayerCount && used.Contains(fallback)) fallback++;
if (fallback >= PlayerCount)
{
member.PlayerInfoIndex = 0;
continue;
}
member.PlayerInfoIndex = fallback;
used.Add(fallback);
}
}
// 根据房间成员信息更新 mapconfig 信息
public void UpdateLobbyMember(Dictionary<ulong, MemberInfo> memberInfos)
{
// 先剔除已离开 lobby 的成员,避免 MultiCivs 留下幽灵占位:
// 旧版只 Add 不 Remove会导致大厅 nP 跳号(1P/4P/5P/6P)
// 以及开战时给离线幽灵创 PlayerData、占用 PlayerCount 名额、AI 补位变少。
MultiCivs.RemoveAll(mc => !memberInfos.ContainsKey(mc.MemberId));
EnsurePlayerInfosCount();
RefreshMultiCivsDict();
for (int i = MultiCivs.Count - 1; i >= 0; i--)
{
if (memberInfos.ContainsKey(MultiCivs[i].MemberId)) continue;
_memberCivs.Remove(MultiCivs[i].MemberId);
MultiCivs.RemoveAt(i);
}
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.PlayerInfoIndex = uint.MaxValue;
MultiCivs.Add(civ);
}
RefreshMultiCivsDict();
NormalizeMemberPlayerInfoIndexes();
}
// 内部刷新
@ -161,14 +286,31 @@ namespace RuntimeData
return;
}
EnsurePlayerInfosCount();
uint newIndex = civ.PlayerInfoIndex;
if (newIndex >= PlayerCount)
{
// 兼容旧消息:按 Civ/Force 找索引
for (uint i = 0; i < PlayerCount; i++)
{
if (!GetPlayerInfoByIndex(i, out var info)) continue;
if (info.CivId != civ.CivId || info.ForceId != civ.ForceId) continue;
newIndex = i;
break;
}
if (newIndex >= PlayerCount) newIndex = 0;
}
foreach (var memberCiv in MultiCivs)
{
if (memberCiv.MemberId != civ.MemberId) continue;
memberCiv.CivId = civ.CivId;
memberCiv.ForceId = civ.ForceId;
memberCiv.PlayerInfoIndex = newIndex;
NormalizeMemberPlayerInfoIndexes();
return;
}
civ.PlayerInfoIndex = newIndex;
MultiCivs.Add(civ);
NormalizeMemberPlayerInfoIndexes();
}
// 主从端一致的本地数据检测
@ -190,18 +332,17 @@ namespace RuntimeData
// 从 MapData 中重绑定 MemberCiv 的 Player 信息
public bool ReBindPlayerInfoFromMapData(MapData mapData)
{
EnsurePlayerInfosCount();
RefreshMultiCivsDict();
NormalizeMemberPlayerInfoIndexes();
if (mapData.Net.Mode == NetMode.Single)
{
foreach (var player in mapData.PlayerMap.PlayerDataList)
{
if (player.PlayerCivId != selfCivId || player.PlayerForceId != selfForceId) continue;
mapData.PlayerMap.SelfPlayerId = player.Id;
}
if (mapData.PlayerMap.SelfPlayerId == 0)
if (SelfPlayerInfoIndex < mapData.PlayerMap.PlayerDataList.Count)
mapData.PlayerMap.SelfPlayerId = mapData.PlayerMap.PlayerDataList[(int)SelfPlayerInfoIndex].Id;
else
{
LogSystem.LogError($"单机模式指定地图中找不到指定的阵营信息, 启动游戏失败, " +
$"地图 ID : {Id} 文明 ID : {selfCivId} 势力 ID : {selfForceId}");
$"地图 ID : {Id} 玩家索引 : {SelfPlayerInfoIndex}");
return false;
}
}
@ -210,16 +351,13 @@ namespace RuntimeData
{
foreach (var member in MultiCivs)
{
foreach (var player in mapData.PlayerMap.PlayerDataList)
{
if (player.PlayerCivId != member.CivId || player.PlayerForceId != member.ForceId) continue;
member.PlayerId = player.PlayerCivId;
}
if (member.PlayerInfoIndex >= mapData.PlayerMap.PlayerDataList.Count) member.PlayerId = 0;
else member.PlayerId = mapData.PlayerMap.PlayerDataList[(int)member.PlayerInfoIndex].Id;
if (member.PlayerId == 0)
{
LogSystem.LogError($"联机模式指定地图中找不到指定的阵营信息, 启动游戏失败, " +
$"地图 ID : {Id} 文明 ID : {member.CivId} 势力 ID : {member.ForceId}");
$"地图 ID : {Id} 玩家索引 : {member.PlayerInfoIndex}");
return false;
}
}
@ -273,6 +411,17 @@ namespace RuntimeData
{
public ulong MemberId;
public uint PlayerId;
// 兼容旧数据(已弃用,真实值来自 PlayerInfos[PlayerInfoIndex]
public uint CivId;
public uint ForceId;
public uint PlayerInfoIndex;
}
[MemoryPackable]
public partial class PlayerInfo
{
public uint Index;
public uint CivId;
public uint ForceId;
}
@ -1778,7 +1927,7 @@ namespace RuntimeData
{
foreach (var player in PlayerMap.PlayerDataList)
{
if (MatchSettlement.IsWin(player.Id)) return player;
if (MatchSettlement.IsWin(this, player.Id)) return player;
}
return null;
@ -1787,7 +1936,7 @@ namespace RuntimeData
// 游戏是否结束
public bool CheckIfGameEnd(out bool isWin)
{
isWin = MatchSettlement.IsWin(PlayerMap.SelfPlayerId);
isWin = MatchSettlement.IsWin(this, PlayerMap.SelfPlayerId);
return MatchSettlement.IsFinished;
}

View File

@ -152,6 +152,7 @@ namespace RuntimeData
public int RandomSeed;
private System.Random _random;
private static readonly ArrayBufferWriter<byte> _bufferWriter = new ArrayBufferWriter<byte>(64 * 1024);
private List<ulong> _tmpMemberIdListBuffer;
// 玩家开始时间记录
[MemoryPackIgnore]
@ -206,16 +207,35 @@ namespace RuntimeData
if (Mode != NetMode.Multi) return;
if (LobbyManager.Instance.Lobby.IsLobbyOwner())
{
// 创建 Player 的时候会分配一次 PlayerId这里直接使用
mapData.MapConfig.EnsurePlayerInfosCount();
var memberIds = LobbyManager.Instance.Lobby.GetAllMemberIds();
// 移除不在当前房间的映射
_tmpMemberIdListBuffer ??= new List<ulong>();
_tmpMemberIdListBuffer.Clear();
foreach (var kv in Players)
{
if (memberIds.Contains(kv.Key)) continue;
_tmpMemberIdListBuffer.Add(kv.Key);
}
foreach (var memberId in _tmpMemberIdListBuffer) Players.Remove(memberId);
// 创建 Player 的时候会分配一次 PlayerId这里直接使用 index -> PlayerId
foreach (var memberCiv in mapData.MapConfig.MultiCivs)
{
if (memberCiv.PlayerInfoIndex >= mapData.PlayerMap.PlayerDataList.Count)
{
memberCiv.PlayerId = 0;
continue;
}
memberCiv.PlayerId = mapData.PlayerMap.PlayerDataList[(int)memberCiv.PlayerInfoIndex].Id;
if (memberCiv.PlayerId == 0) continue;
if (Players.ContainsKey(memberCiv.MemberId)) continue;
if (!memberIds.Contains(memberCiv.MemberId)) continue;
Players[memberCiv.MemberId] = memberCiv.PlayerId;
}
// 添加其他人
foreach (var memberId in LobbyManager.Instance.Lobby.GetAllMemberIds())
foreach (var memberId in memberIds)
{
if (Players.ContainsKey(memberId)) continue;
foreach (var player in mapData.PlayerMap.PlayerDataList)

View File

@ -118,47 +118,53 @@ namespace RuntimeData
if (netMode == NetMode.Single)
{
map.MapConfig.EnsurePlayerInfosCount();
for (int i = 0; i < map.MapConfig.PlayerCount; 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);
uint civId = (uint)i;
uint forceId = (uint)i;
if (map.MapConfig.GetPlayerInfoByIndex((uint)i, out var playerInfo))
{
civId = playerInfo.CivId;
forceId = playerInfo.ForceId;
}
PlayerData player = new PlayerData(civId, forceId, idGenerator);
PlayerDataList.Add(player);
_playerDataDict[player.Id] = player;
}
}
if (netMode == 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);
map.MapConfig.EnsurePlayerInfosCount();
for (int i = 0; i < map.MapConfig.PlayerCount; i++)
{
uint civId = (uint)i;
uint forceId = (uint)i;
if (map.MapConfig.GetPlayerInfoByIndex((uint)i, out var playerInfo))
{
civId = playerInfo.CivId;
forceId = playerInfo.ForceId;
}
var player = new PlayerData(civId, forceId, idGenerator);
PlayerDataList.Add(player);
_playerDataDict[player.Id] = player;
}
foreach (var multiCiv in map.MapConfig.MultiCivs)
{
var player = new PlayerData(multiCiv.CivId, multiCiv.CivId, 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);
if (multiCiv.PlayerInfoIndex >= PlayerDataList.Count)
{
multiCiv.PlayerId = 0;
continue;
}
multiCiv.PlayerId = PlayerDataList[(int)multiCiv.PlayerInfoIndex].Id;
}
}
SelfPlayerId = PlayerDataList[0].Id;
if (netMode == NetMode.Single && map.MapConfig.SelfPlayerInfoIndex < PlayerDataList.Count)
SelfPlayerId = PlayerDataList[(int)map.MapConfig.SelfPlayerInfoIndex].Id;
else
SelfPlayerId = PlayerDataList[0].Id;
foreach (var self in PlayerDataList)
{
foreach (var target in PlayerDataList)

View File

@ -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,11 @@ namespace TH1_Logic.Action
if (_actionId.PlayerActionType == PlayerActionType.BreakAlly)
{
actionParams.PlayerData.GetCountryDiplomacyInfo(actionParams.TargetPlayerData.Id, out var dipInfo);
actionParams.TargetPlayerData.GetCountryDiplomacyInfo(actionParams.PlayerData.Id,out var dipInfo2);
if (dipInfo.IsTeammate || dipInfo2.IsTeammate) return false;
//如果没有结盟 return
if (dipInfo.DiplomacyState != DiplomacyState.League) return false;
//如果对方率先breakreturn
actionParams.TargetPlayerData.GetCountryDiplomacyInfo(actionParams.PlayerData.Id,out var dipInfo2);
if (dipInfo2.DiplomacyState == DiplomacyState.LeagueRupture) return false;
return true;
}
@ -446,10 +448,11 @@ namespace TH1_Logic.Action
//Step #8 判断能否break结盟
{
actionParams.PlayerData.GetCountryDiplomacyInfo(actionParams.TargetPlayerData.Id, out var dipInfo);
actionParams.TargetPlayerData.GetCountryDiplomacyInfo(actionParams.PlayerData.Id,out var dipInfo2);
if (dipInfo.IsTeammate || dipInfo2.IsTeammate) return false;
//如果没有结盟 return
if (dipInfo.DiplomacyState != DiplomacyState.League) return false;
//如果对方率先breakreturn
actionParams.TargetPlayerData.GetCountryDiplomacyInfo(actionParams.PlayerData.Id,out var dipInfo2);
if (dipInfo2.DiplomacyState == DiplomacyState.LeagueRupture) return false;
return true;
}
@ -488,6 +491,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 +601,4 @@ namespace TH1_Logic.Action
return true;
}
}
}
}

View File

@ -107,6 +107,7 @@ namespace Logic.Editor
private void OnGUIMapConfig(MapConfig mapConfig)
{
EditorGUILayout.BeginVertical();
mapConfig.EnsurePlayerInfosCount();
// 基础配置
if (InspectorUtils.InspectorButtonWithTextWidth("删除关卡"))
@ -135,7 +136,9 @@ namespace Logic.Editor
EditorGUILayout.BeginHorizontal();
InspectorUtils.InspectorTextWidthRich("玩家数量:");
var oldPlayerCount = mapConfig.PlayerCount;
mapConfig.PlayerCount = (uint)EditorGUILayout.IntField((int)mapConfig.PlayerCount, GUILayout.Width(200));
if (oldPlayerCount != mapConfig.PlayerCount) mapConfig.EnsurePlayerInfosCount();
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
@ -159,13 +162,19 @@ namespace Logic.Editor
// 单机配置
InspectorUtils.InspectorTextWidthRich("<b>单机配置</b>");
EditorGUILayout.BeginHorizontal();
InspectorUtils.InspectorTextWidthRich("文明ID:");
mapConfig.selfCivId = (uint)EditorGUILayout.IntField((int)mapConfig.selfCivId, GUILayout.Width(200));
InspectorUtils.InspectorTextWidthRich("单机玩家索引:");
mapConfig.SelfPlayerInfoIndex = (uint)EditorGUILayout.IntField((int)mapConfig.SelfPlayerInfoIndex, GUILayout.Width(200));
if (mapConfig.PlayerCount > 0 && mapConfig.SelfPlayerInfoIndex >= mapConfig.PlayerCount)
mapConfig.SelfPlayerInfoIndex = mapConfig.PlayerCount - 1;
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
InspectorUtils.InspectorTextWidthRich("势力ID:");
mapConfig.selfForceId = (uint)EditorGUILayout.IntField((int)mapConfig.selfForceId, GUILayout.Width(200));
InspectorUtils.InspectorTextWidthRich("单机玩家阵营(Civ/Force):");
if (mapConfig.GetPlayerInfoByIndex(mapConfig.SelfPlayerInfoIndex, out var selfInfo))
{
selfInfo.CivId = (uint)EditorGUILayout.IntField((int)selfInfo.CivId, GUILayout.Width(95));
selfInfo.ForceId = (uint)EditorGUILayout.IntField((int)selfInfo.ForceId, GUILayout.Width(95));
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();

View File

@ -146,11 +146,13 @@ namespace Logic.Editor
var civ = Main.Instance.MapConfig.GetMemberCiv(selfMemberId);
if (civ != null)
{
Main.Instance.MapConfig.GetPlayerInfoByIndex(civ.PlayerInfoIndex, out var info);
EditorGUILayout.BeginHorizontal();
if (InspectorUtils.InspectorButtonWithTextWidth("改1")) civ.CivId = 1;
if (InspectorUtils.InspectorButtonWithTextWidth("改2")) civ.CivId = 2;
if (InspectorUtils.InspectorButtonWithTextWidth("改3")) civ.CivId = 3;
if (InspectorUtils.InspectorButtonWithTextWidth("改4")) civ.CivId = 4;
InspectorUtils.InspectorTextWidthRich($"Idx:{civ.PlayerInfoIndex} Civ:{info?.CivId ?? 0} Force:{info?.ForceId ?? 0}");
if (InspectorUtils.InspectorButtonWithTextWidth("改Idx0")) { civ.PlayerInfoIndex = 0; Main.Instance.MapConfig.UpdateMemberCiv(civ); }
if (InspectorUtils.InspectorButtonWithTextWidth("改Idx1")) { civ.PlayerInfoIndex = 1; Main.Instance.MapConfig.UpdateMemberCiv(civ); }
if (InspectorUtils.InspectorButtonWithTextWidth("改Idx2")) { civ.PlayerInfoIndex = 2; Main.Instance.MapConfig.UpdateMemberCiv(civ); }
if (InspectorUtils.InspectorButtonWithTextWidth("改Idx3")) { civ.PlayerInfoIndex = 3; Main.Instance.MapConfig.UpdateMemberCiv(civ); }
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.EndVertical();

View File

@ -11,6 +11,7 @@ using Logic.CrashSight;
using MemoryPack;
using RuntimeData;
using TH1_Logic.Collect;
using TH1_Logic.Core;
namespace TH1_Logic.MatchConfig
@ -56,11 +57,31 @@ namespace TH1_Logic.MatchConfig
}
public bool IsWin(uint id)
{
return IsWin(Main.MapData, id);
}
public bool IsWin(MapData map, uint id)
{
if (!IsFinished) return false;
var settlementGroup = PlayerSettlements.GetValueOrDefault(id);
if (settlementGroup == null) return false;
return settlementGroup.IsWin;
if (settlementGroup != null && settlementGroup.IsWin) return true;
if (map == null) return false;
if (!map.PlayerMap.GetPlayerDataByPlayerID(id, out var selfPlayer)) return false;
foreach (var kv in PlayerSettlements)
{
if (kv.Key == id) continue;
if (kv.Value == null || !kv.Value.IsWin) continue;
if (!map.PlayerMap.GetPlayerDataByPlayerID(kv.Key, out var teammatePlayer)) continue;
if (!selfPlayer.GetCountryDiplomacyInfo(teammatePlayer.Id, out var selfToTeammateDip)) continue;
if (!teammatePlayer.GetCountryDiplomacyInfo(selfPlayer.Id, out var teammateToSelfDip)) continue;
if (!selfToTeammateDip.IsTeammate && !teammateToSelfDip.IsTeammate) continue;
return true;
}
return false;
}
public MatchSettlementInfo(MatchSettlementInfo copyData)
@ -416,7 +437,6 @@ namespace TH1_Logic.MatchConfig
}
}
/// <summary>
/// 偶现 bug 兜底:玩家明明已经满足"应当结束"的客观条件,但 task 链路因为某种运行时累积态没把
/// PlayerSettlementGroup 翻成 IsSettlement导致游戏一直能下一回合。已知"退出再读档"可恢复。

View File

@ -29,6 +29,8 @@ namespace Logic
//player[pid]解雇unit[uid]
public int UpdateSight_LogicView(MapData mapData, PlayerData playerData, List<uint> gidList,bool viewNextFrame,float duration);
//unit[uid]在grid[tpos]的位置,为player[pid]更新了视野情况
bool SetTeammateAndLeague(MapData mapData, PlayerData playerA, PlayerData playerB, bool isTeammate);
//设置双方队友关系;当 isTeammate=true 时同步设为结盟,并通过首都周围视野触发双向 meet
//-------tech相关操作-------
//返回player[pid]的tid科技是否被锁了
@ -42,4 +44,4 @@ namespace Logic
//player[pid]进入下一回合
//void TempReturnThisAction(string name, PlayerData P, CityData C, UnitData U, GridData T,MapData M);
}
}
}

View File

@ -1696,12 +1696,48 @@ namespace Logic
}
}
// 设置双方队友关系;当 isTeammate=true 时同步设为结盟,并通过首都周围视野触发双向 meet
public bool SetTeammateAndLeague(MapData map, PlayerData playerA, PlayerData playerB, bool isTeammate)
{
if (map == null || playerA == null || playerB == null) return false;
if (playerA.Id == playerB.Id) return false;
if (!playerA.GetCountryDiplomacyInfo(playerB.Id, out var playerAToB)) return false;
if (!playerB.GetCountryDiplomacyInfo(playerA.Id, out var playerBToA)) return false;
playerAToB.IsTeammate = isTeammate;
playerBToA.IsTeammate = isTeammate;
if (!isTeammate) return true;
playerAToB.DiplomacyState = DiplomacyState.League;
playerBToA.DiplomacyState = DiplomacyState.League;
playerAToB.IsLeagueRequest = false;
playerBToA.IsLeagueRequest = false;
playerAToB.IsLeagueRupture = false;
playerBToA.IsLeagueRupture = false;
if (map.GetCapitalCityDataByPlayerId(playerB.Id, out var playerBCapital)
&& map.GetGridDataByCityId(playerBCapital.Id, out var playerBCapitalGrid))
{
UpdateSight_LogicView(map, playerA, map.GridMap.GetAroundGridIdList(1, playerBCapitalGrid, true));
}
if (map.GetCapitalCityDataByPlayerId(playerA.Id, out var playerACapital)
&& map.GetGridDataByCityId(playerACapital.Id, out var playerACapitalGrid))
{
UpdateSight_LogicView(map, playerB, map.GridMap.GetAroundGridIdList(1, playerACapitalGrid, true));
}
return true;
}
// 设置外交关系
public void SetDiplomacyLeague(MapData map, PlayerData originPlayer, PlayerData targetPlayer, DiplomacyState state)
{
if (!originPlayer.GetCountryDiplomacyInfo(targetPlayer.Id, out var player1ToPlayer2)) return;
if (!targetPlayer.GetCountryDiplomacyInfo(originPlayer.Id, out var player2ToPlayer1)) return;
if (state == DiplomacyState.War && (player1ToPlayer2.IsTeammate || player2ToPlayer1.IsTeammate)) return;
player1ToPlayer2.DiplomacyState = state;
player2ToPlayer1.DiplomacyState = state;
if (state == DiplomacyState.War)

View File

@ -161,7 +161,12 @@ namespace TH1_Logic.Steam
}
var data = new ChangeCivMessage();
data.Civ = memberCiv;
data.Civ = new MemberCiv
{
MemberId = memberCiv.MemberId,
PlayerInfoIndex = memberCiv.PlayerInfoIndex,
PlayerId = memberCiv.PlayerId
};
SendMessage(data);
}
@ -263,4 +268,4 @@ namespace TH1_Logic.Steam
BroadcastMessage(data);
}
}
}
}

View File

@ -121,11 +121,13 @@ namespace TH1_Logic.Steam
var civ = Main.Instance.MapConfig.GetMemberCiv(selfMemberId);
if (civ != null)
{
Main.Instance.MapConfig.GetPlayerInfoByIndex(civ.PlayerInfoIndex, out var info);
GUILayout.BeginHorizontal();
if (GUILayout.Button("改1")) civ.CivId = 1;
if (GUILayout.Button("改2")) civ.CivId = 2;
if (GUILayout.Button("改3")) civ.CivId = 3;
if (GUILayout.Button("改4")) civ.CivId = 4;
GUILayout.Label($"Idx:{civ.PlayerInfoIndex} Civ:{info?.CivId ?? 0} Force:{info?.ForceId ?? 0}");
if (GUILayout.Button("改Idx0")) { civ.PlayerInfoIndex = 0; Main.Instance.MapConfig.UpdateMemberCiv(civ); }
if (GUILayout.Button("改Idx1")) { civ.PlayerInfoIndex = 1; Main.Instance.MapConfig.UpdateMemberCiv(civ); }
if (GUILayout.Button("改Idx2")) { civ.PlayerInfoIndex = 2; Main.Instance.MapConfig.UpdateMemberCiv(civ); }
if (GUILayout.Button("改Idx3")) { civ.PlayerInfoIndex = 3; Main.Instance.MapConfig.UpdateMemberCiv(civ); }
GUILayout.EndHorizontal();
}
}
@ -138,4 +140,4 @@ namespace TH1_Logic.Steam
#endif
}
}
}

View File

@ -268,6 +268,10 @@ namespace Logic
&& mapData.GetPlayerDataByUnitId(unitData.Id, out var player1)
&& player1.Id != player2.Id)
{
if (player1.GetCountryDiplomacyInfo(player2.Id, out var player1ToPlayer2)
&& player2.GetCountryDiplomacyInfo(player1.Id, out var player2ToPlayer1)
&& (player1ToPlayer2.IsTeammate || player2ToPlayer1.IsTeammate))
return true;
player2.AddAttacker(player1.Id);
Main.PlayerLogic.SetDiplomacyLeague(mapData, player1, player2, DiplomacyState.War);
}
@ -515,11 +519,17 @@ namespace Logic
if (type is DamageType.ActiveAttack or DamageType.FollowAttack or DamageType.Splash or DamageType.True)
{
Main.PlayerLogic.SetDiplomacyLeague(mapData,player1, player2, DiplomacyState.War);
player1.CurAttackPlayers.Add(player2.Id);
player2.CurAttackPlayers.Add(player1.Id);
player2.AddAttacker(player1.Id);
player1.TurnNoAttack = 0;
bool isTeammate = player1.GetCountryDiplomacyInfo(player2.Id, out var player1ToPlayer2)
&& player2.GetCountryDiplomacyInfo(player1.Id, out var player2ToPlayer1)
&& (player1ToPlayer2.IsTeammate || player2ToPlayer1.IsTeammate);
if (!isTeammate)
{
Main.PlayerLogic.SetDiplomacyLeague(mapData,player1, player2, DiplomacyState.War);
player1.CurAttackPlayers.Add(player2.Id);
player2.CurAttackPlayers.Add(player1.Id);
player2.AddAttacker(player1.Id);
player1.TurnNoAttack = 0;
}
}
//Step #4 Moment Process