diff --git a/installer/Data/ConfigFileData.cs b/installer/Data/ConfigFileData.cs index 2d8d466..c7379cc 100644 --- a/installer/Data/ConfigFileData.cs +++ b/installer/Data/ConfigFileData.cs @@ -1,4 +1,6 @@ -//using installer.ViewModel; +//ConfigDataFile.cs + +//using installer.ViewModel; using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; diff --git a/installer/Model/Logger.cs b/installer/Model/Logger.cs index bca38a2..803f435 100644 --- a/installer/Model/Logger.cs +++ b/installer/Model/Logger.cs @@ -1,4 +1,5 @@ -using System.Collections.Concurrent; +//Logger.cs +using System.Collections.Concurrent; using System.Collections.ObjectModel; using System.Collections.Generic; using System.IO; diff --git a/interface/AvaloniaUI_debug_interface/debug_interface/Models/MapCell.cs b/interface/AvaloniaUI_debug_interface/debug_interface/Models/MapCell.cs index 2ff0f9b..6006d95 100644 --- a/interface/AvaloniaUI_debug_interface/debug_interface/Models/MapCell.cs +++ b/interface/AvaloniaUI_debug_interface/debug_interface/Models/MapCell.cs @@ -8,43 +8,43 @@ using System.Text; using System.Threading.Tasks; namespace debug_interface.Models +{ + //internal class MapCell + //{ + //} + // 定义地图单元格的类型,根据游戏规则可包含障碍物、空地、草丛、资源、建筑等 + public enum MapCellType { - //internal class MapCell - //{ - //} - // 定义地图单元格的类型,根据游戏规则可包含障碍物、空地、草丛、资源、建筑等 - public enum MapCellType - { - Obstacle, // 障碍物(例如地图边界或特定阻挡物) - OpenLand, // 空地,角色可自由移动 - Grass, // 草丛,可提供隐蔽效果(决战期后会消失) - Resource, // 资源点(用于开采经济资源) - Building // 建筑(预留,例如兵营、农场等) - } - - // 地图单元类,继承自 ObservableObject 便于数据绑定更新 - public partial class MapCell : ObservableObject - { - // 地图中的行号(0~49) - [ObservableProperty] - private int cellX; - - // 地图中的列号(0~49) - [ObservableProperty] - private int cellY; - - // 当前单元格的类型 - [ObservableProperty] - private MapCellType cellType; - - // 该单元格显示时使用的颜色 - [ObservableProperty] - private SolidColorBrush displayColor; - - // 可选:显示的文字,例如建筑血量、资源进度等 - [ObservableProperty] - private string displayText; - } + Obstacle, // 障碍物(例如地图边界或特定阻挡物) + OpenLand, // 空地,角色可自由移动 + Grass, // 草丛,可提供隐蔽效果(决战期后会消失) + Resource, // 资源点(用于开采经济资源) + Building // 建筑(预留,例如兵营、农场等) } + // 地图单元类,继承自 ObservableObject 便于数据绑定更新 + public partial class MapCell : ObservableObject + { + // 地图中的行号(0~49) + [ObservableProperty] + private int cellX; + + // 地图中的列号(0~49) + [ObservableProperty] + private int cellY; + + // 当前单元格的类型 + [ObservableProperty] + private MapCellType cellType; + + // 该单元格显示时使用的颜色 + [ObservableProperty] + private SolidColorBrush displayColor; + + // 可选:显示的文字,例如建筑血量、资源进度等 + [ObservableProperty] + private string displayText; + } +} + diff --git a/interface/AvaloniaUI_debug_interface/debug_interface/Services/ServerCommunicationService.cs b/interface/AvaloniaUI_debug_interface/debug_interface/Services/ServerCommunicationService.cs new file mode 100644 index 0000000..9c44c59 --- /dev/null +++ b/interface/AvaloniaUI_debug_interface/debug_interface/Services/ServerCommunicationService.cs @@ -0,0 +1,327 @@ +//using System; +//using System.Threading.Tasks; +//using intaller.Data; +//using installer.Utils; +//using debug_interface.Utils; +//using THUAI8.Proto; // 确保这是你实际的Proto命名空间 + +//namespace debug_interface.Services +//{ +// public class ServerCommunicationService +// { +// private readonly DebugConfig _config; +// private readonly Logger _logger; +// private Channel _channel; +// private DebugInterface.DebugInterfaceClient _client; // 使用你的Proto定义的客户端类 +// private AsyncServerStreamingCall _responseStream; +// private bool _isConnected = false; +// private bool _isSpectatorMode = false; + +// public ServerCommunicationService( +// IConfiguration configuration, +// Logger logger) +// { +// _config = configuration.GetSection("DebugConfig").Get(); +// _logger = logger; +// } + +// public bool IsConnected => _isConnected; + +// public async Task ConnectToServer() +// { +// try +// { +// string ip = _config.Commands.IP; +// string port = _config.Commands.Port; +// long playerID = long.Parse(_config.Commands.PlayerID); +// long teamID = long.Parse(_config.Commands.TeamID); + +// _logger.LogInfo($"正在连接到服务器 {ip}:{port}"); +// _logger.LogInfo($"玩家ID: {playerID}, 队伍ID: {teamID}"); + +// if (playerID > 2023) +// { +// _isSpectatorMode = true; +// _logger.LogInfo("启用观察者模式"); +// } + +// // 创建连接地址 +// string connect = $"{ip}:{port}"; +// _logger.LogInfo($"创建gRPC通道: {connect}"); + +// // 创建Channel +// _channel = new Channel(connect, ChannelCredentials.Insecure); + +// // 创建客户端 +// _client = new DebugInterface.DebugInterfaceClient(_channel); +// _logger.LogInfo("创建gRPC客户端成功"); + +// // 创建玩家消息 +// PlayerMsg playerMsg = new PlayerMsg(); +// playerMsg.PlayerId = playerID; +// playerMsg.TeamId = teamID; + +// // 如果不是观察者模式,设置附加信息 +// if (!_isSpectatorMode) +// { +// // 设置Ship类型等信息 +// int shipTypeID = int.Parse(_config.Commands.ShipType); +// ShipType shipType = (ShipType)shipTypeID; +// playerMsg.ShipType = shipType; +// _logger.LogInfo($"玩家舰船类型: {shipType}"); +// } + +// // 连接到服务器 +// _logger.LogInfo("尝试连接服务器..."); +// _responseStream = _client.AddPlayer(playerMsg); +// _logger.LogInfo("成功获取服务器响应流"); + +// _isConnected = true; +// _logger.LogInfo("成功连接到服务器!"); + +// // 开始接收服务器消息 +// StartReceivingMessages(); +// } +// catch (RpcException ex) +// { +// _isConnected = false; +// _logger.LogError($"gRPC连接错误: {ex.Status.Detail}"); +// _logger.LogError($"错误状态码: {ex.Status.StatusCode}"); +// } +// catch (Exception ex) +// { +// _isConnected = false; +// _logger.LogError($"连接失败: {ex.Message}"); +// _logger.LogError($"异常类型: {ex.GetType().FullName}"); +// if (ex.InnerException != null) +// { +// _logger.LogError($"内部异常: {ex.InnerException.Message}"); +// } +// } +// } + +// private async void StartReceivingMessages() +// { +// try +// { +// _logger.LogInfo("开始接收服务器消息..."); + +// while (_responseStream != null && await _responseStream.ResponseStream.MoveNext()) +// { +// _logger.LogInfo("收到服务器消息"); + +// // 获取当前消息 +// MessageToClient message = _responseStream.ResponseStream.Current; + +// // 处理游戏状态 +// switch (message.GameState) +// { +// case GameState.GameStart: +// _logger.LogInfo("游戏开始"); +// ProcessGameStart(message); +// break; + +// case GameState.GameRunning: +// _logger.LogInfo("游戏运行中"); +// ProcessGameRunning(message); +// break; + +// case GameState.GameEnd: +// _logger.LogInfo("游戏结束"); +// ProcessGameEnd(message); +// break; +// } +// } + +// _logger.LogInfo("服务器消息流结束"); +// } +// catch (Exception ex) +// { +// _logger.LogError($"接收消息时发生错误: {ex.Message}"); +// _isConnected = false; +// } +// } + +// private void ProcessGameStart(MessageToClient message) +// { +// try +// { +// _logger.LogInfo("处理游戏开始消息"); + +// // 处理对象消息 +// foreach (var obj in message.ObjMessage) +// { +// ProcessObjectMessage(obj); +// } + +// // 处理全局消息 +// _logger.LogInfo($"红方能量: {message.AllMessage.RedTeamEnergy}, 蓝方能量: {message.AllMessage.BlueTeamEnergy}"); +// _logger.LogInfo($"红方血量: {message.AllMessage.RedHomeHp}, 蓝方血量: {message.AllMessage.BlueHomeHp}"); +// _logger.LogInfo($"红方分数: {message.AllMessage.RedTeamScore}, 蓝方分数: {message.AllMessage.BlueTeamScore}"); +// } +// catch (Exception ex) +// { +// _logger.LogError($"处理游戏开始消息时发生错误: {ex.Message}"); +// } +// } + +// private void ProcessGameRunning(MessageToClient message) +// { +// try +// { +// _logger.LogInfo("处理游戏运行消息"); + +// // 处理对象消息 +// foreach (var obj in message.ObjMessage) +// { +// ProcessObjectMessage(obj); +// } + +// // 处理全局消息 +// _logger.LogInfo($"红方能量: {message.AllMessage.RedTeamEnergy}, 蓝方能量: {message.AllMessage.BlueTeamEnergy}"); +// } +// catch (Exception ex) +// { +// _logger.LogError($"处理游戏运行消息时发生错误: {ex.Message}"); +// } +// } + +// private void ProcessGameEnd(MessageToClient message) +// { +// try +// { +// _logger.LogInfo("处理游戏结束消息"); + +// // 处理对象消息 +// foreach (var obj in message.ObjMessage) +// { +// ProcessObjectMessage(obj); +// } + +// // 处理全局消息 +// _logger.LogInfo($"红方最终分数: {message.AllMessage.RedTeamScore}, 蓝方最终分数: {message.AllMessage.BlueTeamScore}"); +// } +// catch (Exception ex) +// { +// _logger.LogError($"处理游戏结束消息时发生错误: {ex.Message}"); +// } +// } + +// private void ProcessObjectMessage(MessageOfObj obj) +// { +// try +// { +// switch (obj.MessageOfObjCase) +// { +// case MessageOfObj.MessageOfObjOneofCase.ShipMessage: +// _logger.LogInfo($"舰船位置: ({obj.ShipMessage.X}, {obj.ShipMessage.Y})"); +// break; + +// case MessageOfObj.MessageOfObjOneofCase.MapMessage: +// _logger.LogInfo("收到地图信息"); +// break; + +// case MessageOfObj.MessageOfObjOneofCase.BulletMessage: +// _logger.LogInfo($"子弹位置: ({obj.BulletMessage.X}, {obj.BulletMessage.Y})"); +// break; + +// // 可以添加其他消息类型的处理 +// } +// } +// catch (Exception ex) +// { +// _logger.LogError($"处理对象消息时发生错误: {ex.Message}"); +// } +// } + +// public async Task DisconnectFromServer() +// { +// if (!_isConnected) return; + +// try +// { +// _logger.LogInfo("正在断开服务器连接..."); + +// // 关闭响应流 +// _responseStream?.Dispose(); + +// // 关闭通道 +// if (_channel != null) +// { +// await _channel.ShutdownAsync(); +// } + +// _isConnected = false; +// _logger.LogInfo("已断开服务器连接"); +// } +// catch (Exception ex) +// { +// _logger.LogError($"断开连接时发生错误: {ex.Message}"); +// } +// } + +// public async Task SendCommand(string command) +// { +// if (!_isConnected || _client == null) +// { +// _logger.LogWarning("无法发送命令:未连接到服务器"); +// return; +// } + +// try +// { +// _logger.LogInfo($"发送命令: {command}"); + +// // 这里需要根据实际的Proto定义来实现命令发送 +// // 以下代码仅作为示例 +// if (command.StartsWith("move")) +// { +// string direction = command.Substring(5); +// double angle = 0; + +// switch (direction.ToLower()) +// { +// case "up": angle = Math.PI; break; +// case "down": angle = 0; break; +// case "left": angle = Math.PI * 3 / 2; break; +// case "right": angle = Math.PI / 2; break; +// } + +// MoveMsg moveMsg = new MoveMsg +// { +// PlayerId = long.Parse(_config.Commands.PlayerID), +// TeamId = long.Parse(_config.Commands.TeamID), +// Angle = angle, +// TimeInMilliseconds = 100 +// }; + +// await _client.MoveAsync(moveMsg); +// _logger.LogInfo("移动命令已发送"); +// } +// else if (command.StartsWith("attack")) +// { +// AttackMsg attackMsg = new AttackMsg +// { +// PlayerId = long.Parse(_config.Commands.PlayerID), +// TeamId = long.Parse(_config.Commands.TeamID), +// Angle = 0 // 或者根据需要设置角度 +// }; + +// await _client.AttackAsync(attackMsg); +// _logger.LogInfo("攻击命令已发送"); +// } +// // 添加其他命令的处理 +// } +// catch (Exception ex) +// { +// _logger.LogError($"发送命令时发生错误: {ex.Message}"); +// } +// } + +// public void CleanUp() +// { +// _responseStream?.Dispose(); +// _channel?.Dispose(); +// } +// } +//} \ No newline at end of file diff --git a/interface/AvaloniaUI_debug_interface/debug_interface/ViewModels/ViewModelBase.cs b/interface/AvaloniaUI_debug_interface/debug_interface/ViewModels/ViewModelBase.cs index 55100f6..8a1edbf 100644 --- a/interface/AvaloniaUI_debug_interface/debug_interface/ViewModels/ViewModelBase.cs +++ b/interface/AvaloniaUI_debug_interface/debug_interface/ViewModels/ViewModelBase.cs @@ -1,30 +1,31 @@ //ViewModeBase.cs using System; -using System.Collections.Generic; -using System.Threading.Tasks; + using Avalonia.Threading; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using debug_interface.Models; using Google.Protobuf; +using Protobuf; using Grpc.Core; -//using installer; -//using installer.Model; + +using installer.Model; +using installer.Data; using Avalonia.Controls.Shapes; using Avalonia.Logging; -using System.Threading.Channels; + namespace debug_interface.ViewModels { - public class ViewModelBase : ObservableObject + public partial class ViewModelBase : ObservableObject { // 用于 UI 刷新的定时器(Avalonia 的 DispatcherTimer) private DispatcherTimer timerViewModel; private int counterViewModelTest = 0; // 使用 CommunityToolkit 的 ObservableProperty 自动实现 INotifyPropertyChanged - //[ObservableProperty] - //private string title; + [ObservableProperty] + private string title; //private MapPatch testPatch; //public MapPatch TestPatch @@ -48,286 +49,64 @@ namespace debug_interface.ViewModels private long teamID; //private ShipType shipType; - //private AvailableService.AvailableServiceClient? client; - //private AsyncServerStreamingCall? responseStream; + private AvailableService.AvailableServiceClient? client; + private AsyncServerStreamingCall? responseStream; private bool isSpectatorMode = false; private bool isPlaybackMode = false; // 用于存储上次移动角度(示例,仅作为参考) private double lastMoveAngle; - // 日志记录(保持你原来的 Logger 类) + // 日志记录 //public Logger myLogger; //public Logger lockGenerator; - // 以下定义各个操作的命令(基于 CommunityToolkit.Mvvm.Input 的 RelayCommand) - public RelayCommand MoveUpCommand { get; } - public RelayCommand MoveDownCommand { get; } - public RelayCommand MoveLeftCommand { get; } - public RelayCommand MoveRightCommand { get; } - public RelayCommand MoveLeftUpCommand { get; } - public RelayCommand MoveRightUpCommand { get; } - public RelayCommand MoveLeftDownCommand { get; } - public RelayCommand MoveRightDownCommand { get; } - public RelayCommand AttackCommand { get; } - public RelayCommand RecoverCommand { get; } - public RelayCommand ProduceCommand { get; } - public RelayCommand ConstructCommand { get; } public ViewModelBase() { - //Title = "THUAI8; + title = "THUAI8"; // 读取配置(假设 ConfigData 类来自 installer.Data 命名空间) - //var d = new installer.Data.ConfigData(); - //ip = d.Commands.IP; - //port = d.Commands.Port; - //playerID = Convert.ToInt64(d.Commands.PlayerID); - //teamID = Convert.ToInt64(d.Commands.TeamID); + var d = new installer.Data.ConfigData(); + ip = d.Commands.IP; + port = d.Commands.Port; + playerID = Convert.ToInt64(d.Commands.PlayerID); + teamID = Convert.ToInt64(d.Commands.TeamID); //shipTypeID = Convert.ToInt32(d.Commands.ShipType); - //string playbackFile = d.Commands.PlaybackFile; - //double playbackSpeed = d.Commands.PlaybackSpeed; + string playbackFile = d.Commands.PlaybackFile; + double playbackSpeed = d.Commands.PlaybackSpeed; - // 初始化日志记录器 + //初始化日志记录器 //myLogger = LoggerProvider.FromFile(System.IO.Path.Combine(d.InstallPath, "Logs", $"Client.{teamID}.{playerID}.log")); //lockGenerator = LoggerProvider.FromFile(System.IO.Path.Combine(d.InstallPath, "Logs", $"lock.{teamID}.{playerID}.log")); - // 初始化命令:这里仅示例了部分命令,其他命令同理 - MoveUpCommand = new RelayCommand(() => - { - //if (client == null || isSpectatorMode || isPlaybackMode) - //{ - // myLogger.LogInfo("Client is null or in Spectator/Playback mode"); - // return; - //} - //// 构造移动消息,这里采用 gRPC 的消息格式(注意:根据你的 proto 定义,字段名称可能有所不同) - //MoveMsg movemsg = new MoveMsg - //{ - // character_id = playerID, - // team_id = teamID, - // angle = Math.PI, - // time_in_milliseconds = 50 - //}; - //lastMoveAngle = movemsg.angle; - //client.Move(movemsg); - }); - MoveDownCommand = new RelayCommand(() => - { - //if (client == null || isSpectatorMode || isPlaybackMode) - //{ - // myLogger.LogInfo("Client is null or in Spectator/Playback mode"); - // return; - //} - //MoveMsg movemsg = new MoveMsg - //{ - // character_id = playerID, - // team_id = teamID, - // // 这里使用 0 表示“负零” - // angle = 0, - // time_in_milliseconds = 100 - //}; - //lastMoveAngle = movemsg.angle; - //client.Move(movemsg); - }); - - MoveLeftCommand = new RelayCommand(() => - { - //if (client == null || isSpectatorMode || isPlaybackMode) - //{ - // myLogger.LogInfo("Client is null or in Spectator/Playback mode"); - // return; - //} - //MoveMsg movemsg = new MoveMsg - //{ - // character_id = playerID, - // team_id = teamID, - // angle = Math.PI * 3 / 2, - // time_in_milliseconds = 100 - //}; - //lastMoveAngle = movemsg.angle; - //client.Move(movemsg); - }); - - MoveRightCommand = new RelayCommand(() => - { - //if (client == null || isSpectatorMode || isPlaybackMode) - //{ - // myLogger.LogInfo("Client is null or in Spectator/Playback mode"); - // return; - //} - //MoveMsg movemsg = new MoveMsg - //{ - // character_id = playerID, - // team_id = teamID, - // angle = Math.PI / 2, - // time_in_milliseconds = 100 - //}; - //lastMoveAngle = movemsg.angle; - //client.Move(movemsg); - }); - - MoveLeftUpCommand = new RelayCommand(() => - { - //if (client == null || isSpectatorMode || isPlaybackMode) - //{ - // myLogger.LogInfo("Client is null or in Spectator/Playback mode"); - // return; - //} - //MoveMsg movemsg = new MoveMsg - //{ - // character_id = playerID, - // team_id = teamID, - // angle = Math.PI * 5 / 4, - // time_in_milliseconds = 100 - //}; - //lastMoveAngle = movemsg.angle; - //client.Move(movemsg); - }); - - MoveRightUpCommand = new RelayCommand(() => - { - //if (client == null || isSpectatorMode || isPlaybackMode) - //{ - // myLogger.LogInfo("Client is null or in Spectator/Playback mode"); - // return; - //} - //MoveMsg movemsg = new MoveMsg - //{ - // character_id = playerID, - // team_id = teamID, - // angle = Math.PI * 3 / 4, - // time_in_milliseconds = 100 - //}; - //lastMoveAngle = movemsg.angle; - //client.Move(movemsg); - }); - - MoveLeftDownCommand = new RelayCommand(() => - { - //if (client == null || isSpectatorMode || isPlaybackMode) - //{ - // myLogger.LogInfo("Client is null or in Spectator/Playback mode"); - // return; - //} - //MoveMsg movemsg = new MoveMsg - //{ - // character_id = playerID, - // team_id = teamID, - // angle = Math.PI * 7 / 4, - // time_in_milliseconds = 100 - //}; - //lastMoveAngle = movemsg.angle; - //client.Move(movemsg); - }); - - MoveRightDownCommand = new RelayCommand(() => - { - //if (client == null || isSpectatorMode || isPlaybackMode) - //{ - // myLogger.LogInfo("Client is null or in Spectator/Playback mode"); - // return; - //} - //MoveMsg movemsg = new MoveMsg - //{ - // character_id = playerID, - // team_id = teamID, - // angle = Math.PI / 4, - // time_in_milliseconds = 100 - //}; - //lastMoveAngle = movemsg.angle; - //client.Move(movemsg); - }); - - AttackCommand = new RelayCommand(() => - { - //if (client == null || isSpectatorMode || isPlaybackMode) - //{ - // myLogger.LogInfo("Client is null or in Spectator/Playback mode"); - // return; - //} - //AttackMsg attackMsg = new AttackMsg - //{ - // character_id = playerID, - // team_id = teamID, - // attack_range = 50, // 示例值,根据实际情况修改 - // attacked_character_id = 0 // 示例目标ID - //}; - //client.Attack(attackMsg); - }); - - RecoverCommand = new RelayCommand(() => - { - //if (client == null || isSpectatorMode || isPlaybackMode) - //{ - // myLogger.LogInfo("Client is null or in Spectator/Playback mode"); - // return; - //} - //RecoverMsg recoverMsg = new RecoverMsg - //{ - // character_id = playerID, - // recovered_hp = 10, // 示例数值 - // team_id = teamID - //}; - //client.Recover(recoverMsg); - }); - - ProduceCommand = new RelayCommand(() => - { - //if (client == null || isSpectatorMode || isPlaybackMode) - //{ - // myLogger.LogInfo("Client is null or in Spectator/Playback mode"); - // return; - //} - //// 此处 Produce 可使用对应的 gRPC 方法(例如 Equip 或其他你定义的生产逻辑) - //IDMsg idMsg = new IDMsg - //{ - // character_id = playerID, - // team_id = teamID - //}; - //client.Equip(idMsg); - }); - - ConstructCommand = new RelayCommand(() => - { - //if (client == null || isSpectatorMode || isPlaybackMode) - //{ - // myLogger.LogInfo("Client is null or in Spectator/Playback mode"); - // return; - //} - //ConstructMsg constructMsg = new ConstructMsg - //{ - // character_id = playerID, - // team_id = teamID, - // construction_type = ConstructionType.BARRACKS // 示例建筑类型 - //}; - //client.Construct(constructMsg); - }); // 使用 Avalonia 的 DispatcherTimer 定时刷新 UI timerViewModel = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(50) }; timerViewModel.Tick += Refresh; timerViewModel.Start(); - // 判断是否走回放模式 - //if (string.IsNullOrEmpty(d.Commands.PlaybackFile)) - //{ - // string[] comInfo = new string[] - // { - // ip, - // port, - // Convert.ToString(playerID), - // Convert.ToString(teamID), - // Convert.ToString(shipTypeID), - // }; - // ConnectToServer(comInfo); - // OnReceive(); - //} - //else - //{ - // myLogger.LogInfo($"PlaybackFile: {d.Commands.PlaybackFile}"); - // Playback(d.Commands.PlaybackFile, playbackSpeed); - //} + //判断是否走回放模式 + if (string.IsNullOrEmpty(d.Commands.PlaybackFile)) + { + string[] comInfo = new string[] + { + ip, + port, + Convert.ToString(playerID), + Convert.ToString(teamID), + Convert.ToString(0), + }; + + ConnectToServer(comInfo); + OnReceive(); + } + else + { + //myLogger.LogInfo($"PlaybackFile: {d.Commands.PlaybackFile}"); + //Playback(d.Commands.PlaybackFile, playbackSpeed); + } } /// @@ -336,38 +115,38 @@ namespace debug_interface.ViewModels /// 包含 ip、port、playerID、teamID、shipTypeID 的数组 public void ConnectToServer(string[] comInfo) { - //if (isPlaybackMode) return; - //if (Convert.ToInt64(comInfo[2]) > 2023) - //{ - // isSpectatorMode = true; - // myLogger.LogInfo("isSpectatorMode = true"); - //} - //if (comInfo.Length != 5) - //{ - // throw new Exception("Error Registration Information!"); - //} + if (isPlaybackMode) return; + if (Convert.ToInt64(comInfo[2]) > 2023) + { + isSpectatorMode = true; + //myLogger.LogInfo("isSpectatorMode = true"); + } + if (comInfo.Length != 5) + { + throw new Exception("Error Registration Information!"); + } - //string connect = $"{comInfo[0]}:{comInfo[1]}"; - //Channel channel = new Channel(connect, ChannelCredentials.Insecure); - //client = new AvailableService.AvailableServiceClient(channel); - //PlayerMsg playerMsg = new PlayerMsg(); - //playerID = Convert.ToInt64(comInfo[2]); - //playerMsg.PlayerId = playerID; - //if (!isSpectatorMode) - //{ - // teamID = Convert.ToInt64(comInfo[3]); - // playerMsg.TeamId = teamID; - // shipType = Convert.ToInt64(comInfo[4]) switch - // { - // 0 => ShipType.NullShipType, - // 1 => ShipType.CivilianShip, - // 2 => ShipType.MilitaryShip, - // 3 => ShipType.FlagShip, - // _ => ShipType.NullShipType - // }; - // playerMsg.ShipType = shipType; - //} - //responseStream = client.AddPlayer(playerMsg); + string connect = $"{comInfo[0]}:{comInfo[1]}"; + Channel channel = new Channel(connect, ChannelCredentials.Insecure); + client = new AvailableService.AvailableServiceClient(channel); + CharacterMsg playerMsg = new CharacterMsg(); + playerID = Convert.ToInt64(comInfo[2]); + playerMsg.CharacterId = playerID; + if (!isSpectatorMode) + { + teamID = Convert.ToInt64(comInfo[3]); + playerMsg.TeamId = teamID; + //shipType = Convert.ToInt64(comInfo[4]) switch + //{ + // 0 => ShipType.NullShipType, + // 1 => ShipType.CivilianShip, + // 2 => ShipType.MilitaryShip, + // 3 => ShipType.FlagShip, + // _ => ShipType.NullShipType + //}; + playerMsg.CharacterType = CharacterType.TangSeng; + } + responseStream = client.AddCharacter(playerMsg); } /// diff --git a/interface/AvaloniaUI_debug_interface/debug_interface/Views/MainWindow.axaml b/interface/AvaloniaUI_debug_interface/debug_interface/Views/MainWindow.axaml index bc3fa31..83e6551 100644 --- a/interface/AvaloniaUI_debug_interface/debug_interface/Views/MainWindow.axaml +++ b/interface/AvaloniaUI_debug_interface/debug_interface/Views/MainWindow.axaml @@ -4,8 +4,8 @@ xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:debug_interface.Views" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="using:debug_interface.ViewModels" x:Name="MainWindowElement" Title="THUAI8 调试界面" @@ -207,10 +207,7 @@ - + @@ -248,14 +245,14 @@ - - - - - + + + + + diff --git a/interface/AvaloniaUI_debug_interface/debug_interface/Views/MainWindow.axaml.cs b/interface/AvaloniaUI_debug_interface/debug_interface/Views/MainWindow.axaml.cs index f8f7d10..dc76b90 100644 --- a/interface/AvaloniaUI_debug_interface/debug_interface/Views/MainWindow.axaml.cs +++ b/interface/AvaloniaUI_debug_interface/debug_interface/Views/MainWindow.axaml.cs @@ -4,8 +4,8 @@ using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace debug_interface.Views -{ - +{ + //public partial class MainWindow : Window //{ // public MainWindow() diff --git a/interface/AvaloniaUI_debug_interface/debug_interface/Views/MapView.axaml b/interface/AvaloniaUI_debug_interface/debug_interface/Views/MapView.axaml index b7ac18f..9384744 100644 --- a/interface/AvaloniaUI_debug_interface/debug_interface/Views/MapView.axaml +++ b/interface/AvaloniaUI_debug_interface/debug_interface/Views/MapView.axaml @@ -9,11 +9,11 @@ xmlns:vm="using:debug_interface.ViewModels" mc:Ignorable="d"> - - - + + + - - - + + + \ No newline at end of file diff --git a/interface/AvaloniaUI_debug_interface/debug_interface/Views/MapView.axaml.cs b/interface/AvaloniaUI_debug_interface/debug_interface/Views/MapView.axaml.cs index 2c33bc6..08dd7be 100644 --- a/interface/AvaloniaUI_debug_interface/debug_interface/Views/MapView.axaml.cs +++ b/interface/AvaloniaUI_debug_interface/debug_interface/Views/MapView.axaml.cs @@ -144,65 +144,159 @@ namespace debug_interface.Views { if (characterCanvas == null) return; + //bool isRedTeam = color.Equals(Colors.Red); + + //// ״ѡ - ʹԲΣʹ + //for (int i = 0; i < characters.Count; i++) + //{ + // var character = characters[i]; + + // // - ڶλ + // var container = new Canvas + // { + // Width = 16, + // Height = 16, + // Tag = character + // }; + + // Control characterShape; + + // if (isRedTeam) + // { + // // ʹԲ + // characterShape = new Ellipse + // { + // Width = 14, + // Height = 14, + // Fill = new SolidColorBrush(color) { Opacity = 0.7 }, + // Stroke = Brushes.White, + // StrokeThickness = 1 + // }; + // } + // else + // { + // // ʹ + // characterShape = new Rectangle + // { + // Width = 14, + // Height = 14, + // Fill = new SolidColorBrush(color) { Opacity = 0.7 }, + // Stroke = Brushes.White, + // StrokeThickness = 1 + // }; + // } + + // // ״ + // Canvas.SetLeft(characterShape, 1); + // Canvas.SetTop(characterShape, 1); + // container.Children.Add(characterShape); + + // // ӱʶ - ʹòͬķʽʶڲĽɫ + // var identifier = new TextBlock + // { + // Text = (i + 1).ToString(), + // FontSize = 8, + // Foreground = Brushes.White, + // HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, + // VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center + // }; + + // // Ϊʶӱǿɶ + // var textContainer = new Border + // { + // Child = identifier, + // Width = 14, + // Height = 14, + // Background = Brushes.Transparent, + // HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, + // VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center + // }; + + // Canvas.SetLeft(textContainer, 1); + // Canvas.SetTop(textContainer, 1); + // container.Children.Add(textContainer); + + // // ӹʾʾϸϢ + // var tooltip = new ToolTip + // { + // // ʹýɫķԣȷԷ + // Content = new TextBlock { Text = $"{(isRedTeam ? "" : "")} ɫ {i + 1}" } + // }; + // ToolTip.SetTip(container, tooltip); + + // // ӵ + // characterCanvas.Children.Add(container); + // characterElements[character.Name] = container; + + // // ʼλ - Ժ + + // Canvas.SetLeft(container, i*i * i*i); + // Canvas.SetTop(container, i*i * i * i ); + //} + ///////////////////////////////////// + ///////////////////////////////////// + //////////////////////////////////// for (int i = 0; i < characters.Count; i++) { - var character = characters[i]; - var id = color == Colors.Red ? $"red_{i}" : $"blue_{i}"; - - // һGridΪ߿ı/ͼ - var grid = new Grid { - Width = 15, - Height = 15, - }; + var character = characters[i]; + var id = color == Colors.Red ? $"red_{i}" : $"blue_{i}"; - // ɫ߿Բ - var borderellipse = new Ellipse - { - Width = 15, - Height = 15, - Fill = new SolidColorBrush(Colors.White), // ɫ - Stroke = new SolidColorBrush(color), // ɫ߿ - StrokeThickness = 2, - Tag = character.Name, - }; - - grid.Children.Add(borderellipse); - - // ===== ѡ1: ʾֱ ===== - // Ҫֱţע͵δ - //var textBlock = new TextBlock - //{ - // Text = (i + 1).ToString(), // ʹñ(1ʼ) - // HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, - // VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, - // FontSize = 8, - // Foreground = new SolidColorBrush(color), // ıɫɫһ - // FontWeight = FontWeight.Bold, - //}; - //grid.Children.Add(textBlock); - - // ʾϢ - ToolTip.SetTip(grid, character.Name); - - // óʼλ - Canvas.SetLeft(grid, character.PosY * 15); - Canvas.SetTop(grid, character.PosX * 15); - - characterCanvas.Children.Add(grid); - - // 洢Gridֵ - characterElements[id] = grid; - - // ԸĴ - character.PropertyChanged += (s, e) => - { - if (e.PropertyName == nameof(CharacterViewModel.PosX) || e.PropertyName == nameof(CharacterViewModel.PosY)) + // һGridΪ߿ı/ͼ + var grid = new Grid { - // Gridλ - UpdateCharacterPosition(grid, character.PosX, character.PosY); - } - }; + Width = 15, + Height = 15, + }; + + // ɫ߿Բ + var borderellipse = new Ellipse + { + Width = 15, + Height = 15, + Fill = new SolidColorBrush(Colors.White), // ɫ + Stroke = new SolidColorBrush(color), // ɫ߿ + StrokeThickness = 2, + Tag = character.Name, + }; + + grid.Children.Add(borderellipse); + + // ===== ѡ1: ʾֱ ===== + // Ҫֱţע͵δ + var textBlock = new TextBlock + { + Text = (i + 1).ToString(), // ʹñ(1ʼ) + HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, + VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, + FontSize = 8, + Foreground = new SolidColorBrush(color), // ıɫɫһ + FontWeight = FontWeight.Bold, + }; + //grid.Children.Add(textBlock); + + // ʾϢ + ToolTip.SetTip(grid, character.Name); + + // óʼλ + Canvas.SetLeft(grid, character.PosY * 15); + Canvas.SetTop(grid, character.PosX * 15); + + characterCanvas.Children.Add(grid); + + // 洢Gridֵ + characterElements[id] = grid; + + // ԸĴ + character.PropertyChanged += (s, e) => + { + if (e.PropertyName == nameof(CharacterViewModel.PosX) || e.PropertyName == nameof(CharacterViewModel.PosY)) + { + // Gridλ + UpdateCharacterPosition(grid, character.PosX, character.PosY); + } + }; + } } } @@ -226,5 +320,77 @@ namespace debug_interface.Views // When collection changes, refresh all characters for simplicity RefreshCharacters(); } + + + public void UpdateCharacterPosition(long characterId, int x, int y, bool isRedTeam, string name) + { + // нɫǻ򴴽± + var marker = FindCharacterMarker(characterId); + + if (marker == null) + { + // ½ɫ + marker = new Ellipse + { + Width = 10, + Height = 10, + Fill = new SolidColorBrush(isRedTeam ? Colors.Red : Colors.Blue), + Tag = characterId + }; + + // ıǩ + var label1 = new TextBlock + { + Text = name, + FontSize = 8, + Foreground = new SolidColorBrush(Colors.White) + }; + + // ӵ + CharacterCanvas.Children.Add(marker); + CharacterCanvas.Children.Add(label1); + } + + // λ + double cellWidth = CharacterCanvas.Bounds.Width / 50; + double cellHeight = CharacterCanvas.Bounds.Height / 50; + + Canvas.SetLeft(marker, y * cellWidth + cellWidth / 2 - marker.Width / 2); + Canvas.SetTop(marker, x * cellHeight + cellHeight / 2 - marker.Height / 2); + + // ±ǩλ + var label = FindCharacterLabel(characterId); + if (label != null) + { + Canvas.SetLeft(label, y * cellWidth + cellWidth / 2 - label.Bounds.Width / 2); + Canvas.SetTop(label, x * cellHeight + cellHeight / 2 + marker.Height); + } + } + + private Ellipse FindCharacterMarker(long characterId) + { + foreach (var child in CharacterCanvas.Children) + { + if (child is Ellipse ellipse && (long?)ellipse.Tag == characterId) + { + return ellipse; + } + } + return null; + } + + private TextBlock FindCharacterLabel(long characterId) + { + var marker = FindCharacterMarker(characterId); + if (marker == null) return null; + + int index = CharacterCanvas.Children.IndexOf(marker); + if (index >= 0 && index + 1 < CharacterCanvas.Children.Count && + CharacterCanvas.Children[index + 1] is TextBlock label) + { + return label; + } + return null; + } } } \ No newline at end of file diff --git a/interface/AvaloniaUI_debug_interface/debug_interface/debug_interface.csproj b/interface/AvaloniaUI_debug_interface/debug_interface/debug_interface.csproj index 557318c..b400419 100644 --- a/interface/AvaloniaUI_debug_interface/debug_interface/debug_interface.csproj +++ b/interface/AvaloniaUI_debug_interface/debug_interface/debug_interface.csproj @@ -1,22 +1,24 @@  - - WinExe - net8.0-windows - enable - true - app.manifest - true - debug_interface - - - - - + + WinExe + net8.0-windows + enable + true + app.manifest + true + debug_interface + - + + + + + Protos\%(RecursiveDir)%(Filename)%(Extension) + + @@ -28,28 +30,32 @@ - - - - - - - - - None - All - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - + + + + + + + + None + All + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + diff --git a/interface/AvaloniaUI_debug_interface/debug_interface/debug_interface.sln b/interface/AvaloniaUI_debug_interface/debug_interface/debug_interface.sln index d738b5d..25f3cbb 100644 --- a/interface/AvaloniaUI_debug_interface/debug_interface/debug_interface.sln +++ b/interface/AvaloniaUI_debug_interface/debug_interface/debug_interface.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 17.11.35219.272 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "debug_interface", "debug_interface.csproj", "{4F12E13F-A324-4E71-8003-DB2D5C8C4643}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Proto", "..\..\..\dependency\proto\Proto.csproj", "{B6C305C4-ACFA-467E-9408-9617886B7D4D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +17,10 @@ Global {4F12E13F-A324-4E71-8003-DB2D5C8C4643}.Debug|Any CPU.Build.0 = Debug|Any CPU {4F12E13F-A324-4E71-8003-DB2D5C8C4643}.Release|Any CPU.ActiveCfg = Release|Any CPU {4F12E13F-A324-4E71-8003-DB2D5C8C4643}.Release|Any CPU.Build.0 = Release|Any CPU + {B6C305C4-ACFA-467E-9408-9617886B7D4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B6C305C4-ACFA-467E-9408-9617886B7D4D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B6C305C4-ACFA-467E-9408-9617886B7D4D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B6C305C4-ACFA-467E-9408-9617886B7D4D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/logic/ClientTest/Program.cs b/logic/ClientTest/Program.cs index c137a10..87691d0 100644 --- a/logic/ClientTest/Program.cs +++ b/logic/ClientTest/Program.cs @@ -7,14 +7,26 @@ namespace ClientTest { public static Task Main(string[] args) { + if (!int.TryParse(args[0], out int characterId)) + { + Console.WriteLine("Invalid CharacterId. Please provide a valid integer."); + return Task.CompletedTask; + } + + if (!int.TryParse(args[1], out int teamId)) + { + Console.WriteLine("Invalid TeamId. Please provide a valid integer."); + return Task.CompletedTask; + } Thread.Sleep(3000); Channel channel = new("127.0.0.1:8888", ChannelCredentials.Insecure); var client = new AvailableService.AvailableServiceClient(channel); CharacterMsg playerInfo = new() { - CharacterId = 0, - TeamId = 0, - CharacterType = CharacterType.TangSeng + CharacterId = characterId, + TeamId = teamId, + CharacterType = teamId == 0 ? CharacterType.JiuLing : CharacterType.TangSeng, + SideFlag = 1 - teamId }; var call = client.AddCharacter(playerInfo); MoveMsg moveMsg = new() diff --git a/logic/proto/Message2Clients.proto b/logic/proto/Message2Clients.proto new file mode 100644 index 0000000..5f28270 --- /dev/null +++ b/logic/proto/Message2Clients.proto @@ -0,0 +1 @@ + \ No newline at end of file