Merge branch 'main' of http://10.27.17.121:3000/kawagiri/TH1
This commit is contained in:
commit
38175b9004
@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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折
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -36,10 +36,7 @@ namespace Logic.HeroTask
|
||||
[MemoryPackOnDeserialized]
|
||||
public void OnAfterMemoryPackDeserialize()
|
||||
{
|
||||
foreach (var item in Items)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -17,7 +17,7 @@ namespace TH1_Logic.HeroTask
|
||||
{
|
||||
public static HeroTaskManager Instance = new HeroTaskManager();
|
||||
private HeroTaskData _data;
|
||||
|
||||
|
||||
|
||||
public void Init()
|
||||
{
|
||||
|
||||
@ -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)
|
||||
|
||||
3
Unity/Assets/Scripts/TH1_Logic/Net.meta
Normal file
3
Unity/Assets/Scripts/TH1_Logic/Net.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9bd695aa118d4d02a094e6273b9eb9b3
|
||||
timeCreated: 1758014744
|
||||
120
Unity/Assets/Scripts/TH1_Logic/Net/ILobby.cs
Normal file
120
Unity/Assets/Scripts/TH1_Logic/Net/ILobby.cs
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* @Author: 白哉
|
||||
* @Description:
|
||||
* @Date: 2025年09月16日 星期二 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Unity/Assets/Scripts/TH1_Logic/Net/ILobby.cs.meta
Normal file
3
Unity/Assets/Scripts/TH1_Logic/Net/ILobby.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fdb1d9700efa4b579fd60337d47e081d
|
||||
timeCreated: 1758013115
|
||||
22
Unity/Assets/Scripts/TH1_Logic/Net/LobbyManager.cs
Normal file
22
Unity/Assets/Scripts/TH1_Logic/Net/LobbyManager.cs
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* @Author: 白哉
|
||||
* @Description:
|
||||
* @Date: 2025年09月18日 星期四 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Unity/Assets/Scripts/TH1_Logic/Net/LobbyManager.cs.meta
Normal file
3
Unity/Assets/Scripts/TH1_Logic/Net/LobbyManager.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e636e67ebbd640e5bc85057f41dbe1a4
|
||||
timeCreated: 1758165819
|
||||
160
Unity/Assets/Scripts/TH1_Logic/Steam/GameNetReceiver.cs
Normal file
160
Unity/Assets/Scripts/TH1_Logic/Steam/GameNetReceiver.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d8456326f3a49218f670c2f301f954e
|
||||
timeCreated: 1757490238
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
|
||||
67
Unity/Assets/Scripts/TH1_Logic/Steam/SteamGUIMono.cs
Normal file
67
Unity/Assets/Scripts/TH1_Logic/Steam/SteamGUIMono.cs
Normal file
@ -0,0 +1,67 @@
|
||||
#if USE_INPUT
|
||||
|
||||
/*
|
||||
* @Author: 白哉
|
||||
* @Description:
|
||||
* @Date: 2025年09月18日 星期四 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
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 96a3dc180c464f76ab2da78db6827c2a
|
||||
timeCreated: 1758178749
|
||||
@ -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()
|
||||
|
||||
@ -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; }
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
|
||||
@ -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]升级
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user