This commit is contained in:
kawagiri 2025-09-23 18:40:56 +08:00
commit 38175b9004
31 changed files with 1207 additions and 420 deletions

View File

@ -998,6 +998,9 @@ namespace RuntimeData
[MemoryPackOnDeserialized]
public void OnAfterMemoryPackDeserialize()
{
// 重绑定 ID
Net.RefreshPlayerNet(this);
// 重建缓存字典
_gridToCityDict ??= new Dictionary<uint, uint>();
_gridToUnitDict ??= new Dictionary<uint, uint>();
@ -1188,6 +1191,23 @@ namespace RuntimeData
return (uint)realLv;
}
// 获取下一位执行玩家
public PlayerData GetNextPlayer(MapData map)
{
if (map.PlayerMap.PlayerDataList.Count == 0)
{
LogSystem.LogError($"UpdateNextPlayer Error : PlayerDataList Count = 0!!!");
return null;
}
var curTurn = map.PlayerMap.PlayerDataList[0].Turn;
foreach (var player in map.PlayerMap.PlayerDataList)
{
if (player.Turn >= curTurn) continue;
return player;
}
return map.PlayerMap.PlayerDataList[0];
}
}

View File

@ -10,6 +10,7 @@ using System.Collections.Generic;
using Logic.AI;
using MemoryPack;
using Steamworks;
using TH1_Logic.Net;
using TH1_Logic.Steam;
using UnityEngine;
@ -22,8 +23,8 @@ namespace RuntimeData
{
// 地图哈希
public string MapHash;
// PlayerId => SteamId 的索引
public Dictionary<uint, ulong> Players;
// SteamId => PlayerId 的索引
public Dictionary<ulong, uint> Players;
// 所有玩家行为的序列
public List<ActionNetData> Actions;
// 随机数种子 开始游戏时由房主进行初始化,整局游戏不可变
@ -33,7 +34,7 @@ namespace RuntimeData
[MemoryPackConstructor]
public NetData()
{
Players = new Dictionary<uint, ulong>();
Players = new Dictionary<ulong, uint>();
Actions = new List<ActionNetData>();
// 生成确定性种子(由房主生成并广播)
RandomSeed = System.Environment.TickCount;
@ -44,7 +45,7 @@ namespace RuntimeData
{
MapHash = copyData.MapHash;
RandomSeed = copyData.RandomSeed;
Players = new Dictionary<uint, ulong>();
Players = new Dictionary<ulong, uint>();
Actions = new List<ActionNetData>();
}
@ -53,7 +54,7 @@ namespace RuntimeData
{
MapHash = copyData.MapHash;
RandomSeed = copyData.RandomSeed;
Players = new Dictionary<uint, ulong>();
Players = new Dictionary<ulong, uint>();
Actions = new List<ActionNetData>();
}
@ -64,27 +65,31 @@ namespace RuntimeData
return _random;
}
public void RefreshMapNet(MapData mapData)
public void RefreshPlayerNet(MapData mapData)
{
if (!SteamLobbyManager.Instance.IsLobbyOwner) return;
// 地图初始哈希
MapHash = GetMapDataHash(mapData);
// 添加自己
if (!Players.ContainsKey(mapData.PlayerMap.SelfPlayerId))
if (LobbyManager.Instance.Lobby.IsLobbyOwner())
{
Players[mapData.PlayerMap.SelfPlayerId] = SteamUser.GetSteamID().m_SteamID;
}
// 添加其他人
foreach (var cSteamID in SteamLobbyManager.Instance.EnumerateMembers())
{
if (Players.ContainsValue(cSteamID.m_SteamID)) continue;
foreach (var player in mapData.PlayerMap.PlayerDataList)
// 添加其他人
foreach (var memberId in LobbyManager.Instance.Lobby.GetAllMemberIds())
{
if (player.Id == mapData.PlayerMap.SelfPlayerId) continue;
if (Players.ContainsKey(player.Id)) return;
Players[player.Id] = cSteamID.m_SteamID;
if (Players.ContainsKey(memberId)) continue;
foreach (var player in mapData.PlayerMap.PlayerDataList)
{
if (Players.ContainsValue(player.Id)) return;
Players[memberId] = player.Id;
}
}
}
var selfMemberId = LobbyManager.Instance.Lobby.GetSelfMemberId();
if (Players.TryGetValue(selfMemberId, out var id))
mapData.PlayerMap.SelfPlayerId = id;
}
public void RefreshMapNet(MapData mapData)
{
// 地图哈希
MapHash = GetMapDataHash(mapData);
}
public uint GetActionVersion()
@ -93,6 +98,15 @@ namespace RuntimeData
return Actions[^1].Version + 1;
}
public ulong GetSteamId(uint playerId)
{
foreach (var kv in Players)
{
if (kv.Value == playerId) return kv.Key;
}
return 0;
}
public static string GetMapDataHash(MapData mapData)
{
byte[] bytes = MemoryPackSerializer.Serialize(mapData);

View File

@ -91,6 +91,7 @@ namespace RuntimeData
[MemoryPackable]
public partial class PlayerMapData
{
[MemoryPackIgnore]
public uint SelfPlayerId;
public List<PlayerData> PlayerDataList;
@ -239,11 +240,13 @@ namespace RuntimeData
public void OnTurnStart(MapData map, PlayerData player)
{
Main.PlayerLogic.StartNextTurn(map, player);
player.OnTurnStart(map);
}
public void OnTurnEnd(MapData map, PlayerData player)
{
Main.PlayerLogic.EndThisTurn(map, player);
player.OnTurnEnd(map);
}
}

View File

@ -93,15 +93,23 @@ namespace RuntimeData
{
var units = new HashSet<UnitData>();
map.GetUnitDataListByPlayerId(player.Id, units);
foreach (var unit in units) unit.OnTurnStart(map);
foreach (var unit in units)
{
Main.UnitLogic.StartNextTurn(map, unit);
unit.OnTurnStart(map);
}
}
public void OnTurnEnd(MapData map, PlayerData player)
{
var units = new HashSet<UnitData>();
map.GetUnitDataListByPlayerId(player.Id, units);
foreach (var unit in units) unit.OnTurnEnd(map);
foreach (var unit in units)
{
Main.UnitLogic.UnitEndTurn(map, unit);
unit.OnTurnEnd(map);
}
}
// 新建小兵
@ -295,12 +303,10 @@ namespace RuntimeData
if (UnitType == UnitType.Giant)
return UnitLevel switch
{
0 => 8,
1 => 11,
2 => 13,
3 => 15,
4 => 20,
5 => 30,
0 => 10,
1 => 10,
2 => 15,
3 => 25,
_ => 0
};
//如果生命值低于50%,得分打8折

View File

@ -15,6 +15,8 @@ using MemoryPack;
using OPS.Obfuscator.Attribute;
using RuntimeData;
using TH1_Logic.Core;
using TH1_Logic.Net;
using TH1_Logic.Steam;
using UnityEngine;
using Vector2 = System.Numerics.Vector2;
@ -1900,15 +1902,27 @@ namespace Logic.AI
public void CheckIsActionInPlayerSight()
{
IsInSight = true;
var player = Param.MapData.PlayerMap.SelfPlayerData;
if (Param.MapData.GridMap.GetGridDataByGid(Param.GridId, out var grid)
&& player.Sight.CheckIsInSight(grid.Id)) return;
if (Param.MapData.GetGridDataByUnitId(Param.UnitId, out var unitGrid)
&& player.Sight.CheckIsInSight(unitGrid.Id)) return;
if (Param.MapData.GetGridDataByUnitId(Param.TargetUnitId, out var targetUnit)
&& player.Sight.CheckIsInSight(targetUnit.Id)) return;
if (Param.MapData.GetGridDataByCityId(Param.CityId, out var cityGrid)
&& player.Sight.CheckIsInSight(cityGrid.Id)) return;
var checkGridList = new List<GridData>();
if (Param.MapData.GridMap.GetGridDataByGid(Param.GridId, out var targetGrid)) checkGridList.Add(targetGrid);
if (Param.MapData.GetGridDataByUnitId(Param.UnitId, out var unitGrid) ) checkGridList.Add(unitGrid);
if (Param.MapData.GetGridDataByUnitId(Param.TargetUnitId, out var targetUnit)) checkGridList.Add(targetUnit);
if (Param.MapData.GetGridDataByCityId(Param.CityId, out var cityGrid)) checkGridList.Add(cityGrid);
if (LobbyManager.Instance.Lobby.IsInLobby())
{
foreach (var kv in Param.MapData.Net.Players)
{
if (!LobbyManager.Instance.Lobby.IsMemberInLobby(kv.Key)) continue;
var player = Param.MapData.PlayerMap.GetPlayerData(kv.Value);
if (player == null) continue;
foreach (var grid in checkGridList) if (player.Sight.CheckIsInSight(grid.Id)) return;
}
}
else
{
foreach (var grid in checkGridList)
if (Param.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(grid.Id)) return;
}
IsInSight = false;
}

View File

@ -96,6 +96,7 @@ namespace Logic.AI
// 结束 AI 逻辑
public void FinishAILogic()
{
AILogicState = AILogicState.Prepare;
RecordActions.Clear();
}
@ -202,23 +203,5 @@ namespace Logic.AI
// }
// }
}
// 获取 AI 执行权限
private bool GetAILogicPermission()
{
return true;
}
// 选取最高得分行动
private void CalculateMaxScoreAction()
{
if (RecordActions.Count == 0) return;
MaxScoreAction = _scoreCalculator.CalculateMaxScoreAIAction(_mapData, _playerData, RecordActions, _cfg);
if (MaxScoreAction != null && MaxScoreAction.ActionLogic.ActionId != null &&
MaxScoreAction.ActionLogic.ActionId.ActionType == CommonActionType.LearnTech)
{
Debug.LogWarning($"学习科技了!!!!! {MaxScoreAction.ActionLogic.ActionId.TechType}");
}
}
}
}

