增加大量保护
This commit is contained in:
parent
c0517acf7e
commit
096f6e4010
@ -347,6 +347,18 @@ namespace RuntimeData
|
||||
return map.GetGridDataByUnitId(Id, out grid);
|
||||
}
|
||||
|
||||
public bool IsValidOnMap(MapData map, GridData expectedGrid = null)
|
||||
{
|
||||
if (map?.UnitMap == null) return false;
|
||||
if (!map.UnitMap.GetUnitDataByUnitId(Id, out var currentUnit)) return false;
|
||||
if (!ReferenceEquals(currentUnit, this)) return false;
|
||||
if (!map.GetPlayerDataByUnitId(Id, out _)) return false;
|
||||
if (expectedGrid == null) return true;
|
||||
return map.GetGridDataByUnitId(Id, out var currentGrid)
|
||||
&& currentGrid != null
|
||||
&& currentGrid.Id == expectedGrid.Id;
|
||||
}
|
||||
|
||||
public UnitRenderer Renderer(MapData map)
|
||||
{
|
||||
if (!map.IsCurrentShowMap()) return null;
|
||||
@ -1472,13 +1484,17 @@ namespace RuntimeData
|
||||
// 移动后
|
||||
public void OnMove(MapData map, GridData target, MoveType moveType, List<Vector2Int> path = null)
|
||||
{
|
||||
if (map == null || target == null || !IsValidOnMap(map, target)) return;
|
||||
|
||||
var isFrozen = IsFrozen();
|
||||
var copy = new List<SkillBase>(Skills);
|
||||
foreach (var skill in copy)
|
||||
{
|
||||
if (!IsValidOnMap(map, target)) return;
|
||||
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
|
||||
skill.OnMove(this, target, map,moveType, path);
|
||||
}
|
||||
if (!IsValidOnMap(map, target)) return;
|
||||
//赋予格子特殊效果,scarletEmpire的单位走到格子上时会得到被赋予一个技能realTimeVampire
|
||||
// 注意:多人允许相同 Empire 后,多名 PlayerCivId==0 玩家会同时享有此特权,符合预期保留逻辑。
|
||||
if(target.HasSpType(GridSpType.RemiliaGrid) && target.RealUnit(map,out var unit) && unit.Player(map,out var player) && player.PlayerCivId == 0)
|
||||
@ -1528,10 +1544,14 @@ namespace RuntimeData
|
||||
public void BeforeActiveAttackOther(MapData mapData, UnitData origin, UnitData target,out int addDmg)
|
||||
{
|
||||
addDmg = 0;
|
||||
if (mapData == null || origin == null || target == null) return;
|
||||
if (!origin.IsValidOnMap(mapData) || !target.IsValidOnMap(mapData)) return;
|
||||
|
||||
var isFrozen = IsFrozen();
|
||||
var copy = new List<SkillBase>(Skills);
|
||||
foreach (var skill in copy)
|
||||
{
|
||||
if (!origin.IsValidOnMap(mapData) || !target.IsValidOnMap(mapData)) return;
|
||||
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
|
||||
skill.BeforeActiveAttackOther(mapData, origin, target, out var tmpAddDmg);
|
||||
addDmg += tmpAddDmg;
|
||||
|
||||
@ -66,7 +66,7 @@ namespace TH1_Logic.Oss
|
||||
// 检查缓存的凭证是否有效(提前60秒刷新)
|
||||
if (_cachedCredentials == null || DateTime.UtcNow >= _credentialsExpireTime.AddSeconds(-60))
|
||||
{
|
||||
var authTicket = GetAuthTicket();
|
||||
if (!TryGetAuthTicket(out var authTicket)) return false;
|
||||
_cachedCredentials = await _stsService.RequestStsTokenAsync(steamId, authTicket, "ossdata");
|
||||
_credentialsExpireTime = DateTime.UtcNow.AddSeconds(_cachedCredentials.expiresIn);
|
||||
LogSystem.LogInfo($"STS token obtained, expires at {_credentialsExpireTime}");
|
||||
@ -104,7 +104,7 @@ namespace TH1_Logic.Oss
|
||||
// 检查缓存的凭证是否有效(提前60秒刷新)
|
||||
if (_cachedCollectCredentials == null || DateTime.UtcNow >= _collectCredentialsExpireTime.AddSeconds(-60))
|
||||
{
|
||||
var authTicket = GetAuthTicket();
|
||||
if (!TryGetAuthTicket(out var authTicket)) return false;
|
||||
_cachedCollectCredentials = await _stsService.RequestStsTokenAsync(steamId, authTicket, "collectdata");
|
||||
_collectCredentialsExpireTime = DateTime.UtcNow.AddSeconds(_cachedCollectCredentials.expiresIn);
|
||||
LogSystem.LogInfo($"Collect STS token obtained, expires at {_collectCredentialsExpireTime}");
|
||||
@ -144,7 +144,7 @@ namespace TH1_Logic.Oss
|
||||
return (false, null);
|
||||
}
|
||||
|
||||
var authTicket = GetAuthTicket();
|
||||
if (!TryGetAuthTicket(out var authTicket)) return (false, null);
|
||||
var credentials = await _stsService.RequestStsTokenAsync(steamId, authTicket, "bugreport", version);
|
||||
var result = await _uploadService.UploadFileAsync(credentials, packageData, "application/zip",
|
||||
MaxBugReportUploadBytes);
|
||||
@ -181,7 +181,7 @@ namespace TH1_Logic.Oss
|
||||
return (false, null);
|
||||
}
|
||||
|
||||
var authTicket = GetAuthTicket();
|
||||
if (!TryGetAuthTicket(out var authTicket)) return (false, null);
|
||||
var credentials = await _stsService.RequestStsTokenAsync(steamId, authTicket, "multilingualreport",
|
||||
version);
|
||||
var result = await _uploadService.UploadFileAsync(credentials, packageData, "application/zip",
|
||||
@ -220,7 +220,7 @@ namespace TH1_Logic.Oss
|
||||
_isSteamAuthWarmupRunning = true;
|
||||
try
|
||||
{
|
||||
var authTicket = GetAuthTicket();
|
||||
if (!TryGetAuthTicket(out var authTicket)) return false;
|
||||
var response = await _stsService.WarmupSteamAuthAsync(steamId, authTicket);
|
||||
var refreshSeconds = response != null && response.expiresIn > 90
|
||||
? Math.Min(SteamAuthWarmupRefreshSeconds, response.expiresIn - 60)
|
||||
@ -260,15 +260,28 @@ namespace TH1_Logic.Oss
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetAuthTicket()
|
||||
private static bool TryGetAuthTicket(out string authTicket)
|
||||
{
|
||||
var ticket = new byte[1024];
|
||||
var identity = new SteamNetworkingIdentity();
|
||||
SteamUser.GetAuthSessionTicket(ticket, 1024, out var ticketSize, ref identity);
|
||||
if (ticketSize == 0)
|
||||
throw new Exception("Steam auth ticket is empty");
|
||||
authTicket = null;
|
||||
try
|
||||
{
|
||||
var ticket = new byte[1024];
|
||||
var identity = new SteamNetworkingIdentity();
|
||||
SteamUser.GetAuthSessionTicket(ticket, 1024, out var ticketSize, ref identity);
|
||||
if (ticketSize == 0)
|
||||
{
|
||||
LogSystem.LogWarning("Steam auth ticket is empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
return BitConverter.ToString(ticket, 0, (int)ticketSize).Replace("-", "").ToLower();
|
||||
authTicket = BitConverter.ToString(ticket, 0, (int)ticketSize).Replace("-", "").ToLower();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogSystem.LogWarning($"Steam auth ticket unavailable: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,11 +30,13 @@ namespace Logic.Skill
|
||||
public override void BeforeActiveAttackOther(MapData mapData, UnitData origin, UnitData target, out int addDmg)
|
||||
{
|
||||
addDmg = 0;
|
||||
if (origin == null || target == null) return;
|
||||
if (mapData == null || origin == null || target == null) return;
|
||||
if (!origin.IsValidOnMap(mapData) || !target.IsValidOnMap(mapData)) return;
|
||||
if (!mapData.GetGridDataByUnitId(target.Id, out var targetGrid)) return;
|
||||
var count = 0;
|
||||
foreach (var unit in mapData.UnitMap.UnitList)
|
||||
{
|
||||
if (unit == null || !unit.IsValidOnMap(mapData)) continue;
|
||||
if (unit == origin || unit == target) continue;
|
||||
// 仅本体的我方/在盟盟友可参与协同;刚背盟的不算,敌方幻象更不算
|
||||
if (!mapData.IsLeagueUnitByUnit(unit.Id, origin.Id)) continue;
|
||||
@ -49,6 +51,7 @@ namespace Logic.Skill
|
||||
MapRenderer.Instance.ProjectileManager.CreateProjectile(unitPosition, targetPosition, ProjectileType.ReisenAttack);
|
||||
count++;
|
||||
}
|
||||
if (!origin.IsValidOnMap(mapData) || !target.IsValidOnMap(mapData, targetGrid)) return;
|
||||
target.AddSkill_Legacy(SkillType.KAGUYAFRENCHSYNERGYDEBUFF, mapData,false,0,true,count,true,SpecialAddSkillType.AddLevel,origin.Id);
|
||||
//target.GetSkill(SkillType.KAGUYAFRENCHSYNERGYDEBUFF, out var debuffSkill);
|
||||
//debuffSkill.AddLevel(mapData, origin, target, count);
|
||||
|
||||
@ -50,6 +50,9 @@ namespace Logic.Skill
|
||||
{
|
||||
if (healType != HealType.AttackAllyHeal) return;
|
||||
if (mapData == null || origin == null || target == null) return;
|
||||
var originId = origin.Id;
|
||||
var targetId = target.Id;
|
||||
if (!TryGetLiveUnit(mapData, originId, out origin) || !TryGetLiveUnit(mapData, targetId, out target)) return;
|
||||
|
||||
//处理三连发
|
||||
if (origin.Skills != null && origin.GetSkill(SkillType.SANAENINE, out var _))
|
||||
@ -57,6 +60,7 @@ namespace Logic.Skill
|
||||
bool again = false;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (!TryGetLiveUnit(mapData, originId, out origin) || !TryGetLiveUnit(mapData, targetId, out target)) return;
|
||||
var divine = GetBuff(mapData, origin,true, out var skill);
|
||||
if(divine is SanaeDivineType.BigUnlucky or SanaeDivineType.BigLucky)
|
||||
again = true;
|
||||
@ -65,10 +69,8 @@ namespace Logic.Skill
|
||||
var timer = Timer.Instance;
|
||||
System.Action playOmikuji = () =>
|
||||
{
|
||||
if (mapData == null || origin == null || target == null) return;
|
||||
var originGrid = origin.Grid(mapData);
|
||||
var targetGrid = target.Grid(mapData);
|
||||
if (originGrid == null || targetGrid == null) return;
|
||||
if (!TryGetLiveUnitGrid(mapData, originId, out _, out var originGrid)) return;
|
||||
if (!TryGetLiveUnitGrid(mapData, targetId, out _, out var targetGrid)) return;
|
||||
//处理投掷神签动画
|
||||
OmikujiAnim(mapData, originGrid, targetGrid, divine);
|
||||
};
|
||||
@ -85,6 +87,7 @@ namespace Logic.Skill
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!TryGetLiveUnit(mapData, targetId, out target)) return;
|
||||
target.AddSkill_Legacy(skill,mapData,false,1,false,-1,false,SpecialAddSkillType.AddTurnLimit,origin.Id);
|
||||
if (divine == SanaeDivineType.BigLucky)
|
||||
{
|
||||
@ -96,11 +99,15 @@ namespace Logic.Skill
|
||||
|
||||
}
|
||||
if(again)
|
||||
{
|
||||
if (!TryGetLiveUnit(mapData, originId, out origin)) return;
|
||||
origin.SetFullActionPoint_AllSkillRefresh();
|
||||
}
|
||||
}
|
||||
//处理单次效果
|
||||
else
|
||||
{
|
||||
if (!TryGetLiveUnit(mapData, originId, out origin) || !TryGetLiveUnit(mapData, targetId, out target)) return;
|
||||
var divine = GetBuff(mapData, origin, true, out var skill);
|
||||
//处理投掷神签动画
|
||||
var originGrid = origin.Grid(mapData);
|
||||
@ -112,13 +119,16 @@ namespace Logic.Skill
|
||||
{
|
||||
BigUnlucky(mapData, origin,targetGrid,0);
|
||||
//origin.
|
||||
if (!TryGetLiveUnit(mapData, originId, out origin)) return;
|
||||
origin.SetFullActionPoint_AllSkillRefresh();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!TryGetLiveUnit(mapData, targetId, out target)) return;
|
||||
target.AddSkill_Legacy(skill,mapData,false,1,false, -1,false,SpecialAddSkillType.AddTurnLimit,origin.Id);
|
||||
if (divine == SanaeDivineType.BigLucky)
|
||||
{
|
||||
if (!TryGetLiveUnit(mapData, originId, out origin)) return;
|
||||
origin.SetFullActionPoint_AllSkillRefresh();
|
||||
BigLucky(mapData, origin,targetGrid,0f);
|
||||
}
|
||||
@ -133,23 +143,30 @@ namespace Logic.Skill
|
||||
{
|
||||
if (mapData == null || info?.DamageOrigin == null || info.DamageTargetGrid == null) return;
|
||||
if (info.DamageType != DamageType.ActiveAttack) return;
|
||||
var originId = info.DamageOrigin.Id;
|
||||
var targetGridId = info.DamageTargetGrid.Id;
|
||||
var targetId = info.DamageTarget?.Id ?? 0;
|
||||
if (!TryGetLiveUnitGrid(mapData, originId, out var origin, out _)) return;
|
||||
if (!TryGetLiveGrid(mapData, targetGridId, out var targetGrid)) return;
|
||||
|
||||
//如果是三连发
|
||||
if (info.DamageOrigin.Skills != null && info.DamageOrigin.GetSkill(SkillType.SANAENINE,out var _))
|
||||
if (origin.Skills != null && origin.GetSkill(SkillType.SANAENINE,out var _))
|
||||
{
|
||||
bool again = false;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
var divine = GetBuff(mapData, info.DamageOrigin,false, out var skill);
|
||||
if (!TryGetLiveUnitGrid(mapData, originId, out origin, out _)) return;
|
||||
if (!TryGetLiveGrid(mapData, targetGridId, out targetGrid)) return;
|
||||
var divine = GetBuff(mapData, origin,false, out var skill);
|
||||
if(divine is SanaeDivineType.BigUnlucky or SanaeDivineType.BigLucky)
|
||||
again = true;
|
||||
|
||||
System.Action playOmikuji = () =>
|
||||
{
|
||||
if (mapData == null || info.DamageOrigin == null || info.DamageTargetGrid == null) return;
|
||||
var originGrid = info.DamageOrigin.Grid(mapData);
|
||||
if (originGrid == null) return;
|
||||
if (!TryGetLiveUnitGrid(mapData, originId, out _, out var originGrid)) return;
|
||||
if (!TryGetLiveGrid(mapData, targetGridId, out var liveTargetGrid)) return;
|
||||
//处理投掷神签动画
|
||||
OmikujiAnim(mapData, originGrid, info.DamageTargetGrid, divine);
|
||||
OmikujiAnim(mapData, originGrid, liveTargetGrid, divine);
|
||||
};
|
||||
if (Timer.Instance == null)
|
||||
playOmikuji();
|
||||
@ -157,46 +174,54 @@ namespace Logic.Skill
|
||||
Timer.Instance.TimerRegister(this, playOmikuji,1.1f * i,"SANAEDIVINE - SANAENINE");
|
||||
//处理大凶
|
||||
if (divine == SanaeDivineType.BigUnlucky)
|
||||
BigUnlucky(mapData, info.DamageOrigin,info.DamageTargetGrid,1.1f * i);
|
||||
BigUnlucky(mapData, origin,targetGrid,1.1f * i);
|
||||
|
||||
else
|
||||
{
|
||||
//skill = SkillType.DIVINE_E4_KILL;
|
||||
info.DamageTarget?.AddSkill_Legacy(skill,mapData,false,1,false, -1,false, SpecialAddSkillType.AddTurnLimit,info.DamageOrigin.Id);
|
||||
if (targetId != 0 && TryGetLiveUnit(mapData, targetId, out var liveTarget))
|
||||
liveTarget.AddSkill_Legacy(skill,mapData,false,1,false, -1,false, SpecialAddSkillType.AddTurnLimit,origin.Id);
|
||||
if (divine == SanaeDivineType.BigLucky)
|
||||
{
|
||||
BigLucky(mapData, info.DamageOrigin,info.DamageTargetGrid,1.1f * i);
|
||||
BigLucky(mapData, origin,targetGrid,1.1f * i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if(again)
|
||||
info.DamageOrigin.SetFullActionPoint_AllSkillRefresh();
|
||||
{
|
||||
if (!TryGetLiveUnit(mapData, originId, out origin)) return;
|
||||
origin.SetFullActionPoint_AllSkillRefresh();
|
||||
}
|
||||
}
|
||||
//如果是单发
|
||||
else
|
||||
{
|
||||
var divine = GetBuff(mapData, info.DamageOrigin,false, out var skill);
|
||||
if (!TryGetLiveUnitGrid(mapData, originId, out origin, out var originGrid)) return;
|
||||
if (!TryGetLiveGrid(mapData, targetGridId, out targetGrid)) return;
|
||||
var divine = GetBuff(mapData, origin,false, out var skill);
|
||||
//处理投掷神签动画
|
||||
var originGrid = info.DamageOrigin.Grid(mapData);
|
||||
if (originGrid == null) return;
|
||||
OmikujiAnim(mapData, originGrid, info.DamageTargetGrid, divine);
|
||||
OmikujiAnim(mapData, originGrid, targetGrid, divine);
|
||||
|
||||
//处理大凶
|
||||
if (divine == SanaeDivineType.BigUnlucky)
|
||||
{
|
||||
BigUnlucky(mapData, info.DamageOrigin,info.DamageTargetGrid,0f);
|
||||
info.DamageOrigin.SetFullActionPoint_AllSkillRefresh();
|
||||
BigUnlucky(mapData, origin,targetGrid,0f);
|
||||
if (!TryGetLiveUnit(mapData, originId, out origin)) return;
|
||||
origin.SetFullActionPoint_AllSkillRefresh();
|
||||
}
|
||||
else
|
||||
{
|
||||
//skill = SkillType.DIVINE_E4_KILL;
|
||||
info.DamageTarget?.AddSkill_Legacy(skill,mapData,false,1,false,-1,false,SpecialAddSkillType.AddTurnLimit,info.DamageOrigin.Id);
|
||||
if (targetId != 0 && TryGetLiveUnit(mapData, targetId, out var liveTarget))
|
||||
liveTarget.AddSkill_Legacy(skill,mapData,false,1,false,-1,false,SpecialAddSkillType.AddTurnLimit,origin.Id);
|
||||
if (divine == SanaeDivineType.BigLucky)
|
||||
{
|
||||
info.DamageOrigin.SetFullActionPoint_AllSkillRefresh();
|
||||
BigLucky(mapData, info.DamageOrigin,info.DamageTargetGrid,0f);
|
||||
if (!TryGetLiveUnit(mapData, originId, out origin)) return;
|
||||
origin.SetFullActionPoint_AllSkillRefresh();
|
||||
BigLucky(mapData, origin,targetGrid,0f);
|
||||
}
|
||||
|
||||
}
|
||||
@ -218,11 +243,11 @@ namespace Logic.Skill
|
||||
if(Table.Instance.ProjectileTypeDataAssets != null &&
|
||||
Table.Instance.ProjectileTypeDataAssets.GetProjectileTypeInfo(omikuji, out projInfo))
|
||||
MapRenderer.Instance?.ProjectileManager?.CreateProjectile(startPos,endPos,omikuji);
|
||||
var targetGrid = target;
|
||||
var targetGridId = target.Id;
|
||||
var map = mapData;
|
||||
System.Action playOmikujiVfx = () =>
|
||||
{
|
||||
if (targetGrid == null || map == null) return;
|
||||
if (!TryGetLiveGrid(map, targetGridId, out var liveTargetGrid)) return;
|
||||
var vfx1 = divine switch
|
||||
{
|
||||
SanaeDivineType.BigLucky => GridVFXType.BigLucky,
|
||||
@ -238,7 +263,7 @@ namespace Logic.Skill
|
||||
_ => GridVFXType.BigUnluckyText
|
||||
};
|
||||
|
||||
var renderer = targetGrid.Renderer(map);
|
||||
var renderer = liveTargetGrid.Renderer(map);
|
||||
renderer?.PlayVFXInSight(new GridVFXParams(vfx1));
|
||||
renderer?.PlayVFXInSight(new GridVFXParams(vfx2));
|
||||
|
||||
@ -252,28 +277,39 @@ namespace Logic.Skill
|
||||
|
||||
private void BigUnlucky(MapData mapData, UnitData originUnit,GridData targetGrid,float waitTime)
|
||||
{
|
||||
var grid = targetGrid;
|
||||
var originId = originUnit?.Id ?? 0;
|
||||
var gridId = targetGrid?.Id ?? 0;
|
||||
if (!TryGetLiveUnit(mapData, originId, out originUnit)) return;
|
||||
if (!TryGetLiveGrid(mapData, gridId, out var grid)) return;
|
||||
|
||||
ProjectileTypeInfo projInfo = null;
|
||||
if (targetGrid.InMainSight() || (originUnit.Grid(mapData)?.InMainSight()??false))
|
||||
if ((grid.InMainSight() || (originUnit.Grid(mapData)?.InMainSight()??false))
|
||||
&& Table.Instance?.ProjectileTypeDataAssets != null)
|
||||
Table.Instance.ProjectileTypeDataAssets.GetProjectileTypeInfo(ProjectileType.SanaeOmikuji, out projInfo);
|
||||
var aroundBuf = RentAroundBuf();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, grid, aroundBuf);
|
||||
foreach (var round in aroundBuf)
|
||||
{
|
||||
if (round == null) continue;
|
||||
if (!TryGetLiveUnit(mapData, originId, out originUnit)) break;
|
||||
if (!round.RealUnit(mapData, out var unit)) continue;
|
||||
if (!unit.IsValidOnMap(mapData, round)) continue;
|
||||
if (!unit.IsAlive()) continue;
|
||||
bool sameUnion = mapData.SameUnionByUnitId(unit.Id, originUnit.Id);
|
||||
var map = mapData;
|
||||
var tmpGrid = round;
|
||||
var tmpGridId = round.Id;
|
||||
var tmpUnitId = unit.Id;
|
||||
var dmg = sameUnion ? _bigUnluckyFriendDmg : _bigUnluckyEnemyDmg;
|
||||
var canBeKilled = unit.CanBeKilled(mapData);
|
||||
var dmgInfo = Main.UnitLogic.DamageSettlement(mapData, originUnit, unit, dmg , sameUnion ? DamageType.KillSelf : DamageType.Splash);
|
||||
if (dmgInfo?.DamageTargetGrid == null) continue;
|
||||
//处理视觉
|
||||
if (dmgInfo.DamageTargetGrid.InMainSight())
|
||||
{
|
||||
|
||||
Timer.Instance.TimerRegister(this, () =>
|
||||
RegisterOrRunTimer(() =>
|
||||
{
|
||||
if (!TryGetLiveGrid(map, tmpGridId, out var tmpGrid)) return;
|
||||
tmpGrid.Renderer(map)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Hurt));
|
||||
tmpGrid.Renderer(map)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Damage,dmg));
|
||||
if (dmgInfo.IsKill)
|
||||
@ -282,7 +318,8 @@ namespace Logic.Skill
|
||||
if (canBeKilled)
|
||||
tmpGrid.Renderer(map)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Die));
|
||||
}
|
||||
unit.Renderer(map)?.InstantUpdateUnit(showoff: true);
|
||||
if (TryGetLiveUnit(map, tmpUnitId, out var liveUnit))
|
||||
liveUnit.Renderer(map)?.InstantUpdateUnit(showoff: true);
|
||||
|
||||
},(projInfo?.AnimTime ?? 0f )+ waitTime,"SANAEDIVINE OMIKUJI BigUnlucky Anim");
|
||||
}
|
||||
@ -293,29 +330,40 @@ namespace Logic.Skill
|
||||
|
||||
private void BigLucky(MapData mapData, UnitData originUnit,GridData targetGrid,float waitTime)
|
||||
{
|
||||
var grid = targetGrid;
|
||||
var originId = originUnit?.Id ?? 0;
|
||||
var gridId = targetGrid?.Id ?? 0;
|
||||
if (!TryGetLiveUnit(mapData, originId, out originUnit)) return;
|
||||
if (!TryGetLiveGrid(mapData, gridId, out var grid)) return;
|
||||
|
||||
ProjectileTypeInfo projInfo = null;
|
||||
if (targetGrid.InMainSight() || (originUnit.Grid(mapData)?.InMainSight()??false))
|
||||
if ((grid.InMainSight() || (originUnit.Grid(mapData)?.InMainSight()??false))
|
||||
&& Table.Instance?.ProjectileTypeDataAssets != null)
|
||||
Table.Instance.ProjectileTypeDataAssets.GetProjectileTypeInfo(ProjectileType.SanaeOmikuji, out projInfo);
|
||||
var aroundBuf = RentAroundBuf();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, grid, aroundBuf);
|
||||
foreach (var round in aroundBuf)
|
||||
{
|
||||
if (round == null) continue;
|
||||
if (!TryGetLiveUnit(mapData, originId, out originUnit)) break;
|
||||
if (!round.RealUnit(mapData, out var unit)) continue;
|
||||
if (!unit.IsValidOnMap(mapData, round)) continue;
|
||||
bool sameUnion = mapData.SameUnionByUnitId(unit.Id, originUnit.Id);
|
||||
var map = mapData;
|
||||
var tmpGrid = round;
|
||||
var tmpGridId = round.Id;
|
||||
var tmpUnitId = unit.Id;
|
||||
//处理敌人
|
||||
if (!sameUnion)
|
||||
{
|
||||
var canBeKilled = unit.CanBeKilled(mapData);
|
||||
var dmgInfo = Main.UnitLogic.DamageSettlement(mapData, originUnit, unit, _bigLuckyDmg , DamageType.Splash);
|
||||
if (dmgInfo?.DamageTargetGrid == null) continue;
|
||||
//处理视觉
|
||||
if (dmgInfo.DamageTargetGrid.InMainSight())
|
||||
{
|
||||
|
||||
Timer.Instance.TimerRegister(this, () =>
|
||||
RegisterOrRunTimer(() =>
|
||||
{
|
||||
if (!TryGetLiveGrid(map, tmpGridId, out var tmpGrid)) return;
|
||||
tmpGrid.Renderer(map)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Hurt));
|
||||
tmpGrid.Renderer(map)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Damage,4));
|
||||
if (dmgInfo.IsKill)
|
||||
@ -325,7 +373,8 @@ namespace Logic.Skill
|
||||
tmpGrid.Renderer(map)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Die));
|
||||
}
|
||||
|
||||
unit.Renderer(map)?.InstantUpdateUnit(showoff: true);
|
||||
if (TryGetLiveUnit(map, tmpUnitId, out var liveUnit))
|
||||
liveUnit.Renderer(map)?.InstantUpdateUnit(showoff: true);
|
||||
|
||||
},(projInfo?.AnimTime ?? 0f) + waitTime,"SANAEDIVINE OMIKUJI BigUnlucky Anim");
|
||||
}
|
||||
@ -338,10 +387,12 @@ namespace Logic.Skill
|
||||
//处理视觉
|
||||
if (unit.Grid(map)?.InMainSight()??false)
|
||||
{
|
||||
Timer.Instance.TimerRegister(this, () =>
|
||||
RegisterOrRunTimer(() =>
|
||||
{
|
||||
if (!TryGetLiveGrid(map, tmpGridId, out var tmpGrid)) return;
|
||||
tmpGrid.Renderer(map)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Heal));
|
||||
unit.Renderer(map)?.InstantUpdateUnit(showoff: true);
|
||||
if (TryGetLiveUnit(map, tmpUnitId, out var liveUnit))
|
||||
liveUnit.Renderer(map)?.InstantUpdateUnit(showoff: true);
|
||||
|
||||
},projInfo?.AnimTime ?? 0f,"SANAEDIVINE OMIKUJI BigUnlucky Anim");
|
||||
}
|
||||
@ -353,10 +404,47 @@ namespace Logic.Skill
|
||||
}
|
||||
ReturnAroundBuf();
|
||||
}
|
||||
|
||||
private void RegisterOrRunTimer(System.Action action, float delay, string message)
|
||||
{
|
||||
if (action == null) return;
|
||||
var timer = Timer.Instance;
|
||||
if (timer == null)
|
||||
{
|
||||
action();
|
||||
return;
|
||||
}
|
||||
|
||||
timer.TimerRegister(this, action, delay, message);
|
||||
}
|
||||
|
||||
private static bool TryGetLiveUnit(MapData mapData, uint unitId, out UnitData unit)
|
||||
{
|
||||
unit = null;
|
||||
if (unitId == 0 || mapData?.UnitMap == null) return false;
|
||||
return mapData.UnitMap.GetUnitDataByUnitId(unitId, out unit)
|
||||
&& unit != null
|
||||
&& unit.IsValidOnMap(mapData);
|
||||
}
|
||||
|
||||
private static bool TryGetLiveGrid(MapData mapData, uint gridId, out GridData grid)
|
||||
{
|
||||
grid = null;
|
||||
if (gridId == 0 || mapData?.GridMap == null) return false;
|
||||
return mapData.GridMap.GetGridDataByGid(gridId, out grid) && grid != null;
|
||||
}
|
||||
|
||||
private static bool TryGetLiveUnitGrid(MapData mapData, uint unitId, out UnitData unit, out GridData grid)
|
||||
{
|
||||
grid = null;
|
||||
if (!TryGetLiveUnit(mapData, unitId, out unit)) return false;
|
||||
return mapData.GetGridDataByUnitId(unit.Id, out grid) && grid != null;
|
||||
}
|
||||
|
||||
public SanaeDivineType GetBuff(MapData map, UnitData self,bool IsHeal, out SkillType skill)
|
||||
{
|
||||
skill = SkillType.NONE;
|
||||
if (map?.Net == null || self == null) return SanaeDivineType.Lucky;
|
||||
var roll = map.Net.GetRandom(map).Next(1, 101); // 生成1到100的随机数
|
||||
var buff = SanaeDivineType.Lucky;
|
||||
|
||||
|
||||
@ -37,8 +37,11 @@ namespace Logic.Skill
|
||||
|
||||
public override void OnMove(UnitData self, GridData grid, MapData mapData, MoveType moveType, List<Vector2Int> path = null)
|
||||
{
|
||||
if (mapData == null || self == null || grid == null) return;
|
||||
if (!self.IsValidOnMap(mapData, grid)) return;
|
||||
if (!mapData.GetPlayerDataByUnitId(self.Id, out var selfPlayer)) return;
|
||||
|
||||
using var pooledSelfUnitList = THCollectionPool.GetHashSetHandle<UnitData>(out var selfUnitList);
|
||||
mapData.GetPlayerDataByUnitId(self.Id, out var selfPlayer);
|
||||
mapData.GetUnitDataListByPlayerId(selfPlayer.Id, selfUnitList);
|
||||
|
||||
// 收集需要视觉更新的数据。Renderer 必须在 DamageSettlement 前缓存。
|
||||
@ -49,12 +52,18 @@ namespace Logic.Skill
|
||||
mapData.GridMap.GetAroundGridData(1, 1, grid, aroundBuf);
|
||||
foreach (var roundGrid in aroundBuf)
|
||||
{
|
||||
var ROgrid = MapRenderer.Instance.ROGridMap[roundGrid.Id];
|
||||
if (roundGrid == null) continue;
|
||||
if (!self.IsValidOnMap(mapData, grid)) break;
|
||||
|
||||
GridRenderer ROgrid = null;
|
||||
if (mapData == Main.MapData)
|
||||
MapRenderer.Instance?.ROGridMap?.TryGetValue(roundGrid.Id, out ROgrid);
|
||||
|
||||
//如果格子上没有单位,播放地震动画
|
||||
if (!roundGrid.RealUnit(mapData,out var unit))
|
||||
{
|
||||
//TODO 下面的是不规范做法,后面要迭代
|
||||
if (roundGrid.InMainSight())
|
||||
if (ROgrid != null && roundGrid.InMainSight())
|
||||
{
|
||||
ROgrid.SetBounceAnim(NeedRandomWait:true);
|
||||
}
|
||||
@ -68,7 +77,8 @@ namespace Logic.Skill
|
||||
var damage = Table.Instance.CalcDamage(mapData, self, unit, damagePara:0.5f);
|
||||
|
||||
var targetRenderer = unit.Renderer(mapData);
|
||||
Main.UnitLogic.DamageSettlement(mapData, self, unit, damage, DamageType.Splash);
|
||||
var settlement = Main.UnitLogic.DamageSettlement(mapData, self, unit, damage, DamageType.Splash);
|
||||
if (settlement == null) continue;
|
||||
bool wasKilled = !unit.IsAlive();
|
||||
|
||||
if (roundGrid.InMainSight())
|
||||
@ -116,7 +126,7 @@ namespace Logic.Skill
|
||||
g.Renderer(mapData)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Hurt));
|
||||
g.Renderer(mapData)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Damage, d));
|
||||
g.Renderer(mapData)?.InstantUpdateGrid();
|
||||
ro.SetBounceAnim(NeedRandomWait:true);
|
||||
ro?.SetBounceAnim(NeedRandomWait:true);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -141,7 +151,7 @@ namespace Logic.Skill
|
||||
roundGrid.Renderer(mapData)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Hurt));
|
||||
roundGrid.Renderer(mapData)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Damage, damage));
|
||||
roundGrid.Renderer(mapData)?.InstantUpdateGrid();
|
||||
ROgrid.SetBounceAnim(NeedRandomWait:true);
|
||||
ROgrid?.SetBounceAnim(NeedRandomWait:true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,52 +192,68 @@ namespace TH1_Logic.Steam
|
||||
// 连接前检查
|
||||
private bool PreConnectionCheck(CSteamID targetSteamID)
|
||||
{
|
||||
// 检查Steam是否已登录
|
||||
if (!SteamUser.BLoggedOn())
|
||||
try
|
||||
{
|
||||
LogSystem.LogError("Steam not logged in");
|
||||
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.SteamLoginRequired);
|
||||
// 检查Steam是否已登录
|
||||
if (!SteamUser.BLoggedOn())
|
||||
{
|
||||
LogSystem.LogWarning("Steam not logged in");
|
||||
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.SteamLoginRequired);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查目标用户是否在线
|
||||
var friendState = SteamFriends.GetFriendPersonaState(targetSteamID);
|
||||
if (friendState == EPersonaState.k_EPersonaStateOffline)
|
||||
{
|
||||
LogSystem.LogWarning($"Target user {targetSteamID} appears offline");
|
||||
}
|
||||
|
||||
// 检查当前lobby信息
|
||||
LogSystem.LogInfo("Checking lobby status...");
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogSystem.LogWarning($"Steam P2P pre-check skipped: {ex.Message}");
|
||||
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.SteamUnavailable);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查目标用户是否在线
|
||||
var friendState = SteamFriends.GetFriendPersonaState(targetSteamID);
|
||||
if (friendState == EPersonaState.k_EPersonaStateOffline)
|
||||
{
|
||||
LogSystem.LogWarning($"Target user {targetSteamID} appears offline");
|
||||
}
|
||||
|
||||
// 检查当前lobby信息
|
||||
LogSystem.LogInfo("Checking lobby status...");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void DiagnoseNetworkStatus(CSteamID targetSteamID)
|
||||
{
|
||||
LogSystem.LogInfo("=== P2P 连接诊断 ===");
|
||||
|
||||
// Steam 状态
|
||||
LogSystem.LogInfo($"Steam 登录状态: {SteamUser.BLoggedOn()}");
|
||||
LogSystem.LogInfo($"本地 Steam ID: {SteamUser.GetSteamID()}");
|
||||
|
||||
// 目标用户状态
|
||||
var friendState = SteamFriends.GetFriendPersonaState(targetSteamID);
|
||||
LogSystem.LogInfo($"目标用户状态: {friendState}");
|
||||
|
||||
// 检查是否是好友
|
||||
var relationShip = SteamFriends.GetFriendRelationship(targetSteamID);
|
||||
LogSystem.LogInfo($"好友关系: {relationShip}");
|
||||
|
||||
// Steam 网络状态
|
||||
SteamNetworkingUtils.GetRelayNetworkStatus(out var relayStatus);
|
||||
LogSystem.LogInfo($"Steam 中继网络: {relayStatus.m_eAvail}");
|
||||
LogSystem.LogInfo($"中继网络调试信息: {relayStatus.m_debugMsg}");
|
||||
|
||||
if (relayStatus.m_eAvail != ESteamNetworkingAvailability.k_ESteamNetworkingAvailability_Current)
|
||||
try
|
||||
{
|
||||
LogSystem.LogWarning($"Steam 中继网络问题: {relayStatus.m_debugMsg}");
|
||||
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.P2PConnectionFailed);
|
||||
LogSystem.LogInfo("=== P2P 连接诊断 ===");
|
||||
|
||||
// Steam 状态
|
||||
LogSystem.LogInfo($"Steam 登录状态: {SteamUser.BLoggedOn()}");
|
||||
LogSystem.LogInfo($"本地 Steam ID: {SteamUser.GetSteamID()}");
|
||||
|
||||
// 目标用户状态
|
||||
var friendState = SteamFriends.GetFriendPersonaState(targetSteamID);
|
||||
LogSystem.LogInfo($"目标用户状态: {friendState}");
|
||||
|
||||
// 检查是否是好友
|
||||
var relationShip = SteamFriends.GetFriendRelationship(targetSteamID);
|
||||
LogSystem.LogInfo($"好友关系: {relationShip}");
|
||||
|
||||
// Steam 网络状态
|
||||
SteamNetworkingUtils.GetRelayNetworkStatus(out var relayStatus);
|
||||
LogSystem.LogInfo($"Steam 中继网络: {relayStatus.m_eAvail}");
|
||||
LogSystem.LogInfo($"中继网络调试信息: {relayStatus.m_debugMsg}");
|
||||
|
||||
if (relayStatus.m_eAvail != ESteamNetworkingAvailability.k_ESteamNetworkingAvailability_Current)
|
||||
{
|
||||
LogSystem.LogWarning($"Steam 中继网络问题: {relayStatus.m_debugMsg}");
|
||||
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.P2PConnectionFailed);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogSystem.LogWarning($"Steam P2P diagnose skipped: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -78,6 +78,8 @@ namespace TH1_Logic.Steam
|
||||
private bool _steamServerConnected = false;
|
||||
private int _steamSessionFailCount;
|
||||
private bool _isHandlingSessionLoss;
|
||||
private bool _steamApiUnavailable;
|
||||
private bool _steamApiUnavailableLogged;
|
||||
private int _suppressP2PSendFailureLobbyErrors;
|
||||
private const float SteamSessionCheckInterval = 1f;
|
||||
private const int SteamSessionFailThreshold = 2;
|
||||
@ -146,6 +148,8 @@ namespace TH1_Logic.Steam
|
||||
_refreshSteamStatus = 0;
|
||||
_steamSessionFailCount = 0;
|
||||
_isHandlingSessionLoss = false;
|
||||
_steamApiUnavailable = false;
|
||||
_steamApiUnavailableLogged = false;
|
||||
_onlineFriendsId = new Dictionary<ulong, CSteamID>();
|
||||
_onlineFriendsInfo = new Dictionary<ulong, MemberInfo>();
|
||||
_memberInfos = new Dictionary<ulong, MemberInfo>();
|
||||
@ -154,10 +158,101 @@ namespace TH1_Logic.Steam
|
||||
|
||||
_status = new SteamNetworkStatus();
|
||||
}
|
||||
|
||||
private bool TrySteamApi<T>(string context, Func<T> action, out T value)
|
||||
{
|
||||
value = default;
|
||||
if (_steamApiUnavailable) return false;
|
||||
try
|
||||
{
|
||||
value = action();
|
||||
return true;
|
||||
}
|
||||
catch (DllNotFoundException e)
|
||||
{
|
||||
MarkSteamApiUnavailable(context, e);
|
||||
return false;
|
||||
}
|
||||
catch (EntryPointNotFoundException e)
|
||||
{
|
||||
MarkSteamApiUnavailable(context, e);
|
||||
return false;
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
MarkSteamApiUnavailable(context, e);
|
||||
return false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogSystem.LogWarning($"Steam API call failed at {context}: {e.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool TrySteamApi(string context, System.Action action)
|
||||
{
|
||||
if (_steamApiUnavailable) return false;
|
||||
try
|
||||
{
|
||||
action();
|
||||
return true;
|
||||
}
|
||||
catch (DllNotFoundException e)
|
||||
{
|
||||
MarkSteamApiUnavailable(context, e);
|
||||
return false;
|
||||
}
|
||||
catch (EntryPointNotFoundException e)
|
||||
{
|
||||
MarkSteamApiUnavailable(context, e);
|
||||
return false;
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
MarkSteamApiUnavailable(context, e);
|
||||
return false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogSystem.LogWarning($"Steam API call failed at {context}: {e.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void MarkSteamApiUnavailable(string context, Exception e)
|
||||
{
|
||||
_steamApiUnavailable = true;
|
||||
_isSteamInitialized = false;
|
||||
_isLoggedIn = false;
|
||||
_isLobbyInitialized = false;
|
||||
_steamServerConnected = false;
|
||||
_status = new SteamNetworkStatus();
|
||||
|
||||
if (!_steamApiUnavailableLogged)
|
||||
{
|
||||
_steamApiUnavailableLogged = true;
|
||||
LogSystem.LogWarning($"Steam API unavailable at {context}: {e.GetType().Name}: {e.Message}");
|
||||
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.SteamUnavailable);
|
||||
}
|
||||
}
|
||||
|
||||
private bool EnsureSteamReadyForLobbyAction(string context)
|
||||
{
|
||||
if (_steamApiUnavailable || !_isSteamInitialized)
|
||||
{
|
||||
LogSystem.LogWarning($"Steam lobby action skipped because Steam API is unavailable: {context}");
|
||||
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.SteamUnavailable);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 初始化
|
||||
public void Init()
|
||||
{
|
||||
if (_steamApiUnavailable) return;
|
||||
_steamSDKUpdateRecord += Time.deltaTime;
|
||||
if (_steamSDKUpdateRecord < 2) return;
|
||||
_steamSDKUpdateRecord = 0;
|
||||
@ -171,10 +266,11 @@ namespace TH1_Logic.Steam
|
||||
// 刷新 Steam
|
||||
private void RefreshSteamInit()
|
||||
{
|
||||
if (_steamApiUnavailable) return;
|
||||
if (_isSteamInitialized) return;
|
||||
|
||||
// 检查Steam是否运行
|
||||
if (!SteamAPI.IsSteamRunning())
|
||||
if (!TrySteamApi("SteamAPI.IsSteamRunning", SteamAPI.IsSteamRunning, out var steamRunning) || !steamRunning)
|
||||
{
|
||||
// LogSystem.LogError("Steam客户端未运行!请先启动Steam。");
|
||||
return;
|
||||
@ -182,25 +278,51 @@ namespace TH1_Logic.Steam
|
||||
|
||||
// 初始化Steam API
|
||||
LogSystem.LogInfo("开始初始化Steam...");
|
||||
var initResult = SteamAPI.InitEx(out string steamErrMsg);
|
||||
ESteamAPIInitResult initResult;
|
||||
string steamErrMsg;
|
||||
try
|
||||
{
|
||||
initResult = SteamAPI.InitEx(out steamErrMsg);
|
||||
}
|
||||
catch (DllNotFoundException e)
|
||||
{
|
||||
MarkSteamApiUnavailable("SteamAPI.InitEx", e);
|
||||
return;
|
||||
}
|
||||
catch (EntryPointNotFoundException e)
|
||||
{
|
||||
MarkSteamApiUnavailable("SteamAPI.InitEx", e);
|
||||
return;
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
MarkSteamApiUnavailable("SteamAPI.InitEx", e);
|
||||
return;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogSystem.LogWarning($"Steam API initialization failed: {e.Message}");
|
||||
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.SteamUnavailable);
|
||||
return;
|
||||
}
|
||||
_isSteamInitialized = initResult == ESteamAPIInitResult.k_ESteamAPIInitResult_OK;
|
||||
|
||||
if (!_isSteamInitialized)
|
||||
{
|
||||
LogSystem.LogError($"Steam API初始化失败!result={initResult}, msg={steamErrMsg}");
|
||||
LogSystem.LogWarning($"Steam API初始化失败!result={initResult}, msg={steamErrMsg}");
|
||||
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.SteamUnavailable);
|
||||
switch (initResult)
|
||||
{
|
||||
case ESteamAPIInitResult.k_ESteamAPIInitResult_NoSteamClient:
|
||||
LogSystem.LogError("→ Steam客户端未运行或未登录,请先打开Steam并登录账号。");
|
||||
LogSystem.LogWarning("→ Steam客户端未运行或未登录,请先打开Steam并登录账号。");
|
||||
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.SteamLoginRequired);
|
||||
break;
|
||||
case ESteamAPIInitResult.k_ESteamAPIInitResult_VersionMismatch:
|
||||
LogSystem.LogError("→ Steam客户端版本过旧,请在Steam中检查更新。");
|
||||
LogSystem.LogWarning("→ Steam客户端版本过旧,请在Steam中检查更新。");
|
||||
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.SteamClientOutdated);
|
||||
break;
|
||||
case ESteamAPIInitResult.k_ESteamAPIInitResult_FailedGeneric:
|
||||
LogSystem.LogError("→ 通用失败。常见原因:当前Steam账号未拥有该AppID(需在Steamworks后台授予权限);或工作目录下steam_appid.txt位置错误;或上一次进程未退干净。");
|
||||
LogSystem.LogWarning("→ 通用失败。常见原因:当前Steam账号未拥有该AppID(需在Steamworks后台授予权限);或工作目录下steam_appid.txt位置错误;或上一次进程未退干净。");
|
||||
break;
|
||||
}
|
||||
return;
|
||||
@ -217,8 +339,10 @@ namespace TH1_Logic.Steam
|
||||
if (!_isSteamInitialized) return;
|
||||
|
||||
// 基础Steam连接状态
|
||||
_status.IsSteamConnected = SteamAPI.IsSteamRunning();
|
||||
_status.IsLoggedOn = SteamUser.BLoggedOn();
|
||||
if (!TrySteamApi("RefreshSteamStatus.IsSteamRunning", SteamAPI.IsSteamRunning, out var steamRunning)) return;
|
||||
if (!TrySteamApi("RefreshSteamStatus.BLoggedOn", SteamUser.BLoggedOn, out var loggedOn)) return;
|
||||
_status.IsSteamConnected = steamRunning;
|
||||
_status.IsLoggedOn = loggedOn;
|
||||
_status.IsInLobby = IsInLobby();
|
||||
_status.IsP2PReady = SimpleP2P.Instance?.IsInitialized ?? false;
|
||||
_status.SteamServerConnected = IsSteamSessionLikelyAlive();
|
||||
@ -229,25 +353,18 @@ namespace TH1_Logic.Steam
|
||||
private void RefreshLoginStatus()
|
||||
{
|
||||
if (!_isSteamInitialized || _isLoggedIn) return;
|
||||
try
|
||||
if (!TrySteamApi("RefreshLoginStatus.BLoggedOn", SteamUser.BLoggedOn, out var loggedOn)) return;
|
||||
_isLoggedIn = loggedOn;
|
||||
if (_isLoggedIn)
|
||||
{
|
||||
_isLoggedIn = SteamUser.BLoggedOn();
|
||||
if (_isLoggedIn)
|
||||
{
|
||||
_selfID = SteamUser.GetSteamID();
|
||||
_selfName = SteamFriends.GetPersonaName();
|
||||
LogSystem.LogInfo($"Steam用户已登录: {_selfName} ({_selfID})");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogSystem.LogWarning("Steam用户未登录");
|
||||
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.SteamLoginRequired);
|
||||
}
|
||||
if (!TrySteamApi("RefreshLoginStatus.GetSteamID", SteamUser.GetSteamID, out _selfID)) return;
|
||||
if (!TrySteamApi("RefreshLoginStatus.GetPersonaName", SteamFriends.GetPersonaName, out _selfName)) return;
|
||||
LogSystem.LogInfo($"Steam用户已登录: {_selfName} ({_selfID})");
|
||||
}
|
||||
catch (System.Exception e)
|
||||
else
|
||||
{
|
||||
LogSystem.LogError($"检查用户登录状态异常: {e.Message}");
|
||||
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.SteamUnavailable);
|
||||
LogSystem.LogWarning("Steam用户未登录");
|
||||
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.SteamLoginRequired);
|
||||
}
|
||||
}
|
||||
|
||||
@ -291,16 +408,17 @@ namespace TH1_Logic.Steam
|
||||
// 添加房间内的非好友成员
|
||||
if (CurrentLobby.IsValid())
|
||||
{
|
||||
int memberCount = SteamMatchmaking.GetNumLobbyMembers(CurrentLobby);
|
||||
if (!TrySteamApi("RefreshOnlineFriends.GetNumLobbyMembers", () => SteamMatchmaking.GetNumLobbyMembers(CurrentLobby), out var memberCount)) return;
|
||||
var selfMemberId = GetSelfMemberId();
|
||||
for (int i = 0; i < memberCount; i++)
|
||||
{
|
||||
var memberId = SteamMatchmaking.GetLobbyMemberByIndex(CurrentLobby, i);
|
||||
if (!TrySteamApi("RefreshOnlineFriends.GetLobbyMemberByIndex", () => SteamMatchmaking.GetLobbyMemberByIndex(CurrentLobby, i), out var memberId)) return;
|
||||
// 跳过自己
|
||||
if (memberId == SteamUser.GetSteamID()) continue;
|
||||
if (memberId.m_SteamID == selfMemberId) continue;
|
||||
// 检查是否已在好友列表中
|
||||
if (friends.All(f => f.id != memberId))
|
||||
{
|
||||
string memberName = SteamFriends.GetFriendPersonaName(memberId);
|
||||
if (!TrySteamApi("RefreshOnlineFriends.GetFriendPersonaName", () => SteamFriends.GetFriendPersonaName(memberId), out var memberName)) return;
|
||||
friends.Add((memberId, memberName));
|
||||
}
|
||||
}
|
||||
@ -353,7 +471,7 @@ namespace TH1_Logic.Steam
|
||||
if (!_isSteamInitialized || !_isLoggedIn || !_isLobbyInitialized) return;
|
||||
|
||||
// 更新Steam回调
|
||||
SteamAPI.RunCallbacks();
|
||||
if (!TrySteamApi("SteamAPI.RunCallbacks", SteamAPI.RunCallbacks)) return;
|
||||
|
||||
SimpleP2P.Instance.Update();
|
||||
SimpleP2P.Instance.PollMessages();
|
||||
@ -418,10 +536,35 @@ namespace TH1_Logic.Steam
|
||||
public bool IsSteamSessionLikelyAlive()
|
||||
{
|
||||
if (!_isSteamInitialized) return false;
|
||||
if (!SteamAPI.IsSteamRunning()) return false;
|
||||
if (!SteamUser.BLoggedOn()) return false;
|
||||
if (!TrySteamApi("IsSteamSessionLikelyAlive.IsSteamRunning", SteamAPI.IsSteamRunning, out var steamRunning) || !steamRunning) return false;
|
||||
if (!TrySteamApi("IsSteamSessionLikelyAlive.BLoggedOn", SteamUser.BLoggedOn, out var loggedOn) || !loggedOn) return false;
|
||||
|
||||
var avail = SteamNetworkingUtils.GetRelayNetworkStatus(out var details);
|
||||
ESteamNetworkingAvailability avail;
|
||||
SteamRelayNetworkStatus_t details;
|
||||
try
|
||||
{
|
||||
avail = SteamNetworkingUtils.GetRelayNetworkStatus(out details);
|
||||
}
|
||||
catch (DllNotFoundException e)
|
||||
{
|
||||
MarkSteamApiUnavailable("SteamNetworkingUtils.GetRelayNetworkStatus", e);
|
||||
return false;
|
||||
}
|
||||
catch (EntryPointNotFoundException e)
|
||||
{
|
||||
MarkSteamApiUnavailable("SteamNetworkingUtils.GetRelayNetworkStatus", e);
|
||||
return false;
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
MarkSteamApiUnavailable("SteamNetworkingUtils.GetRelayNetworkStatus", e);
|
||||
return false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogSystem.LogWarning($"Steam relay status check failed: {e.Message}");
|
||||
return false;
|
||||
}
|
||||
bool relayOk = avail == ESteamNetworkingAvailability.k_ESteamNetworkingAvailability_Current
|
||||
|| details.m_eAvail == ESteamNetworkingAvailability.k_ESteamNetworkingAvailability_Current;
|
||||
return relayOk;
|
||||
@ -456,16 +599,18 @@ namespace TH1_Logic.Steam
|
||||
if (!_isSteamInitialized) return;
|
||||
|
||||
// 获取当前App ID
|
||||
var currentAppId = SteamUtils.GetAppID();
|
||||
if (!TrySteamApi("DisplayLaunchInfo.GetAppID", SteamUtils.GetAppID, out var currentAppId)) return;
|
||||
LogSystem.LogInfo($"当前Steam App ID: {currentAppId}");
|
||||
|
||||
// 检查启动方式
|
||||
bool launchedViaSteam = SteamApps.BIsSubscribedApp(currentAppId);
|
||||
if (!TrySteamApi("DisplayLaunchInfo.BIsSubscribedApp", () => SteamApps.BIsSubscribedApp(currentAppId), out var launchedViaSteam)) return;
|
||||
LogSystem.LogInfo($"通过Steam启动: {(launchedViaSteam ? "是" : "否")}");
|
||||
|
||||
// 显示Steam环境信息
|
||||
LogSystem.LogInfo($"Steam语言: {SteamApps.GetCurrentGameLanguage()}");
|
||||
LogSystem.LogInfo($"Steam服务器连接: {(SteamUser.BLoggedOn() ? "已连接" : "未连接")}");
|
||||
if (TrySteamApi("DisplayLaunchInfo.GetCurrentGameLanguage", SteamApps.GetCurrentGameLanguage, out var language))
|
||||
LogSystem.LogInfo($"Steam语言: {language}");
|
||||
if (TrySteamApi("DisplayLaunchInfo.BLoggedOn", SteamUser.BLoggedOn, out var loggedOn))
|
||||
LogSystem.LogInfo($"Steam服务器连接: {(loggedOn ? "已连接" : "未连接")}");
|
||||
|
||||
// 检查DLC和订阅状态
|
||||
if (currentAppId.m_AppId == 480) // Spacewar测试应用
|
||||
@ -481,6 +626,7 @@ namespace TH1_Logic.Steam
|
||||
// 建房
|
||||
public void CreateLobby(int maxMembers = 4, bool isPublic = true, string password = "")
|
||||
{
|
||||
if (!EnsureSteamReadyForLobbyAction(nameof(CreateLobby))) return;
|
||||
if (CurrentState != LobbyState.None)
|
||||
{
|
||||
LogSystem.LogInfo($"Cannot create lobby in state: {CurrentState}");
|
||||
@ -491,7 +637,8 @@ namespace TH1_Logic.Steam
|
||||
_pendingLobbyIsPublic = isPublic;
|
||||
CurrentState = LobbyState.Creating;
|
||||
LogSystem.LogInfo($"Creating {(isPublic ? "public" : "friends-only")} lobby with max members: {maxMembers}, hasPassword: {!string.IsNullOrEmpty(_pendingLobbyPassword)}");
|
||||
SteamMatchmaking.CreateLobby(isPublic?ELobbyType.k_ELobbyTypePublic:ELobbyType.k_ELobbyTypeFriendsOnly, maxMembers);
|
||||
if (!TrySteamApi("SteamMatchmaking.CreateLobby", () => SteamMatchmaking.CreateLobby(isPublic?ELobbyType.k_ELobbyTypePublic:ELobbyType.k_ELobbyTypeFriendsOnly, maxMembers)))
|
||||
ResetLobbyState();
|
||||
}
|
||||
|
||||
// 加入房间
|
||||
@ -502,6 +649,7 @@ namespace TH1_Logic.Steam
|
||||
|
||||
private void JoinLobbyInternal(CSteamID lobbyId, string password, bool requestLobbyDataIfMissing, bool checkPassword)
|
||||
{
|
||||
if (!EnsureSteamReadyForLobbyAction(nameof(JoinLobby))) return;
|
||||
if (CurrentState != LobbyState.None)
|
||||
{
|
||||
//LogSystem.LogInfo($"Cannot join lobby in state: {CurrentState}");
|
||||
@ -514,10 +662,11 @@ namespace TH1_Logic.Steam
|
||||
_pendingJoinPassword = password ?? "";
|
||||
_pendingJoinCheckPassword = checkPassword;
|
||||
|
||||
if (!SteamMatchmaking.RequestLobbyData(lobbyId))
|
||||
if (!TrySteamApi("SteamMatchmaking.RequestLobbyData", () => SteamMatchmaking.RequestLobbyData(lobbyId), out var requestLobbyData)
|
||||
|| !requestLobbyData)
|
||||
{
|
||||
ClearPendingJoinLobby();
|
||||
LogSystem.LogError($"Failed to request lobby data before joining: {lobbyId}");
|
||||
LogSystem.LogWarning($"Failed to request lobby data before joining: {lobbyId}");
|
||||
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.LobbyJoinFailed);
|
||||
OnLobbyErrorEvent?.Invoke("Failed to request lobby data before joining");
|
||||
}
|
||||
@ -528,7 +677,7 @@ namespace TH1_Logic.Steam
|
||||
if (checkPassword && !ValidateLobbyPasswordForJoin(lobbyId, password)) return;
|
||||
|
||||
// TODO 这里会涉及到房间子类对于UI的调用,对于房间的多态是不合理的,暂不处理,糊屎
|
||||
var version = SteamMatchmaking.GetLobbyData(lobbyId, "Version");
|
||||
if (!TrySteamApi("SteamMatchmaking.GetLobbyData.Version", () => SteamMatchmaking.GetLobbyData(lobbyId, "Version"), out var version)) return;
|
||||
if (!string.IsNullOrEmpty(version) && ConfigManager.Instance.VersionCfg.CurVersionInfo.Version != version)
|
||||
{
|
||||
LogSystem.LogInfo($"版本不一致 !!!");
|
||||
@ -538,7 +687,8 @@ namespace TH1_Logic.Steam
|
||||
|
||||
LogSystem.LogInfo($"Joining lobby: {lobbyId}");
|
||||
CurrentState = LobbyState.Joining;
|
||||
SteamMatchmaking.JoinLobby(lobbyId);
|
||||
if (!TrySteamApi("SteamMatchmaking.JoinLobby", () => SteamMatchmaking.JoinLobby(lobbyId)))
|
||||
ResetLobbyState();
|
||||
}
|
||||
|
||||
// 离开房间
|
||||
@ -551,7 +701,7 @@ namespace TH1_Logic.Steam
|
||||
|
||||
// 断开所有P2P连接
|
||||
SimpleP2P.Instance.DisconnectAll();
|
||||
SteamMatchmaking.LeaveLobby(CurrentLobby);
|
||||
TrySteamApi("SteamMatchmaking.LeaveLobby", () => SteamMatchmaking.LeaveLobby(CurrentLobby));
|
||||
GameNetSender.Instance.ClearLobbyDataSyncState();
|
||||
ResetLobbyState();
|
||||
OnLobbyLeftEvent?.Invoke(null);
|
||||
@ -568,14 +718,15 @@ namespace TH1_Logic.Steam
|
||||
|
||||
LogSystem.LogInfo("Disbanding lobby");
|
||||
// 设置房间数据标记解散
|
||||
SteamMatchmaking.SetLobbyData(CurrentLobby, "disbanded", "true");
|
||||
TrySteamApi("SteamMatchmaking.SetLobbyData.disbanded", () => SteamMatchmaking.SetLobbyData(CurrentLobby, "disbanded", "true"));
|
||||
// 踢出所有其他成员
|
||||
foreach (var member in EnumerateMembers())
|
||||
{
|
||||
if (member != SteamUser.GetSteamID())
|
||||
if (!TrySteamApi("DisbandLobby.GetSteamID", SteamUser.GetSteamID, out var selfId)) break;
|
||||
if (member != selfId)
|
||||
{
|
||||
// Steam没有直接踢人API,通过设置数据让客户端自动离开
|
||||
SteamMatchmaking.SetLobbyMemberData(CurrentLobby, "kicked", "true");
|
||||
TrySteamApi("SteamMatchmaking.SetLobbyMemberData.kicked", () => SteamMatchmaking.SetLobbyMemberData(CurrentLobby, "kicked", "true"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -593,7 +744,8 @@ namespace TH1_Logic.Steam
|
||||
return;
|
||||
}
|
||||
|
||||
if (memberId == SteamUser.GetSteamID().m_SteamID)
|
||||
if (!TrySteamApi("KickMember.GetSteamID", SteamUser.GetSteamID, out var selfIdForKick)) return;
|
||||
if (memberId == selfIdForKick.m_SteamID)
|
||||
{
|
||||
LogSystem.LogError("Cannot kick yourself");
|
||||
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.LobbyOperationFailed);
|
||||
@ -605,7 +757,7 @@ namespace TH1_Logic.Steam
|
||||
// 房主写 LobbyData(只有房主有权限设 LobbyData),所有客户端都能 GetLobbyData 读到
|
||||
// 之前用的是 SetLobbyMemberData,那个 API 只能设自己的成员数据,写出去对方根本读不到 —— 协议不匹配
|
||||
// 被踢方在 RefreshKickInfo → CheckIfKicked 里读 kick_{selfId},发现是 "true" 就自动 LeaveLobby
|
||||
SteamMatchmaking.SetLobbyData(CurrentLobby, $"kick_{memberId}", "true");
|
||||
TrySteamApi("SteamMatchmaking.SetLobbyData.kick", () => SteamMatchmaking.SetLobbyData(CurrentLobby, $"kick_{memberId}", "true"));
|
||||
}
|
||||
|
||||
// 通过房间ID直接加入(无需好友关系)
|
||||
@ -654,7 +806,7 @@ namespace TH1_Logic.Steam
|
||||
if (!LobbyIsPublic(lobbyId)) return true;
|
||||
if (!LobbyHasPassword(lobbyId)) return true;
|
||||
|
||||
var expectedPassword = SteamMatchmaking.GetLobbyData(lobbyId, LobbyPasswordKey);
|
||||
if (!TrySteamApi("ValidateLobbyPasswordForJoin.GetLobbyData", () => SteamMatchmaking.GetLobbyData(lobbyId, LobbyPasswordKey), out var expectedPassword)) return false;
|
||||
if (!string.IsNullOrEmpty(expectedPassword) && (password ?? "") == expectedPassword) return true;
|
||||
|
||||
var errorMsg = string.IsNullOrEmpty(expectedPassword)
|
||||
@ -669,11 +821,16 @@ namespace TH1_Logic.Steam
|
||||
private bool ShouldRequestLobbyDataBeforeJoin(CSteamID lobbyId)
|
||||
{
|
||||
if (!lobbyId.IsValid()) return false;
|
||||
if (!string.IsNullOrEmpty(SteamMatchmaking.GetLobbyData(lobbyId, "Game"))) return false;
|
||||
if (!string.IsNullOrEmpty(SteamMatchmaking.GetLobbyData(lobbyId, "Version"))) return false;
|
||||
if (!string.IsNullOrEmpty(SteamMatchmaking.GetLobbyData(lobbyId, LobbyHasPasswordKey))) return false;
|
||||
if (!string.IsNullOrEmpty(SteamMatchmaking.GetLobbyData(lobbyId, LobbyPasswordKey))) return false;
|
||||
if (!string.IsNullOrEmpty(SteamMatchmaking.GetLobbyData(lobbyId, LobbyIsPublicKey))) return false;
|
||||
if (!TrySteamApi("ShouldRequestLobbyDataBeforeJoin.Game", () => SteamMatchmaking.GetLobbyData(lobbyId, "Game"), out var game)) return false;
|
||||
if (!TrySteamApi("ShouldRequestLobbyDataBeforeJoin.Version", () => SteamMatchmaking.GetLobbyData(lobbyId, "Version"), out var version)) return false;
|
||||
if (!TrySteamApi("ShouldRequestLobbyDataBeforeJoin.HasPassword", () => SteamMatchmaking.GetLobbyData(lobbyId, LobbyHasPasswordKey), out var hasPassword)) return false;
|
||||
if (!TrySteamApi("ShouldRequestLobbyDataBeforeJoin.Password", () => SteamMatchmaking.GetLobbyData(lobbyId, LobbyPasswordKey), out var lobbyPassword)) return false;
|
||||
if (!TrySteamApi("ShouldRequestLobbyDataBeforeJoin.IsPublic", () => SteamMatchmaking.GetLobbyData(lobbyId, LobbyIsPublicKey), out var isPublic)) return false;
|
||||
if (!string.IsNullOrEmpty(game)) return false;
|
||||
if (!string.IsNullOrEmpty(version)) return false;
|
||||
if (!string.IsNullOrEmpty(hasPassword)) return false;
|
||||
if (!string.IsNullOrEmpty(lobbyPassword)) return false;
|
||||
if (!string.IsNullOrEmpty(isPublic)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -686,15 +843,16 @@ namespace TH1_Logic.Steam
|
||||
|
||||
private bool LobbyHasPassword(CSteamID lobbyId)
|
||||
{
|
||||
var hasPasswordData = SteamMatchmaking.GetLobbyData(lobbyId, LobbyHasPasswordKey);
|
||||
if (!TrySteamApi("LobbyHasPassword.HasPassword", () => SteamMatchmaking.GetLobbyData(lobbyId, LobbyHasPasswordKey), out var hasPasswordData)) return false;
|
||||
if (IsTrueLobbyData(hasPasswordData)) return true;
|
||||
if (IsFalseLobbyData(hasPasswordData)) return false;
|
||||
return !string.IsNullOrEmpty(SteamMatchmaking.GetLobbyData(lobbyId, LobbyPasswordKey));
|
||||
return TrySteamApi("LobbyHasPassword.Password", () => SteamMatchmaking.GetLobbyData(lobbyId, LobbyPasswordKey), out var passwordData)
|
||||
&& !string.IsNullOrEmpty(passwordData);
|
||||
}
|
||||
|
||||
private bool LobbyIsPublic(CSteamID lobbyId)
|
||||
{
|
||||
var isPublicData = SteamMatchmaking.GetLobbyData(lobbyId, LobbyIsPublicKey);
|
||||
if (!TrySteamApi("LobbyIsPublic.IsPublic", () => SteamMatchmaking.GetLobbyData(lobbyId, LobbyIsPublicKey), out var isPublicData)) return true;
|
||||
if (IsTrueLobbyData(isPublicData)) return true;
|
||||
if (IsFalseLobbyData(isPublicData)) return false;
|
||||
return true;
|
||||
@ -739,7 +897,8 @@ namespace TH1_Logic.Steam
|
||||
public string GenerateUserCode()
|
||||
{
|
||||
if (!_isSteamInitialized || !_isLoggedIn) return null;
|
||||
return Base36Encode(SteamUser.GetSteamID().m_SteamID);
|
||||
var selfMemberId = GetSelfMemberId();
|
||||
return selfMemberId == 0 ? null : Base36Encode(selfMemberId);
|
||||
}
|
||||
|
||||
public void InviteByRawSteamId(string code)
|
||||
@ -996,17 +1155,18 @@ namespace TH1_Logic.Steam
|
||||
public List<(CSteamID id, string name)> GetOnlineFriends()
|
||||
{
|
||||
var list = new List<(CSteamID, string)>();
|
||||
int count = SteamFriends.GetFriendCount(EFriendFlags.k_EFriendFlagImmediate);
|
||||
if (!TrySteamApi("GetOnlineFriends.GetFriendCount", () => SteamFriends.GetFriendCount(EFriendFlags.k_EFriendFlagImmediate), out var count)) return list;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var fid = SteamFriends.GetFriendByIndex(i, EFriendFlags.k_EFriendFlagImmediate);
|
||||
var state = SteamFriends.GetFriendPersonaState(fid);
|
||||
if (!TrySteamApi("GetOnlineFriends.GetFriendByIndex", () => SteamFriends.GetFriendByIndex(i, EFriendFlags.k_EFriendFlagImmediate), out var fid)) return list;
|
||||
if (!TrySteamApi("GetOnlineFriends.GetFriendPersonaState", () => SteamFriends.GetFriendPersonaState(fid), out var state)) return list;
|
||||
if (state == EPersonaState.k_EPersonaStateOnline ||
|
||||
state == EPersonaState.k_EPersonaStateAway ||
|
||||
state == EPersonaState.k_EPersonaStateBusy ||
|
||||
state == EPersonaState.k_EPersonaStateSnooze)
|
||||
{
|
||||
list.Add((fid, SteamFriends.GetFriendPersonaName(fid)));
|
||||
if (!TrySteamApi("GetOnlineFriends.GetFriendPersonaName", () => SteamFriends.GetFriendPersonaName(fid), out var friendName)) return list;
|
||||
list.Add((fid, friendName));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
@ -1061,7 +1221,11 @@ namespace TH1_Logic.Steam
|
||||
}
|
||||
|
||||
CurrentLobby = new CSteamID(data.m_ulSteamIDLobby);
|
||||
CachedOwner = SteamUser.GetSteamID();
|
||||
if (!TrySteamApi("OnLobbyCreatedCallback.GetSteamID", SteamUser.GetSteamID, out CachedOwner))
|
||||
{
|
||||
ResetLobbyState();
|
||||
return;
|
||||
}
|
||||
|
||||
LogSystem.LogInfo($"Lobby created successfully: {CurrentLobby}");
|
||||
|
||||
@ -1247,7 +1411,7 @@ namespace TH1_Logic.Steam
|
||||
// 房主切换时内部处理
|
||||
private void OnHostChangedInternal(CSteamID oldOwner, CSteamID newOwner)
|
||||
{
|
||||
if (oldOwner == SteamUser.GetSteamID())
|
||||
if (oldOwner.m_SteamID == GetSelfMemberId())
|
||||
{
|
||||
LogSystem.LogWarning($"Local host ownership changed to {newOwner}, waiting local disconnect handling");
|
||||
return;
|
||||
@ -1287,8 +1451,9 @@ namespace TH1_Logic.Steam
|
||||
// 检查是否被踢
|
||||
private void CheckIfKicked()
|
||||
{
|
||||
var kickData = SteamMatchmaking.GetLobbyMemberData(CurrentLobby, SteamUser.GetSteamID(), "kicked");
|
||||
var specificKick = SteamMatchmaking.GetLobbyData(CurrentLobby, $"kick_{SteamUser.GetSteamID().m_SteamID}");
|
||||
if (!TrySteamApi("CheckIfKicked.GetSteamID", SteamUser.GetSteamID, out var selfId)) return;
|
||||
if (!TrySteamApi("CheckIfKicked.GetLobbyMemberData", () => SteamMatchmaking.GetLobbyMemberData(CurrentLobby, selfId, "kicked"), out var kickData)) return;
|
||||
if (!TrySteamApi("CheckIfKicked.GetLobbyData", () => SteamMatchmaking.GetLobbyData(CurrentLobby, $"kick_{selfId.m_SteamID}"), out var specificKick)) return;
|
||||
|
||||
if (kickData == "true" || specificKick == "true")
|
||||
{
|
||||
@ -1464,9 +1629,12 @@ namespace TH1_Logic.Steam
|
||||
private IEnumerable<CSteamID> EnumerateMembers()
|
||||
{
|
||||
if (!CurrentLobby.IsValid()) yield break;
|
||||
int count = SteamMatchmaking.GetNumLobbyMembers(CurrentLobby);
|
||||
if (!TrySteamApi("EnumerateMembers.GetNumLobbyMembers", () => SteamMatchmaking.GetNumLobbyMembers(CurrentLobby), out var count)) yield break;
|
||||
for (int i = 0; i < count; i++)
|
||||
yield return SteamMatchmaking.GetLobbyMemberByIndex(CurrentLobby, i);
|
||||
{
|
||||
if (!TrySteamApi("EnumerateMembers.GetLobbyMemberByIndex", () => SteamMatchmaking.GetLobbyMemberByIndex(CurrentLobby, i), out var member)) yield break;
|
||||
yield return member;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取房间所有成员
|
||||
@ -1480,14 +1648,15 @@ namespace TH1_Logic.Steam
|
||||
{
|
||||
if (!CurrentLobby.IsValid()) return;
|
||||
_memberInfos.Clear();
|
||||
int count = SteamMatchmaking.GetNumLobbyMembers(CurrentLobby);
|
||||
if (!TrySteamApi("UpdateMemberInfo.GetNumLobbyMembers", () => SteamMatchmaking.GetNumLobbyMembers(CurrentLobby), out var count)) return;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var cSteamId = SteamMatchmaking.GetLobbyMemberByIndex(CurrentLobby, i);
|
||||
if (!TrySteamApi("UpdateMemberInfo.GetLobbyMemberByIndex", () => SteamMatchmaking.GetLobbyMemberByIndex(CurrentLobby, i), out var cSteamId)) return;
|
||||
if (!_membersCache.ContainsKey(cSteamId.m_SteamID)) _membersCache[cSteamId.m_SteamID] = cSteamId;
|
||||
_memberInfos[cSteamId.m_SteamID] = new MemberInfo();
|
||||
_memberInfos[cSteamId.m_SteamID].Id = cSteamId.m_SteamID;
|
||||
_memberInfos[cSteamId.m_SteamID].Name = SteamFriends.GetFriendPersonaName(cSteamId);
|
||||
if (!TrySteamApi("UpdateMemberInfo.GetFriendPersonaName", () => SteamFriends.GetFriendPersonaName(cSteamId), out var memberName)) return;
|
||||
_memberInfos[cSteamId.m_SteamID].Name = memberName;
|
||||
_memberInfos[cSteamId.m_SteamID].Texture = GetMemberAvatar(cSteamId.m_SteamID);
|
||||
}
|
||||
}
|
||||
@ -1548,7 +1717,7 @@ namespace TH1_Logic.Steam
|
||||
public int GetMemberCount()
|
||||
{
|
||||
if (!CurrentLobby.IsValid()) return 0;
|
||||
return SteamMatchmaking.GetNumLobbyMembers(CurrentLobby);
|
||||
return TrySteamApi("GetMemberCount.GetNumLobbyMembers", () => SteamMatchmaking.GetNumLobbyMembers(CurrentLobby), out var count) ? count : 0;
|
||||
}
|
||||
|
||||
// 获取最大成员数
|
||||
@ -1609,10 +1778,10 @@ namespace TH1_Logic.Steam
|
||||
public bool IsMemberInLobby(ulong memberId)
|
||||
{
|
||||
if (!CurrentLobby.IsValid()) return false;
|
||||
int count = SteamMatchmaking.GetNumLobbyMembers(CurrentLobby);
|
||||
if (!TrySteamApi("IsMemberInLobby.GetNumLobbyMembers", () => SteamMatchmaking.GetNumLobbyMembers(CurrentLobby), out var count)) return false;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var cSteamId = SteamMatchmaking.GetLobbyMemberByIndex(CurrentLobby, i);
|
||||
if (!TrySteamApi("IsMemberInLobby.GetLobbyMemberByIndex", () => SteamMatchmaking.GetLobbyMemberByIndex(CurrentLobby, i), out var cSteamId)) return false;
|
||||
if (cSteamId.m_SteamID == memberId) return true;
|
||||
}
|
||||
return false;
|
||||
@ -1628,15 +1797,15 @@ namespace TH1_Logic.Steam
|
||||
// 获取自己的 memberId
|
||||
public ulong GetSelfMemberId()
|
||||
{
|
||||
return SteamUser.GetSteamID().m_SteamID;
|
||||
if (_selfID.IsValid()) return _selfID.m_SteamID;
|
||||
return TrySteamApi("GetSelfMemberId.GetSteamID", SteamUser.GetSteamID, out var selfId) ? selfId.m_SteamID : 0;
|
||||
}
|
||||
|
||||
// 获取房主的 memberId
|
||||
public ulong GetLobbyOwnerId()
|
||||
{
|
||||
if (!CurrentLobby.IsValid()) return 0;
|
||||
var owner = SteamMatchmaking.GetLobbyOwner(CurrentLobby);
|
||||
return owner.m_SteamID;
|
||||
return TrySteamApi("GetLobbyOwnerId.GetLobbyOwner", () => SteamMatchmaking.GetLobbyOwner(CurrentLobby), out var owner) ? owner.m_SteamID : 0;
|
||||
}
|
||||
|
||||
// 获取当前房间状态
|
||||
@ -1648,13 +1817,16 @@ namespace TH1_Logic.Steam
|
||||
// 自己是否是房主
|
||||
public bool IsLobbyOwner()
|
||||
{
|
||||
return IsInLobby() && SteamMatchmaking.GetLobbyOwner(CurrentLobby) == SteamUser.GetSteamID();
|
||||
if (!IsInLobby()) return false;
|
||||
if (!TrySteamApi("IsLobbyOwner.GetLobbyOwner", () => SteamMatchmaking.GetLobbyOwner(CurrentLobby), out var owner)) return false;
|
||||
if (!TrySteamApi("IsLobbyOwner.GetSteamID", SteamUser.GetSteamID, out var selfId)) return false;
|
||||
return owner == selfId;
|
||||
}
|
||||
|
||||
// 自己是否在房间中
|
||||
public bool IsInLobby()
|
||||
{
|
||||
return IsInitialized() && CurrentState == LobbyState.InLobby && CurrentLobby.IsValid();
|
||||
return !_steamApiUnavailable && IsInitialized() && CurrentState == LobbyState.InLobby && CurrentLobby.IsValid();
|
||||
}
|
||||
|
||||
// 获取自己的当前Steam在线状态 (如: 在线, 忙碌, 离开, 隐身, 离线)
|
||||
|
||||
@ -323,6 +323,8 @@ namespace Logic
|
||||
attackDmg = 0;
|
||||
counterDmg = 0;
|
||||
fragmentType = FragmentType.Attack;
|
||||
if (mapData == null || unit1 == null || unit2 == null) return;
|
||||
if (!unit1.IsValidOnMap(mapData) || !unit2.IsValidOnMap(mapData)) return;
|
||||
if (!mapData.GetPlayerDataByUnitId(unit1.Id, out var player1)) return;
|
||||
if (!mapData.GetPlayerDataByUnitId(unit2.Id, out var player2)) return;
|
||||
if (!mapData.GetGridDataByUnitId(unit1.Id, out var grid1)) return;
|
||||
@ -350,6 +352,14 @@ namespace Logic
|
||||
|
||||
// 攻击前生命周期
|
||||
unit1.BeforeActiveAttackOther(mapData, unit1, unit2, out var tmpAddDmg);
|
||||
if (!unit1.IsValidOnMap(mapData) || !unit2.IsValidOnMap(mapData)) return;
|
||||
if (!mapData.GetPlayerDataByUnitId(unit1.Id, out player1)) return;
|
||||
if (!mapData.GetPlayerDataByUnitId(unit2.Id, out player2)) return;
|
||||
if (!mapData.GetGridDataByUnitId(unit1.Id, out grid1)) return;
|
||||
if (!mapData.GetGridDataByUnitId(unit2.Id, out grid2)) return;
|
||||
attackInfo.OriginPlayer = player1;
|
||||
attackInfo.DamageOriginGrid = grid1;
|
||||
attackInfo.DamageTargetGrid = grid2;
|
||||
|
||||
var attackDistance = Table.Instance.CalcDistance(grid1, grid2);
|
||||
// 计算攻击伤害
|
||||
@ -364,7 +374,8 @@ namespace Logic
|
||||
//攻击会消耗所有类别的行动点数
|
||||
unit1.ClearActionPoint();
|
||||
|
||||
Main.UnitLogic.DamageSettlement(mapData, unit1, unit2, dmg1, DamageType.ActiveAttack);
|
||||
var activeSettlement = Main.UnitLogic.DamageSettlement(mapData, unit1, unit2, dmg1, DamageType.ActiveAttack);
|
||||
if (activeSettlement == null) return;
|
||||
if (!unit2.IsAlive())
|
||||
{
|
||||
attackInfo.IsKill = true;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user