View File

@ -1314,8 +1314,7 @@ namespace Logic.Action
var distance = actionParams.MapData.GridMap.CalcDistance(unitGrid, actionParams.GridData);
}
Main.UnitLogic.MoveTo(actionParams.MapData, actionParams.UnitData, actionParams.GridData,
MoveType.ActiveMove);
Main.UnitLogic.MoveTo(actionParams.MapData, actionParams.UnitData, actionParams.GridData);
return true;
}

View File

@ -9,11 +9,11 @@
using System.Collections.Generic;
using Logic.AI;
using Logic.Audio;
using UnityEngine.PlayerLoop;
using RuntimeData;
using TH1_Core.Managers;
using TH1_Logic.Core;
using UI;
using TH1_Logic.Net;
using TH1_Logic.Steam;
using UnityEngine;
@ -25,6 +25,8 @@ namespace Logic
PlayerRound,
AIRound,
Finished,
MainMemberRound,
NetMemberRound,
}
@ -38,6 +40,7 @@ namespace Logic
//public MapData Map => _mapData;
public Main Main => _main;
public PlayerData CurPlayer => _gameStateDict[_curState].CurPlayer;
public GameStateBase CurState => _gameStateDict[_curState];
public GameLogic(Main main)//, MapData mapData)
@ -49,6 +52,8 @@ namespace Logic
_gameStateDict.Add(GameState.AIRound, new AIRoundState(this));
_gameStateDict.Add(GameState.Menu, new MenuState(this));
_gameStateDict.Add(GameState.Finished, new FinishState(this));
_gameStateDict.Add(GameState.MainMemberRound, new MainMemberRoundState(this));
_gameStateDict.Add(GameState.NetMemberRound, new NetMemberRoundState(this));
_curState = GameState.Menu;
_gameStateDict[_curState].Enter();
}
@ -59,7 +64,6 @@ namespace Logic
Main.PlayerLogic.CalcAllPlayerScore(Main.MapData);
}
public void ChangeState(GameState newState)
{
if (_curState == newState) return;
@ -72,15 +76,35 @@ namespace Logic
{
return _curState;
}
public void ChangeToNextPlayerRound()
{
var player = Main.MapData.GetNextPlayer(Main.MapData);
if (player.Id == Main.MapData.PlayerMap.SelfPlayerId)
{
ChangeState(GameState.PlayerRound);
}
else
{
// 无房间或者是房主
if (!LobbyManager.Instance.Lobby.IsInLobby() || LobbyManager.Instance.Lobby.IsLobbyOwner())
{
ChangeState(GameState.MainMemberRound);
}
else
{
ChangeState(GameState.NetMemberRound);
}
_gameStateDict[_curState].ChangePlayer(player.Id);
}
}
}
public abstract class GameStateBase
{
public int Turn;
protected GameLogic _gameLogic;
protected PlayerData _curPlayer;
public PlayerData CurPlayer => _curPlayer;
@ -93,9 +117,10 @@ namespace Logic
public abstract void Enter();
public abstract void End();
public abstract void Update();
public virtual void ChangePlayer(uint playerId) { }
}
public class PlayerRoundState : GameStateBase
{
private AILogic _aiLogic;
@ -110,23 +135,15 @@ namespace Logic
public override void Enter()
{
MapData.SaveMapData(Main.MapData);
_curPlayer = Main.MapData.PlayerMap.SelfPlayerData;
Turn++;
foreach(var playerData in Main.MapData.PlayerMap.PlayerDataList)
Main.PlayerLogic.StartNextTurn(Main.MapData, playerData);
foreach (var unitData in Main.MapData.UnitMap.UnitList)
Main.UnitLogic.StartNextTurn(Main.MapData, unitData);
_curPlayer = Main.MapData.PlayerMap.SelfPlayerData;
Main.MapData.PlayerMap.OnTurnStart(Main.MapData, _curPlayer);
Main.MapData.CityMap.OnTurnStart(Main.MapData, _curPlayer);
Main.MapData.UnitMap.OnTurnStart(Main.MapData, _curPlayer);
Main.MapData.GridMap.OnTurnStart(Main.MapData);
AudioManager.Instance.InGameOnTurnStart();
UIManager.Instance.EndTurn();
_gameLogic.Main.InputLogic.UnlockInput();
UIManager.Instance.AIPlaying = false;
@ -136,26 +153,21 @@ namespace Logic
PlayerPrefs.Save();
AchievementDataManager.Instance.OnTurnStart(Main.MapData, _curPlayer);
// 判断是否为房主
if (LobbyManager.Instance.Lobby.IsLobbyOwner())
{
GameNetSender.Instance.TurnChange(Main.Instance.GameLogic.CurPlayer.Id);
}
#if GAME_AUTO_DEBUG
_aiLogic = new AILogic();
#endif
}
//玩家结束时出发的End
public override void End()
{
_gameLogic.Main.InputLogic.LockInput();
// TODO endturn逻辑要重新梳理
Main.PlayerLogic.EndThisTurn(Main.MapData, Main.MapData.PlayerMap.SelfPlayerData);
//处理当前每一个unit的回合结束前自动行为。每一个选手回合结束自动回血是在这个阶段出发的
foreach (var unitData in Main.MapData.UnitMap.UnitList)
if(Main.MapData.GetPlayerDataByUnitId(unitData.Id,out var player)
&& player.Id == _curPlayer.Id)
Main.UnitLogic.UnitEndTurn(Main.MapData, unitData);
Main.MapData.PlayerMap.OnTurnEnd(Main.MapData, _curPlayer);
Main.MapData.CityMap.OnTurnEnd(Main.MapData, _curPlayer);
Main.MapData.UnitMap.OnTurnEnd(Main.MapData, _curPlayer);
@ -204,7 +216,6 @@ namespace Logic
public override void Enter()
{
UIManager.Instance.AIPlayingHint.SetActive(true);
Turn++;
_aiPlayers.Clear();
foreach (var playerData in Main.MapData.PlayerMap.PlayerDataList)
{
@ -272,6 +283,193 @@ namespace Logic
}
// 房主客户端上的其他玩家
public class MainMemberRoundState : GameStateBase
{
private AILogic _aiLogic;
private float _startTime;
private float _durationLimit;
public MainMemberRoundState(GameLogic gameLogic) : base(gameLogic)
{
_aiLogic = new AILogic();
_durationLimit = 60;
}
public override GameState State => GameState.MainMemberRound;
public override void Enter()
{
UIManager.Instance.AIPlayingHint.SetActive(true);
MainEditor.Instance.OnAIStarted();
Update();
}
public override void End()
{
TryTurnEndCurPlayerTurn();
}
public override void Update()
{
AutoRefreshNextPlayer();
// 判断是 AI 还是玩家
if (_curPlayer != null && Main.MapData.Net.Players.TryGetValue(_curPlayer.Id, out var memberId))
{
if (LobbyManager.Instance.Lobby.IsMemberInLobby(memberId)) return;
}
// 当 Player 是 AI 或者 Player 掉线时,均执行 AI 行为
if (_aiLogic.AILogicState == AILogicState.Prepare)
{
// AI 难度加钱
int tt = 0;
if (_curPlayer.Turn < 10) tt = (int)Main.MapData.MapConfig.AIDiff;
_curPlayer.PlayerWealth += ((int)_curPlayer.Turn / 5) * (int)Main.MapData.MapConfig.AIDiff + tt;
_aiLogic.StartAILogic(Main.MapData, _curPlayer);
}
_aiLogic.Update();
// AI 行为执行完毕
if (_aiLogic.AILogicState == AILogicState.Finished)
{
TryTurnEndCurPlayerTurn();
AutoRefreshNextPlayer();
}
}
private void AutoRefreshNextPlayer()
{
// 操作超时切换
if (_curPlayer != null && Time.time - _startTime > _durationLimit)
{
TryTurnEndCurPlayerTurn();
}
// 自动分配下一位玩家
if (_curPlayer == null)
{
var player = Main.MapData.GetNextPlayer(Main.MapData);
if (player == null) return;
if (player.Id == Main.MapData.PlayerMap.SelfPlayerId)
{
_gameLogic.ChangeState(GameState.PlayerRound);
return;
}
_curPlayer = player;
TryTurnStartCurPlayerTurn();
}
}
public override void ChangePlayer(uint playerId)
{
if (_curPlayer != null && _curPlayer.Id != playerId) return;
TryTurnEndCurPlayerTurn();
if (playerId == Main.MapData.PlayerMap.SelfPlayerId)
{
_gameLogic.ChangeState(GameState.PlayerRound);
return;
}
var player = Main.MapData.PlayerMap.GetPlayerData(playerId);
if (player != null) _curPlayer = player;
TryTurnStartCurPlayerTurn();
}
private void TryTurnStartCurPlayerTurn()
{
if (_curPlayer == null) return;
Main.MapData.PlayerMap.OnTurnStart(Main.MapData, _curPlayer);
Main.MapData.CityMap.OnTurnStart(Main.MapData, _curPlayer);
Main.MapData.UnitMap.OnTurnStart(Main.MapData, _curPlayer);
Main.MapData.GridMap.OnTurnStart(Main.MapData);
_startTime = Time.time;
// 判断是否为房主
if (LobbyManager.Instance.Lobby.IsLobbyOwner())
{
GameNetSender.Instance.TurnChange(_curPlayer.Id);
}
}
private void TryTurnEndCurPlayerTurn()
{
if (_curPlayer == null) return;
Main.MapData.PlayerMap.OnTurnEnd(Main.MapData, _curPlayer);
Main.MapData.CityMap.OnTurnEnd(Main.MapData, _curPlayer);
Main.MapData.UnitMap.OnTurnEnd(Main.MapData, _curPlayer);
Main.MapData.GridMap.OnTurnEnd(Main.MapData);
_curPlayer = null;
_aiLogic.FinishAILogic();
}
}
// 成员客户端上的其他玩家
public class NetMemberRoundState : GameStateBase
{
public NetMemberRoundState(GameLogic gameLogic) : base(gameLogic)
{
}
public override GameState State => GameState.NetMemberRound;
public override void Enter()
{
UIManager.Instance.AIPlayingHint.SetActive(true);
}
public override void End()
{
TryTurnEndCurPlayerTurn();
}
public override void Update()
{
}
public override void ChangePlayer(uint playerId)
{
if (_curPlayer != null && _curPlayer.Id != playerId) return;
TryTurnEndCurPlayerTurn();
if (playerId == Main.MapData.PlayerMap.SelfPlayerId)
{
_gameLogic.ChangeState(GameState.PlayerRound);
return;
}
var player = Main.MapData.PlayerMap.GetPlayerData(playerId);
if (player != null) _curPlayer = player;
TryTurnStartCurPlayerTurn();
}
private void TryTurnStartCurPlayerTurn()
{
if (_curPlayer == null) return;
Main.MapData.PlayerMap.OnTurnStart(Main.MapData, _curPlayer);
Main.MapData.CityMap.OnTurnStart(Main.MapData, _curPlayer);
Main.MapData.UnitMap.OnTurnStart(Main.MapData, _curPlayer);
Main.MapData.GridMap.OnTurnStart(Main.MapData);
}
private void TryTurnEndCurPlayerTurn()
{
if (_curPlayer == null) return;
Main.MapData.PlayerMap.OnTurnEnd(Main.MapData, _curPlayer);
Main.MapData.CityMap.OnTurnEnd(Main.MapData, _curPlayer);
Main.MapData.UnitMap.OnTurnEnd(Main.MapData, _curPlayer);
Main.MapData.GridMap.OnTurnEnd(Main.MapData);
_curPlayer = null;
}
}
public class MenuState : GameStateBase
{
public MenuState(GameLogic gameLogic) : base(gameLogic)
@ -283,7 +481,7 @@ namespace Logic
public override void Enter()
{
Turn++;
}
public override void End()
@ -309,7 +507,6 @@ namespace Logic
public override void Enter()
{
Turn++;
PlayerPrefs.SetInt("Archive", 0);
var record = Main.MapData.ExportGameRecord();

View File

@ -18,11 +18,13 @@ using RuntimeData;
using TH1_Core.Events;
using TH1_Core.Managers;
using TH1_Logic.HeroTask;
using TH1_Logic.Net;
using TH1_Logic.Steam;
using TH1Renderer;
using TH1Resource;
using UnityEngine;
namespace TH1_Logic.Core
{
public class Main : MonoBehaviour
@ -38,7 +40,6 @@ namespace TH1_Logic.Core
public float AnimationSpeed = 1f;
public bool DebugMode = false;
public bool DebugHideCenterMessage = false;
public bool SteamTest = false;
[Header("Play Settings")]
public int cityCount;
@ -109,6 +110,8 @@ namespace TH1_Logic.Core
new UIManager(); //UIManager单例
UIManager.Instance.Init(this);
LobbyManager.Instance.Init();
TH1SteamManager.Instance.Init();
}
void Start()
@ -136,22 +139,6 @@ namespace TH1_Logic.Core
//step #7 更新成就的情况
AchievementDataManager.Instance.ReCheckAchievementDataNotComplete();
#if UNITY_EDITOR
if (SteamTest)
{
var obj = this.transform.Find("SteamTest");
if (!obj)
{
obj = new GameObject("SteamTest").transform;
obj.parent = this.transform;
}
var com = obj.GetComponent<SteamTestManager>();
if (!com) com = obj.gameObject.AddComponent<SteamTestManager>();
}
#endif
}
@ -182,14 +169,11 @@ namespace TH1_Logic.Core
&& MapData.GetGridDataByCityId(cap.Id, out var grid))
camera.CameraFocusOnGrid(grid,true);
GameLogic.ChangeState(GameState.PlayerRound);
GameLogic.ChangeToNextPlayerRound();
}
public void StartGame(uint h, uint w,uint playerCount, uint civId, uint forceId, AIDifficult diff)
{
//停止音乐然后为这句游戏初始化一个AudioManager的子模块
AudioManager.Instance.StopMusic();
AudioManager.Instance.InGameAudioInit(this,MapData);
@ -197,15 +181,14 @@ namespace TH1_Logic.Core
MapConfig = new MapConfig(h,w,playerCount,civId,forceId,diff);
//初始化所有Data
MapData = new MapData(MapConfig);
MapData.Net.RefreshPlayerNet(MapData);
AchievementDataManager.Instance.BindMapData(MapData);
//清空MapRenderer,然后重新初始化
MapRenderer.Dispose();
MapRenderer.Initialize(this,MapData);
UIManager.Instance.GameInit();
//初始化交互相关的logic
InputLogic = new InputLogic(this,MapData);
MapInteractionLogic = new MapInteraction(this,MapData);
@ -216,6 +199,45 @@ namespace TH1_Logic.Core
MapRenderer.Instance.FirstRenderMap();
//移动镜头+显示开局提示
var camera = GameObject.Find("Main Camera").GetComponent<CameraController>();
var selfp = MapData.PlayerMap.SelfPlayerData;
if(MapData.GetCapitalCityDataByPlayerId(selfp.Id, out var cap) && MapData.GetGridDataByCityId(cap.Id, out var grid))
camera.CameraFocusOnGrid(grid,true);
Timer.Instance.TimerRegister(this, () =>
{
//start game
var announcement = new ShowUIAnnounceMajorEvent { EventType = UIAnnounceMajorEventType.StartGame};
EventManager.Publish(announcement);
//UIManager.Instance.CenterMessageUI.SetCenterMessageShow(UICenterMessageID.StartGame,MapData.PlayerMap.SelfPlayerData);
},1.5f,"Main_CenterMessage_Anim");
MapData.Net.RefreshMapNet(MapData);
if (LobbyManager.Instance.Lobby.IsLobbyOwner()) GameNetSender.Instance.GameStart();
GameLogic.ChangeToNextPlayerRound();
}
// 成员客户端开始游戏
public void NetStartGame(MapData map)
{
//停止音乐然后为这句游戏初始化一个AudioManager的子模块
AudioManager.Instance.StopMusic();
AudioManager.Instance.InGameAudioInit(this,MapData);
MapData = map;
MapData.Net.RefreshPlayerNet(MapData);
AchievementDataManager.Instance.BindMapData(MapData);
//清空MapRenderer,然后重新初始化
MapRenderer.Dispose();
MapRenderer.Initialize(this,MapData);
UIManager.Instance.GameInit();
//初始化交互相关的logic
InputLogic = new InputLogic(this,MapData);
MapInteractionLogic = new MapInteraction(this,MapData);
MapRenderer.Instance.FirstRenderMap();
var camera = GameObject.Find("Main Camera").GetComponent<CameraController>();
var selfp = MapData.PlayerMap.SelfPlayerData;
if(MapData.GetCapitalCityDataByPlayerId(selfp.Id, out var cap)
@ -230,9 +252,8 @@ namespace TH1_Logic.Core
},1.5f,"Main_CenterMessage_Anim");
MapData.Net.RefreshMapNet(MapData);
GameLogic.ChangeState(GameState.PlayerRound);
}
// Update is called once per frame
void Update()
{
@ -247,6 +268,7 @@ namespace TH1_Logic.Core
Timer.Instance.Update();
AudioManager.Instance.Update();
ConfigManager.Instance.Update();
TH1SteamManager.Instance.Update();
if (GameLogic.GetCurState() != GameState.Menu)
{

View File

@ -36,10 +36,7 @@ namespace Logic.HeroTask
[MemoryPackOnDeserialized]
public void OnAfterMemoryPackDeserialize()
{
foreach (var item in Items)
{
}
}
}
}

View File

@ -17,7 +17,7 @@ namespace TH1_Logic.HeroTask
{
public static HeroTaskManager Instance = new HeroTaskManager();
private HeroTaskData _data;
public void Init()
{

View File

@ -6,6 +6,7 @@
*/
using Logic.Action;
using Logic.Audio;
using UnityEngine;
using RuntimeData;
@ -91,7 +92,14 @@ namespace Logic
else if (roUnit.IsAttackHighlight)
{
CancelAllHighlight();
Main.UnitLogic.Attack(Main.MapData, MapRenderer.Instance.SelectUnitData, unitData, out _);
// 攻击行为切换成 Action 驱动
var attackID = new CommonActionId { ActionType = CommonActionType.UnitAttack };
var attackAction = new UnitAttackAction(attackID);
var param = new CommonActionParams(Main.MapData, unitData:MapRenderer.Instance.SelectUnitData, targetUnit:unitData);
param.RefreshParams();
attackAction.CompleteExecute(param, false);
// Main.UnitLogic.Attack(Main.MapData, MapRenderer.Instance.SelectUnitData, unitData, out _);
UIManager.Instance.BottomInfoUI.UIBottomInfoStatus = false;
}
//如果是Ally
@ -134,7 +142,7 @@ namespace Logic
else if (roGrid.IsMoveHighlight)
{
CancelAllHighlight();
Main.UnitLogic.MoveTo(Main.MapData, MapRenderer.Instance.SelectUnitData, gridData,MoveType.ActiveMove);
Main.UnitLogic.MoveTo(Main.MapData, MapRenderer.Instance.SelectUnitData, gridData);
//切换相机镜头
MapRenderer.Instance.CameraController.CameraFocusOnGrid(gridData);
UIManager.Instance.BottomInfoUI.UIBottomInfoStatus = false;
@ -145,10 +153,6 @@ namespace Logic
OnTileClicked(mapData,gridData);
},Table.Instance.AnimDataAssets.MoveAnimTime,"MapInteraction_OnTileClicked_Move");
}
}
//如果是地块点击
else if (!roGrid.IsSelectHighlight)

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9bd695aa118d4d02a094e6273b9eb9b3
timeCreated: 1758014744

View File

@ -0,0 +1,120 @@
/*
* @Author:
* @Description:
* @Date: 20250916 16:09:43
* @Modify:
*/
using System.Collections.Generic;
namespace TH1_Logic.Net
{
// 房间状态
public enum LobbyState
{
None, // 未在房间中
Creating, // 正在创建房间
Joining, // 正在加入房间
InLobby, // 在房间中
Leaving // 正在离开房间
}
public interface ILobby
{
// 获取房间所有成员
public List<ulong> GetAllMemberIds();
// 获取成员数量
public int GetMemberCount();
// 获取最大成员数
public int GetMemberLimit();
// 判断成员是否在房间中
public bool IsMemberInLobby(ulong memberId);
// 获取自己的 memberId
public ulong GetSelfMemberId();
// 获取房主的 memberId
public ulong GetLobbyOwnerId();
public LobbyState GetCurState();
public bool IsLobbyOwner();
public bool IsInLobby();
// 发送P2P消息
public bool SendMessageToPeer(ulong member, byte[] data, bool reliable = true);
// 广播P2P消息
public void BroadcastMessage(byte[] data, bool reliable = true);
}
public class LobbyBase : ILobby
{
// 获取房间所有成员
public List<ulong> GetAllMemberIds()
{
return new List<ulong>();
}
// 获取成员数量
public int GetMemberCount()
{
return 0;
}
// 获取最大成员数
public int GetMemberLimit()
{
return 0;
}
// 判断成员是否在房间中
public bool IsMemberInLobby(ulong memberId)
{
return false;
}
// 获取自己的 memberId
public ulong GetSelfMemberId()
{
return 0;
}
// 获取房主的 memberId
public ulong GetLobbyOwnerId()
{
return 0;
}
public LobbyState GetCurState()
{
return LobbyState.None;
}
public bool IsLobbyOwner()
{
return false;
}
public bool IsInLobby()
{
return false;
}
public bool SendMessageToPeer(ulong member, byte[] data, bool reliable = true)
{
return false;
}
public void BroadcastMessage(byte[] data, bool reliable = true)
{
return;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fdb1d9700efa4b579fd60337d47e081d
timeCreated: 1758013115

View File

@ -0,0 +1,22 @@
/*
* @Author:
* @Description:
* @Date: 20250918 11:09:46
* @Modify:
*/
namespace TH1_Logic.Net
{
public class LobbyManager
{
public static LobbyManager Instance { get; } = new LobbyManager();
public ILobby Lobby;
public void Init()
{
Lobby = new LobbyBase();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e636e67ebbd640e5bc85057f41dbe1a4
timeCreated: 1758165819

View File

@ -0,0 +1,160 @@
using Logic.Action;
using Logic.CrashSight;
using RuntimeData;
using Steamworks;
using TH1_Logic.Core;
using TH1_Logic.Net;
namespace TH1_Logic.Steam
{
public class GameNetReceiver
{
public static GameNetReceiver Instance { get; } = new GameNetReceiver();
public void OnMessageReceived(CSteamID cSteamID, byte[] data)
{
P2PMsgType msgType = GetMessageType(data);
if (msgType == P2PMsgType.String) OnReceivedString(data);
if (msgType == P2PMsgType.GameStart) OnReceivedGameStart(data);
if (msgType == P2PMsgType.ActionConfirm) OnReceivedActionConfirm(data);
if (msgType == P2PMsgType.ActionExcute) OnReceivedActionExcute(data);
if (msgType == P2PMsgType.TurnEnd) OnReceivedTurnEnd(data);
if (msgType == P2PMsgType.TurnChange) OnReceivedTurnChange(data);
}
// 基础字符串消息
private void OnReceivedString(byte[] data)
{
var message = MemoryPack.MemoryPackSerializer.Deserialize<StringMessage>(data);
if (message == null)
{
LogSystem.LogError($"消息解析失败: OnReceivedString");
return;
}
if (string.IsNullOrEmpty(message.Content)) return;
LogSystem.LogInfo($"收到消息 : {message.Content}");
}
// 只有玩家会收到
private void OnReceivedGameStart(byte[] data)
{
var message = MemoryPack.MemoryPackSerializer.Deserialize<GameStartMessage>(data);
if (message == null)
{
LogSystem.LogError($"消息解析失败: OnReceivedGameStart");
return;
}
if (message.MapData == null) return;
if (LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
Main.Instance.NetStartGame(message.MapData);
}
// 只有房主会收到
private void OnReceivedActionConfirm(byte[] data)
{
var message = MemoryPack.MemoryPackSerializer.Deserialize<ActionConfirmMessage>(data);
if (message == null)
{
LogSystem.LogError($"消息解析失败: OnReceivedActionConfirm");
return;
}
if (!LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
if (message.ActionData == null) return;
if (message.ActionData.MapHash != Main.MapData.Net.MapHash)
{
LogSystem.LogError($"OnReceivedActionConfirm MapHash不一致");
return;
}
if (message.ActionData.Version != Main.MapData.Net.GetActionVersion())
{
LogSystem.LogError($"OnReceivedActionConfirm Version 不一致");
return;
}
message.ActionData.Param.MapData = Main.MapData;
message.ActionData.Param.RefreshParams();
var action = ActionLogicFactory.GetActionLogic(message.ActionData.ActionId);
if (action == null)
{
LogSystem.LogError($"OnReceivedActionConfirm 找不到对应 Action");
return;
}
action.CompleteExecute(message.ActionData.Param, false);
GameNetSender.Instance.ActionExcute(message.ActionData.ActionId, message.ActionData.Param);
}
private void OnReceivedActionExcute(byte[] data)
{
var message = MemoryPack.MemoryPackSerializer.Deserialize<ActionExcuteMessage>(data);
if (message == null)
{
LogSystem.LogError($"消息解析失败: OnReceivedActionExcute");
return;
}
if (LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
if (message.ActionData == null) return;
if (message.ActionData.MapHash != Main.MapData.Net.MapHash)
{
LogSystem.LogError($"OnReceivedActionConfirm MapHash不一致");
return;
}
if (message.ActionData.Version != Main.MapData.Net.GetActionVersion())
{
LogSystem.LogError($"OnReceivedActionConfirm Version 不一致");
return;
}
message.ActionData.Param.MapData = Main.MapData;
message.ActionData.Param.RefreshParams();
var action = ActionLogicFactory.GetActionLogic(message.ActionData.ActionId);
if (action == null)
{
LogSystem.LogError($"OnReceivedActionConfirm 找不到对应 Action");
return;
}
action.CompleteExecute(message.ActionData.Param, false);
}
// 只有房主会收到
private void OnReceivedTurnEnd(byte[] data)
{
var message = MemoryPack.MemoryPackSerializer.Deserialize<TurnEndMessage>(data);
if (message == null)
{
LogSystem.LogError($"消息解析失败: OnReceivedTurnEnd");
return;
}
if (!LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
if (Main.Instance.GameLogic.CurPlayer.Id != message.PlayerId) return;
Main.Instance.GameLogic.ChangeToNextPlayerRound();
}
// 只有普通玩家会收到
private void OnReceivedTurnChange(byte[] data)
{
var message = MemoryPack.MemoryPackSerializer.Deserialize<TurnChangeMessage>(data);
if (message == null)
{
LogSystem.LogError($"消息解析失败: OnReceivedTurnChange");
return;
}
if (LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
Main.Instance.GameLogic.ChangeToNextPlayerRound();
if (Main.Instance.GameLogic.CurPlayer.Id != message.PlayerId)
{
LogSystem.LogError($"OnReceivedTurnChange Error: CurPlayer id is {Main.Instance.GameLogic.CurPlayer.Id}, " +
$"but message.PlayerId is {message.PlayerId}");
}
}
private P2PMsgType GetMessageType(byte[] data)
{
// 临时反序列化只为获取消息类型
var tempMessage = MemoryPack.MemoryPackSerializer.Deserialize<BaseMessage>(data);
if (tempMessage == null) return P2PMsgType.None;
return tempMessage.MessageType;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6d8456326f3a49218f670c2f301f954e
timeCreated: 1757490238

View File

@ -7,9 +7,13 @@
using System;
using Logic.Action;
using Logic.AI;
using RuntimeData;
using Steamworks;
using TH1_Logic.Core;
using TH1_Logic.Net;
using UnityEngine;
namespace TH1_Logic.Steam
@ -18,78 +22,114 @@ namespace TH1_Logic.Steam
{
public static GameNetSender Instance { get; } = new GameNetSender();
// 发送消息给房主
public void SendMessage<T>(T message) where T : BaseMessage
{
if (LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
byte[] messageBytes = MemoryPack.MemoryPackSerializer.Serialize(message);
LobbyManager.Instance.Lobby.SendMessageToPeer(LobbyManager.Instance.Lobby.GetLobbyOwnerId(), messageBytes);
}
// 发送消息给指定人
public void SendMessageToPlayer<T>(ulong memberId, T message) where T : BaseMessage
{
byte[] messageBytes = MemoryPack.MemoryPackSerializer.Serialize(message);
LobbyManager.Instance.Lobby.SendMessageToPeer(memberId, messageBytes);
}
// 房主广播消息给所有成员
public void BroadcastMessage<T>(T message) where T : BaseMessage
{
if (!LobbyManager.Instance.Lobby.IsLobbyOwner()) return;
byte[] messageBytes = MemoryPack.MemoryPackSerializer.Serialize(message);
LobbyManager.Instance.Lobby.BroadcastMessage(messageBytes);
}
// 广播字符串
public void BroadcastString(string str)
{
var data = new StringMessage();
data.Content = str;
BroadcastMessage(data);
}
// 游戏开始
public void GameStart()
{
// 序列化 MapData
byte[] mapDataBytes = MemoryPack.MemoryPackSerializer.Serialize(Main.MapData);
// 创建完整消息:消息头(1字节) + 数据长度(4字节) + MapData数据
byte[] result = new byte[1 + 4 + mapDataBytes.Length];
int offset = 0;
// 写入消息类型
result[offset] = (byte)P2PMsgType.GameStart;
offset += 1;
// 写入数据长度
byte[] lengthBytes = BitConverter.GetBytes(mapDataBytes.Length);
Array.Copy(lengthBytes, 0, result, offset, 4);
offset += 4;
// 写入 MapData 数据
Array.Copy(mapDataBytes, 0, result, offset, mapDataBytes.Length);
SteamLobbyManager.Instance.BroadcastMessage(result);
var data = new GameStartMessage();
data.MapData = Main.MapData;
BroadcastMessage(data);
}
//行为确认 (成员 => 房主)
public void ActionConfirm(AIActionBase action)
// 请求行为 (成员 => 房主)
public void ActionConfirm(CommonActionId id, CommonActionParams param)
{
var actionData = new ActionNetData();
actionData.Version = Main.MapData.Net.GetActionVersion();
actionData.MapHash = NetData.GetMapDataHash(Main.MapData);
actionData.Param = action.Param;
actionData.ActionId = action.ActionLogic.ActionId;
actionData.Param = param;
actionData.ActionId = id;
byte[] data = MemoryPack.MemoryPackSerializer.Serialize(actionData);
byte[] result = new byte[1 + 4 + data.Length];
int offset = 0;
// 写入消息类型
result[offset] = (byte)P2PMsgType.ActionConfirm;
offset += 1;
// 写入数据长度
byte[] lengthBytes = BitConverter.GetBytes(data.Length);
Array.Copy(lengthBytes, 0, result, offset, 4);
offset += 4;
// 写入 data
Array.Copy(data, 0, result, offset, data.Length);
SteamLobbyManager.Instance.SendMessageToPeer(SteamLobbyManager.Instance.CachedOwner, result);
var data = new ActionConfirmMessage();
data.ActionData = actionData;
SendMessage(data);
}
//行为执行 (房主 => 所有成员)
public void ActionExcute(AIActionBase action)
// 行为执行 (房主 => 所有成员)
public void ActionExcute(CommonActionId id, CommonActionParams param)
{
var actionData = new ActionNetData();
actionData.Version = Main.MapData.Net.GetActionVersion();
actionData.MapHash = NetData.GetMapDataHash(Main.MapData);
actionData.Param = action.Param;
actionData.ActionId = action.ActionLogic.ActionId;
actionData.Param = param;
actionData.ActionId = id;
byte[] data = MemoryPack.MemoryPackSerializer.Serialize(actionData);
byte[] result = new byte[1 + 4 + data.Length];
int offset = 0;
// 写入消息类型
result[offset] = (byte)P2PMsgType.ActionExcute;
offset += 1;
// 写入数据长度
byte[] lengthBytes = BitConverter.GetBytes(data.Length);
Array.Copy(lengthBytes, 0, result, offset, 4);
offset += 4;
// 写入 data
Array.Copy(data, 0, result, offset, data.Length);
SteamLobbyManager.Instance.BroadcastMessage(result);
var data = new ActionExcuteMessage();
data.ActionData = actionData;
BroadcastMessage(data);
}
// 请求回合结束 (成员 => 房主)
public void TurnEndConfirm()
{
var data = new TurnEndMessage();
data.PlayerId = Main.MapData.PlayerMap.SelfPlayerId;
SendMessage(data);
}
// 回合切换广播 (房主 => 所有成员)
public void TurnChange(uint playerId)
{
var data = new TurnChangeMessage();
data.PlayerId = playerId;
BroadcastMessage(data);
}
// map 校验 (成员 => 房主)
public void MapConfirm()
{
var data = new MapConfirmMessage();
data.PlayerId = Main.MapData.PlayerMap.SelfPlayerId;
SendMessage(data);
}
// 强制更新 (房主 => 单成员)
public void ForceUpdate(uint playerId)
{
var steamId = Main.MapData.Net.GetSteamId(playerId);
if (steamId == 0) return;
var data = new ForceUpdateMessage();
data.MapData = Main.MapData;
SendMessageToPlayer(steamId, data);
}
// 强制更新 (房主 => 所有成员)
public void BroadcastForceUpdate()
{
var data = new ForceUpdateMessage();
data.MapData = Main.MapData;
BroadcastMessage(data);
}
}
}

View File

@ -154,7 +154,7 @@ namespace TH1_Logic.Steam
}
// 发送消息到指定玩家
public bool SendTo(CSteamID target, byte[] data, bool reliable = true)
public bool SendTo(CSteamID target, byte[] data, bool reliable = true, bool ordered = true)
{
if (data == null || data.Length == 0)
{
@ -170,7 +170,8 @@ namespace TH1_Logic.Steam
// 可靠传输=8不可靠传输=0
int flags = reliable ? 8 : 0;
// 如果需要有序传输 k_nSteamNetworkingSend_NoDelay (确保按序处理)
if (ordered) flags |= 1;
IntPtr ptr = IntPtr.Zero;
try
{
@ -242,7 +243,7 @@ namespace TH1_Logic.Steam
Marshal.Copy(message.m_pData, data, 0, message.m_cbSize);
// 触发接收事件
OnMessageReceivedEvent?.Invoke(steamID, data);
GameNetReceiver.Instance.OnMessageReceived(steamID, data);
}
catch (Exception e)
{

View File

@ -0,0 +1,67 @@
#if USE_INPUT
/*
* @Author:
* @Description:
* @Date: 20250918 14:09:13
* @Modify:
*/
using TH1_Logic.Net;
using UnityEngine;
namespace TH1_Logic.Steam
{
public class SteamGUIMono : MonoBehaviour
{
public bool EnableDebugLog = true;
public void Update()
{
if (Input.GetKeyDown(KeyCode.F3))
{
EnableDebugLog = !EnableDebugLog;
}
}
private void OnGUI()
{
if (!EnableDebugLog) return;
GUILayout.BeginArea(new Rect(10, 10, 300, 400));
GUILayout.BeginVertical("box");
GUILayout.Label("Steam 测试状态", GUI.skin.label);
GUILayout.Label($"Steam初始化: {(TH1SteamManager.Instance.IsSteamInitialized ? "" : "")}");
GUILayout.Label($"用户登录: {(TH1SteamManager.Instance.IsLoggedIn ? "" : "")}");
if (TH1SteamManager.Instance.IsLoggedIn)
{
GUILayout.Label($"用户: {TH1SteamManager.Instance.CurrentUserName}");
GUILayout.Label($"ID: {TH1SteamManager.Instance.CurrentUserID}");
}
GUILayout.Space(10);
GUILayout.Label("房间状态", GUI.skin.label);
GUILayout.Label($"当前状态: {LobbyManager.Instance.Lobby.GetCurState()}");
GUILayout.Label($"在房间中: {(LobbyManager.Instance.Lobby.IsInLobby() ? "" : "")}");
GUILayout.Label($"是房主: {(LobbyManager.Instance.Lobby.IsLobbyOwner() ? "" : "")}");
if (LobbyManager.Instance.Lobby.IsInLobby())
{
GUILayout.Label($"房间ID: {LobbyManager.Instance.Lobby.GetCurState()}");
GUILayout.Label($"成员数: {LobbyManager.Instance.Lobby.GetMemberCount()}/{LobbyManager.Instance.Lobby.GetMemberLimit()}");
GUILayout.Label($"P2P连接数: {SimpleP2P.Instance.GetConnectionCount()}");
}
GUILayout.EndVertical();
GUILayout.EndArea();
}
}
}
#endif

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 96a3dc180c464f76ab2da78db6827c2a
timeCreated: 1758178749

View File

@ -2,35 +2,17 @@
using System.Linq;
using Logic.CrashSight;
using Steamworks;
using TH1_Logic.Net;
using UnityEngine;
namespace TH1_Logic.Steam
{
public class SteamLobbyManager
public class SteamLobbyManager : ILobby
{
public static SteamLobbyManager Instance { get; } = new SteamLobbyManager();
public CSteamID CurrentLobby = CSteamID.Nil;
public CSteamID CachedOwner = CSteamID.Nil;
// 房间状态
public enum LobbyState
{
None, // 未在房间中
Creating, // 正在创建房间
Joining, // 正在加入房间
InLobby, // 在房间中
Leaving // 正在离开房间
}
public LobbyState CurrentState { get; private set; } = LobbyState.None;
public bool IsLobbyOwner =>
CurrentLobby.IsValid() &&
SteamMatchmaking.GetLobbyOwner(CurrentLobby) == SteamUser.GetSteamID();
public bool IsInLobby => CurrentState == LobbyState.InLobby && CurrentLobby.IsValid();
// 事件委托
public event System.Action<CSteamID> OnLobbyCreatedEvent; // 房间创建成功
@ -130,7 +112,7 @@ namespace TH1_Logic.Steam
// 解散房间(仅房主可用)
public void DisbandLobby()
{
if (!IsLobbyOwner)
if (!IsLobbyOwner())
{
LogSystem.LogInfo("Only lobby owner can disband the lobby");
return;
@ -156,7 +138,7 @@ namespace TH1_Logic.Steam
// 踢出指定成员(仅房主可用)
public void KickMember(CSteamID memberToKick)
{
if (!IsLobbyOwner)
if (!IsLobbyOwner())
{
OnLobbyErrorEvent?.Invoke("Only lobby owner can kick members");
return;
@ -222,7 +204,7 @@ namespace TH1_Logic.Steam
// 设置房间数据
public void SetLobbyData(string key, string value)
{
if (!IsLobbyOwner)
if (!IsLobbyOwner())
{
OnLobbyErrorEvent?.Invoke("Only lobby owner can set lobby data");
return;
@ -322,7 +304,7 @@ namespace TH1_Logic.Steam
OnMemberJoinedEvent?.Invoke(changedUser);
// 如果我是房主,尝试连接到新成员
if (IsLobbyOwner && changedUser != SteamUser.GetSteamID())
if (IsLobbyOwner() && changedUser != SteamUser.GetSteamID())
{
SimpleP2P.Instance.ConnectToPeer(changedUser);
}
@ -369,7 +351,7 @@ namespace TH1_Logic.Steam
// 房主切换时内部处理
private void OnHostChangedInternal()
{
if (IsLobbyOwner)
if (IsLobbyOwner())
{
LogSystem.LogInfo("I became the new host");
@ -396,7 +378,7 @@ namespace TH1_Logic.Steam
private void OnLobbyReadyInternal()
{
// 如果不是房主,连接到房主
if (!IsLobbyOwner && CachedOwner.IsValid())
if (!IsLobbyOwner() && CachedOwner.IsValid())
{
SimpleP2P.Instance.ConnectToPeer(CachedOwner);
}
@ -450,22 +432,31 @@ namespace TH1_Logic.Steam
LogSystem.LogError($"P2P connection error: {error}");
}
// 发送P2P消息
public bool SendMessageToPeer(CSteamID target, byte[] data, bool reliable = true)
// 轮询P2P消息需要在Update中调用
public void Update()
{
if (!IsInLobby)
SimpleP2P.Instance.PollMessages();
}
// 发送P2P消息
public bool SendMessageToPeer(ulong member, byte[] data, bool reliable = true)
{
if (!IsInLobby())
{
OnLobbyErrorEvent?.Invoke("Not in lobby");
return false;
}
return SimpleP2P.Instance.SendTo(target, data, reliable);
if (IsMemberInLobby(member)) return false;
if (member == GetSelfMemberId()) return false;
var cSteamId = new CSteamID(member);
return SimpleP2P.Instance.SendTo(cSteamId, data, reliable);
}
// 广播P2P消息
public void BroadcastMessage(byte[] data, bool reliable = true)
{
if (!IsInLobby)
if (!IsInLobby())
{
OnLobbyErrorEvent?.Invoke("Not in lobby");
return;
@ -473,15 +464,9 @@ namespace TH1_Logic.Steam
SimpleP2P.Instance.Broadcast(data, reliable);
}
// 轮询P2P消息需要在Update中调用
public void Update()
{
SimpleP2P.Instance.PollMessages();
}
// 枚举房间成员
public IEnumerable<CSteamID> EnumerateMembers()
private IEnumerable<CSteamID> EnumerateMembers()
{
if (!CurrentLobby.IsValid()) yield break;
int count = SteamMatchmaking.GetNumLobbyMembers(CurrentLobby);
@ -489,6 +474,20 @@ namespace TH1_Logic.Steam
yield return SteamMatchmaking.GetLobbyMemberByIndex(CurrentLobby, i);
}
// 获取房间所有成员
public List<ulong> GetAllMemberIds()
{
if (!CurrentLobby.IsValid()) return new List<ulong>();
int count = SteamMatchmaking.GetNumLobbyMembers(CurrentLobby);
var list = new List<ulong>();
for (int i = 0; i < count; i++)
{
var cSteamId = SteamMatchmaking.GetLobbyMemberByIndex(CurrentLobby, i);
list.Add(cSteamId.m_SteamID);
}
return list;
}
// 获取成员数量
public int GetMemberCount()
{
@ -502,6 +501,64 @@ namespace TH1_Logic.Steam
if (!CurrentLobby.IsValid()) return 0;
return SteamMatchmaking.GetLobbyMemberLimit(CurrentLobby);
}
// 判断成员是否在房间中
public bool IsMemberInLobby(ulong memberId)
{
if (!CurrentLobby.IsValid()) return false;
int count = SteamMatchmaking.GetNumLobbyMembers(CurrentLobby);
for (int i = 0; i < count; i++)
{
var cSteamId = SteamMatchmaking.GetLobbyMemberByIndex(CurrentLobby, i);
if (cSteamId.m_SteamID == memberId) return true;
}
return false;
}
// 根据 memberId 获取 CSteamId
public CSteamID GetCSteamID(ulong memberId)
{
if (!CurrentLobby.IsValid()) return CSteamID.Nil;
int count = SteamMatchmaking.GetNumLobbyMembers(CurrentLobby);
for (int i = 0; i < count; i++)
{
var cSteamId = SteamMatchmaking.GetLobbyMemberByIndex(CurrentLobby, i);
if (cSteamId.m_SteamID == memberId) return cSteamId;
}
return CSteamID.Nil;
}
// 获取自己的 memberId
public ulong GetSelfMemberId()
{
return SteamUser.GetSteamID().m_SteamID;
}
// 获取房主的 memberId
public ulong GetLobbyOwnerId()
{
if (!CurrentLobby.IsValid()) return 0;
var owner = SteamMatchmaking.GetLobbyOwner(CurrentLobby);
return owner.m_SteamID;
}
// 获取当前房间状态
public LobbyState GetCurState()
{
return CurrentState;
}
// 自己是否是房主
public bool IsLobbyOwner()
{
return IsInLobby() && SteamMatchmaking.GetLobbyOwner(CurrentLobby) == SteamUser.GetSteamID();
}
// 自己是否在房间中
public bool IsInLobby()
{
return CurrentState == LobbyState.InLobby && CurrentLobby.IsValid();
}
// 清理资源
public void Cleanup()

View File

@ -1,18 +1,116 @@
using System.Text;
using Logic.AI;
using MemoryPack;
using RuntimeData;
/*
* -> 广
*
* 广
* 广
* 广
*/
namespace TH1_Logic.Steam
{
public enum P2PMsgType : byte
{
None = 0,
// 基础字符串消息
String = 1,
// 游戏开始 (房主 => 所有成员)
GameStart = 1,
//行为确认 (成员 => 房主)
ActionConfirm = 2,
//行为执行 (房主 => 所有成员)
ActionExcute = 3,
// 回合结束广播 (房主 => 所有成员)
TurnEnd = 4,
GameStart = 2,
// 请求行为 (成员 => 房主)
ActionConfirm = 3,
// 行为执行 (房主 => 所有成员)
ActionExcute = 4,
// 请求回合结束 (成员 => 房主)
TurnEnd = 5,
// 回合切换广播 (房主 => 所有成员)
TurnChange = 6,
// 游戏校验 (成员 => 房主)
MapConfirm = 7,
// 强制更新 (房主 => 所有成员)
ForceUpdate = 8,
}
[MemoryPackable]
[MemoryPackUnion(1, typeof(StringMessage))]
[MemoryPackUnion(2, typeof(GameStartMessage))]
[MemoryPackUnion(3, typeof(ActionConfirmMessage))]
[MemoryPackUnion(4, typeof(ActionExcuteMessage))]
[MemoryPackUnion(5, typeof(TurnEndMessage))]
[MemoryPackUnion(6, typeof(TurnChangeMessage))]
[MemoryPackUnion(7, typeof(MapConfirmMessage))]
[MemoryPackUnion(8, typeof(ForceUpdateMessage))]
public abstract partial class BaseMessage
{
public abstract P2PMsgType MessageType { get; }
}
[MemoryPackable]
public partial class StringMessage : BaseMessage
{
public override P2PMsgType MessageType => P2PMsgType.String;
public string Content { get; set; }
}
[MemoryPackable]
public partial class GameStartMessage : BaseMessage
{
public override P2PMsgType MessageType => P2PMsgType.GameStart;
public MapData MapData { get; set; }
}
[MemoryPackable]
public partial class ActionConfirmMessage : BaseMessage
{
public override P2PMsgType MessageType => P2PMsgType.ActionConfirm;
public ActionNetData ActionData { get; set; }
}
[MemoryPackable]
public partial class ActionExcuteMessage : BaseMessage
{
public override P2PMsgType MessageType => P2PMsgType.ActionExcute;
public ActionNetData ActionData { get; set; }
}
[MemoryPackable]
public partial class TurnEndMessage : BaseMessage
{
public override P2PMsgType MessageType => P2PMsgType.TurnEnd;
public uint PlayerId { get; set; }
}
[MemoryPackable]
public partial class TurnChangeMessage : BaseMessage
{
public override P2PMsgType MessageType => P2PMsgType.TurnChange;
public uint PlayerId { get; set; }
}
[MemoryPackable]
public partial class MapConfirmMessage : BaseMessage
{
public override P2PMsgType MessageType => P2PMsgType.MapConfirm;
public uint PlayerId { get; set; }
public ActionNetData ActionData { get; set; }
}
[MemoryPackable]
public partial class ForceUpdateMessage : BaseMessage
{
public override P2PMsgType MessageType => P2PMsgType.ForceUpdate;
public MapData MapData { get; set; }
}
}

View File

@ -3,51 +3,29 @@ using System.IO;
using UnityEngine;
using Steamworks;
using Logic.CrashSight;
using TH1_Logic.Net;
namespace TH1_Logic.Steam
{
/// <summary>
/// Steam测试管理器 - 用于在Unity编辑器中测试Steam功能
/// </summary>
public class SteamTestManager : MonoBehaviour
public class TH1SteamManager
{
public static TH1SteamManager Instance { get; } = new TH1SteamManager();
[Header("Steam 连接状态")]
public bool IsSteamInitialized = false;
public bool IsLoggedIn = false;
public string CurrentUserName = "";
public CSteamID CurrentUserID;
[Header("测试配置")]
[SerializeField] private bool autoInitialize = true;
[SerializeField] private bool enableDebugLog = true;
[Header("房间测试")]
[SerializeField] private int maxLobbyMembers = 4;
private void Awake()
{
// 确保只有一个实例
if (FindObjectsOfType<SteamTestManager>().Length > 1)
{
Destroy(gameObject);
return;
}
DontDestroyOnLoad(gameObject);
}
private void Start()
{
if (autoInitialize)
{
StartCoroutine(InitializeSteam());
}
}
private int _maxLobbyMembers = 4;
private SteamLobbyManager _lobby;
/// <summary>
/// 初始化Steam
/// </summary>
private IEnumerator InitializeSteam()
public void Init()
{
LogSystem.LogInfo("开始初始化Steam...");
LogSystem.LogInfo($"启动方式检测: {(SteamAPI.RestartAppIfNecessary(new Steamworks.AppId_t(480)) ? "Steam启动" : "Steam启动")}");
@ -56,7 +34,7 @@ namespace TH1_Logic.Steam
if (!SteamAPI.IsSteamRunning())
{
LogSystem.LogError("Steam客户端未运行请先启动Steam。");
yield break;
return;
}
// 检查steam_appid.txt文件状态
@ -73,14 +51,10 @@ namespace TH1_Logic.Steam
LogSystem.LogError("2. steam_appid.txt文件配置错误开发环境");
LogSystem.LogError("3. 没有以Steam方式启动应用开发环境");
LogSystem.LogError("4. Steam App ID不匹配");
yield break;
return;
}
LogSystem.LogInfo("Steam API初始化成功");
// 等待一帧确保Steam完全初始化
yield return null;
// 检查用户登录状态
try
{
@ -189,20 +163,20 @@ namespace TH1_Logic.Steam
private void InitializeSteamLobbyManager()
{
if (!IsSteamInitialized || !IsLoggedIn) return;
try
{
_lobby ??= new SteamLobbyManager();
// 初始化房间管理器
SteamLobbyManager.Instance.InitCallbacks();
_lobby.InitCallbacks();
// 订阅事件
SteamLobbyManager.Instance.OnLobbyCreatedEvent += OnLobbyCreated;
SteamLobbyManager.Instance.OnLobbyEnteredEvent += OnLobbyEntered;
SteamLobbyManager.Instance.OnLobbyLeftEvent += OnLobbyLeft;
SteamLobbyManager.Instance.OnMemberJoinedEvent += OnMemberJoined;
SteamLobbyManager.Instance.OnMemberLeftEvent += OnMemberLeft;
SteamLobbyManager.Instance.OnHostChangedEvent += OnHostChanged;
SteamLobbyManager.Instance.OnLobbyErrorEvent += OnLobbyError;
_lobby.OnLobbyCreatedEvent += OnLobbyCreated;
_lobby.OnLobbyEnteredEvent += OnLobbyEntered;
_lobby.OnLobbyLeftEvent += OnLobbyLeft;
_lobby.OnMemberJoinedEvent += OnMemberJoined;
_lobby.OnMemberLeftEvent += OnMemberLeft;
_lobby.OnHostChangedEvent += OnHostChanged;
_lobby.OnLobbyErrorEvent += OnLobbyError;
// 订阅P2P事件
SimpleP2P.Instance.OnPeerConnectedEvent += OnP2PPeerConnected;
@ -211,6 +185,7 @@ namespace TH1_Logic.Steam
SimpleP2P.Instance.OnConnectionErrorEvent += OnP2PConnectionError;
LogSystem.LogInfo("Steam房间管理器初始化成功");
LobbyManager.Instance.Lobby = _lobby;
}
catch (System.Exception e)
{
@ -218,7 +193,7 @@ namespace TH1_Logic.Steam
}
}
private void Update()
public void Update()
{
if (IsSteamInitialized)
{
@ -226,7 +201,7 @@ namespace TH1_Logic.Steam
SteamAPI.RunCallbacks();
// 更新P2P消息
SteamLobbyManager.Instance.Update();
_lobby.Update();
}
}
@ -234,7 +209,7 @@ namespace TH1_Logic.Steam
{
if (IsSteamInitialized)
{
SteamLobbyManager.Instance.Cleanup();
_lobby.Cleanup();
SteamAPI.Shutdown();
LogSystem.LogInfo("Steam API已关闭");
}
@ -250,7 +225,7 @@ namespace TH1_Logic.Steam
private void OnLobbyEntered(CSteamID lobbyId)
{
LogSystem.LogInfo($"[测试] 进入房间: {lobbyId}");
LogSystem.LogInfo($"[测试] 房间成员数: {SteamLobbyManager.Instance.GetMemberCount()}/{SteamLobbyManager.Instance.GetMemberLimit()}");
LogSystem.LogInfo($"[测试] 房间成员数: {_lobby.GetMemberCount()}/{_lobby.GetMemberLimit()}");
}
private void OnLobbyLeft()
@ -312,52 +287,69 @@ namespace TH1_Logic.Steam
#endregion
#region - Inspector中调用
#region
[ContextMenu("创建测试房间")]
public void TestCreateLobby()
// 创建测试房间
public void CreateLobby()
{
if (!CanPerformLobbyAction()) return;
LogSystem.LogInfo("[测试] 创建房间...");
SteamLobbyManager.Instance.CreateFriendsLobby(maxLobbyMembers);
_lobby.CreateFriendsLobby(_maxLobbyMembers);
}
[ContextMenu("离开房间")]
public void TestLeaveLobby()
// 离开房间
public void LeaveLobby()
{
if (!SteamLobbyManager.Instance.IsInLobby)
if (!_lobby.IsInLobby())
{
LogSystem.LogWarning("[测试] 当前不在房间中");
return;
}
LogSystem.LogInfo("[测试] 离开房间...");
SteamLobbyManager.Instance.LeaveLobby();
_lobby.LeaveLobby();
}
[ContextMenu("发送测试消息")]
public void TestSendMessage()
// 解散房间
public void DisbandLobby()
{
if (!SteamLobbyManager.Instance.IsInLobby)
if (!_lobby.IsInLobby())
{
LogSystem.LogWarning("[测试] 当前不在房间中");
return;
}
if (!_lobby.IsLobbyOwner())
{
LogSystem.LogWarning("[测试] 只有房主可以解散房间");
return;
}
LogSystem.LogInfo("[测试] 解散房间...");
_lobby.DisbandLobby();
}
// 发送测试消息
public void SendMessage()
{
if (!_lobby.IsInLobby())
{
LogSystem.LogWarning("[测试] 当前不在房间中,无法发送消息");
return;
}
string testMessage = $"测试消息 from {CurrentUserName} at {System.DateTime.Now:HH:mm:ss}";
byte[] data = System.Text.Encoding.UTF8.GetBytes(testMessage);
GameNetSender.Instance.BroadcastString(testMessage);
LogSystem.LogInfo($"[测试] 广播消息: {testMessage}");
SteamLobbyManager.Instance.BroadcastMessage(data, true);
}
[ContextMenu("显示在线好友")]
public void TestShowOnlineFriends()
// 显示在线好友
public void ShowOnlineFriends()
{
if (!CanPerformLobbyAction()) return;
var friends = SteamLobbyManager.Instance.GetOnlineFriends();
var friends = _lobby.GetOnlineFriends();
LogSystem.LogInfo($"[测试] 在线好友数量: {friends.Count}");
foreach (var friend in friends)
@ -366,17 +358,49 @@ namespace TH1_Logic.Steam
}
}
[ContextMenu("打开邀请界面")]
public void TestOpenInviteOverlay()
// 打开邀请界面
public void OpenInviteOverlay()
{
if (!SteamLobbyManager.Instance.IsInLobby)
if (!_lobby.IsInLobby())
{
LogSystem.LogWarning("[测试] 当前不在房间中,无法邀请好友");
return;
}
LogSystem.LogInfo("[测试] 打开Steam邀请界面...");
SteamLobbyManager.Instance.OpenInviteOverlay();
_lobby.OpenInviteOverlay();
}
// 邀请好友
public void InviteFriend(CSteamID friendId)
{
if (!_lobby.IsInLobby())
{
LogSystem.LogWarning("[测试] 当前不在房间中,无法邀请好友");
return;
}
LogSystem.LogInfo($"[测试] 邀请好友: {friendId}");
_lobby.InviteFriend(friendId);
}
// 踢出成员
public void KickMember(CSteamID memberId)
{
if (!_lobby.IsInLobby())
{
LogSystem.LogWarning("[测试] 当前不在房间中,无法踢出成员");
return;
}
if (!_lobby.IsLobbyOwner())
{
LogSystem.LogWarning("[测试] 只有房主可以踢出成员");
return;
}
LogSystem.LogInfo($"[测试] 踢出成员: {memberId}");
_lobby.KickMember(memberId);
}
private bool CanPerformLobbyAction()
@ -397,43 +421,5 @@ namespace TH1_Logic.Steam
}
#endregion
#region GUI显示状态
private void OnGUI()
{
if (!enableDebugLog) return;
GUILayout.BeginArea(new Rect(10, 10, 300, 400));
GUILayout.BeginVertical("box");
GUILayout.Label("Steam 测试状态", GUI.skin.label);
GUILayout.Label($"Steam初始化: {(IsSteamInitialized ? "" : "")}");
GUILayout.Label($"用户登录: {(IsLoggedIn ? "" : "")}");
if (IsLoggedIn)
{
GUILayout.Label($"用户: {CurrentUserName}");
GUILayout.Label($"ID: {CurrentUserID}");
}
GUILayout.Space(10);
GUILayout.Label("房间状态", GUI.skin.label);
GUILayout.Label($"当前状态: {SteamLobbyManager.Instance.CurrentState}");
GUILayout.Label($"在房间中: {(SteamLobbyManager.Instance.IsInLobby ? "" : "")}");
GUILayout.Label($"是房主: {(SteamLobbyManager.Instance.IsLobbyOwner ? "" : "")}");
if (SteamLobbyManager.Instance.IsInLobby)
{
GUILayout.Label($"房间ID: {SteamLobbyManager.Instance.CurrentLobby}");
GUILayout.Label($"成员数: {SteamLobbyManager.Instance.GetMemberCount()}/{SteamLobbyManager.Instance.GetMemberLimit()}");
GUILayout.Label($"P2P连接数: {SimpleP2P.Instance.GetConnectionCount()}");
}
GUILayout.EndVertical();
GUILayout.EndArea();
}
#endregion
}
}

View File

@ -37,7 +37,7 @@ namespace Logic.Timeline
// 这里改成直接结算,包含了死亡,包含了经验增长和权利奇观记录
Main.UnitLogic.DamageSettlement(Map, Origin, Target, Dmg, DamageType.ActiveAttack);
//移动过去并更新视野
Main.UnitLogic.MoveTo(Map, Origin, TargetGrid, MoveType.AttackMove);
Main.UnitLogic.MoveTo(Map, Origin, TargetGrid);
}
public override void OnFinished()
@ -57,7 +57,7 @@ namespace Logic.Timeline
public override void Excute()
{
Main.UnitLogic.DamageSettlement(Map, Origin, Target, Dmg, DamageType.ActiveAttack);
Main.UnitLogic.MoveTo(Map, Origin, TargetGrid, MoveType.AttackMove);
Main.UnitLogic.MoveTo(Map, Origin, TargetGrid);
}
public override void OnUpdate(float progressTime)

View File

@ -12,9 +12,9 @@ namespace Logic
{
public interface IUnitLogic
{
bool MoveTo(MapData mapData, UnitData unitData, GridData gridData, MoveType moveType);
void MoveTo(MapData mapData, UnitData unitData, GridData gridData, MoveType moveType);
//unit[uid]移动到grid[pos]
bool Attack(MapData mapData, UnitData unitDataA, UnitData unitDataB, out float duration, bool isMoment=false);
void Attack(MapData mapData, UnitData unitDataA, UnitData unitDataB, out float duration, bool isMoment=false);
//unit[A]攻击unit[B]
void Upgrade(MapData mapData, UnitData unitData);
//unit[uid]升级

View File

@ -10,6 +10,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Animancer;
using Logic.Action;
using Logic.Audio;
using Logic.CrashSight;
using Logic.Skill;
@ -76,14 +77,23 @@ namespace Logic
mapData.GetPlayerDataByUnitId(uid, out var playerData);
return playerData == mapData.PlayerMap.SelfPlayerData;
}
public void MoveTo(MapData mapData, UnitData unitData, GridData gridData)
{
// 攻击行为切换成 Action 驱动
var moveId = new CommonActionId { ActionType = CommonActionType.UnitMove };
var moveAction = new UnitMoveAction(moveId);
var param = new CommonActionParams(mapData, unitData:unitData, gridData:gridData);
param.RefreshParams();
moveAction.CompleteExecute(param, false);
}
//-------- 执行类 --------//
public bool MoveTo(MapData mapData, UnitData unitData, GridData gridData,MoveType moveType)
public void MoveTo(MapData mapData, UnitData unitData, GridData gridData,MoveType moveType)
{
//处理移动目标有单位的情况(return false)
var targetGridUnit = gridData.Unit(mapData);
if (targetGridUnit != null) return false;
if (targetGridUnit != null) return;
mapData.SetUnitIdToGridId(unitData.Id,gridData.Id);
if (mapData == Main.MapData) AchievementDataManager.Instance.OnUnitMove(mapData, unitData, gridData);
@ -119,7 +129,7 @@ namespace Logic
if (!mapData.GetPlayerDataByUnitId(unitData.Id, out var playerData))
{
LogSystem.LogError("unit找不到player");
return false;
return;
}
//如果是盟友的navalbase,且对方有恢复力,则消耗恢复力,恢复该单位所有行动点
@ -160,9 +170,6 @@ namespace Logic
player2.AddAttacker(player1.Id);
Main.PlayerLogic.SetDiplomacyLeague(mapData,player1, player2, DiplomacyState.War);
}
return true;
}
@ -252,16 +259,16 @@ namespace Logic
return false;
}
public bool Attack(MapData mapData, UnitData unit1, UnitData unit2, out float duration, bool isMoment=false)
public void Attack(MapData mapData, UnitData unit1, UnitData unit2, out float duration, bool isMoment=false)
{
duration = 0;
if (!mapData.GetPlayerDataByUnitId(unit1.Id, out var player1)) return false;
if (!mapData.GetPlayerDataByUnitId(unit2.Id, out var player2)) return false;
if (!mapData.GetCityDataByUnitId(unit1.Id, out var city1)) return false;
if (!mapData.GetCityDataByUnitId(unit2.Id, out var city2)) return false;
if (!mapData.GetGridDataByUnitId(unit1.Id, out var grid1)) return false;
if (!mapData.GetGridDataByUnitId(unit2.Id, out var grid2)) return false;
if (unit1.IsLimitSelfAttack(mapData)) return false;
if (!mapData.GetPlayerDataByUnitId(unit1.Id, out var player1)) return;
if (!mapData.GetPlayerDataByUnitId(unit2.Id, out var player2)) return;
if (!mapData.GetCityDataByUnitId(unit1.Id, out var city1)) return;
if (!mapData.GetCityDataByUnitId(unit2.Id, out var city2)) return;
if (!mapData.GetGridDataByUnitId(unit1.Id, out var grid1)) return;
if (!mapData.GetGridDataByUnitId(unit2.Id, out var grid2)) return;
if (unit1.IsLimitSelfAttack(mapData)) return;
foreach (var skill in unit1.Skills) skill.BeforeSelfActiveAttack(mapData, unit1, unit2);
// 计算攻击伤害
@ -323,74 +330,23 @@ namespace Logic
float counterAttackWait = attackBack + Table.Instance.AnimDataAssets.GetAttackTimeByAttackRange(unit2.GetAttackRange())
+ Table.Instance.AnimDataAssets.BetweenAttackCounterAnimTime;
//第一次攻击到对方后返回+对方反击打到我+对方返回的时刻
float counterAttackBack = counterAttackWait +
Table.Instance.AnimDataAssets.GetAttackReturnTimeByAttackRange(
unit2.GetAttackRange());
var attackReturnTime = Table.Instance.AnimDataAssets.GetAttackReturnTimeByAttackRange(unit2.GetAttackRange());
float counterAttackBack = counterAttackWait + attackReturnTime;
if (TestKillUnit(mapData,unit1,unit2,dmg1)) //如果伤害直接够杀死对方
var info1 = Main.UnitLogic.DamageSettlement(mapData, unit1, unit2, dmg1, DamageType.ActiveAttack);
if (info1.IsKill)
{
//攻击+移动:如果是近战且目标位置可以移动过去
if (unit1.GetAttackRange() == 1 && CheckUnitCanMoveToGrid(mapData,player1,unit1,grid2))
if (unit1.GetAttackRange() == 1 && CheckUnitCanMoveToGrid(mapData, player1, unit1, grid2))
{
unit1.AttackRenderMark = false;
var fragment = new MoveKill();
fragment.Map = mapData;
fragment.Duration = Table.Instance.AnimDataAssets.MoveAnimTime;
fragment.Origin = unit1;
fragment.Target = unit2;
fragment.Dmg = dmg1;
fragment.OriginGrid = grid1;
fragment.TargetGrid = grid2;
fragment.OriginPlayer = player1;
fragment.TargetPlayer = player2;
duration = fragment.Duration;
if (isMoment) fragment.Excute();
else TimelineManager.Instance.AddFragment(fragment);
}
else
{
var fragment = new NotMoveKill();
fragment.Map = mapData;
fragment.Duration = attackBack;
fragment.Origin = unit1;
fragment.Target = unit2;
fragment.Dmg = dmg1;
fragment.OriginGrid = grid1;
fragment.TargetGrid = grid2;
fragment.OriginPlayer = player1;
fragment.TargetPlayer = player2;
fragment.AttackTime = attackWait;
fragment.AttackBackTime = attackBack;
duration = fragment.Duration;
if (isMoment) fragment.Excute();
else TimelineManager.Instance.AddFragment(fragment);
Main.UnitLogic.MoveTo(mapData, unit1, grid2, MoveType.AttackMove);
}
}
//如果杀不死对方
else
{
var fragment = new AttackAndCounter();
fragment.Map = mapData;
fragment.Duration = counterAttackBack;
fragment.Origin = unit1;
fragment.Target = unit2;
fragment.Dmg1 = dmg1;
fragment.Dmg2 = dmg2;
fragment.OriginGrid = grid1;
fragment.TargetGrid = grid2;
fragment.OriginPlayer = player1;
fragment.TargetPlayer = player2;
fragment.CanCounter = canCounter;
fragment.AttackAnimTime = Table.Instance.AnimDataAssets.AttackAnimTime;
fragment.CounterAttackStart = counterAttackStart;
fragment.CounterAttackWait = counterAttackWait;
fragment.CounterAttackBack = counterAttackBack;
duration = fragment.Duration;
if (isMoment) fragment.Excute();
else TimelineManager.Instance.AddFragment(fragment);
if (unit1.Health == 0 && unit2.Health == 0) return;
if (mapData.SameUnionByUnitId(unit1.Id, unit2.Id)) return;
Main.UnitLogic.DamageSettlement(mapData, unit2, unit1, dmg2, DamageType.CounterAttack);
}
return true;
}
// 伤害新结算方法所有的掉血都要走此方法不允许直接修改UnitData.Health

View File

@ -7,6 +7,8 @@ using RuntimeData;
using TH1_Core.Events;
using TH1_Core.Managers;
using TH1_Logic.Core;
using TH1_Logic.Net;
using TH1_Logic.Steam;
using TH1Resource;
using UI;
using UI.HintUI;
@ -222,10 +224,14 @@ public class BottomBarUI
private void OnNextTurnClicked()
{
UIManager.Instance.BottomInfoUI.SetBottomInfoHide();
_main.MapInteractionLogic.CancelAllHighlight();
_main.GameLogic.ChangeState(GameState.AIRound);
if (LobbyManager.Instance.Lobby.IsInLobby() && !LobbyManager.Instance.Lobby.IsLobbyOwner())
{
GameNetSender.Instance.TurnEndConfirm();
}
// 单机或者是房主直接切
else _main.GameLogic.ChangeToNextPlayerRound();
}
private void OnMessageClicked()