diff --git a/CAPI/cpp/API/include/constants.h b/CAPI/cpp/API/include/constants.h index f457e10..526de62 100644 --- a/CAPI/cpp/API/include/constants.h +++ b/CAPI/cpp/API/include/constants.h @@ -22,7 +22,7 @@ namespace Constants SCCI int32_t DestroyFarmBonus = 4000; // SCCI double recoverMultiplier = 1.2; // SCCI double recycleMultiplier = 0.5; - //角色 + // 角色 SCCI int32_t sizeofCharacter = 800; SCCI int32_t Speed = 2500; struct Monk @@ -92,39 +92,39 @@ namespace Constants SCCI int32_t attackRange = 5; SCCI int32_t Cost = 3000; }; - //模块 + // 模块 - struct resumption //生命之泉 + struct resumption // 生命之泉 { SCCI int32_t recovery1 = 50; SCCI int32_t recovery2 = 100; SCCI int32_t recovery3 = 150; - SCCI int32_t score1 = 2000; //一级生命之泉分数 - SCCI int32_t score2 = 3000; //二级生命之泉分数 - SCCI int32_t score3 = 4000; //三级生命之泉分数 - SCCI int32_t maxHp1 = 200; //一级生命之泉守关怪物血量 - SCCI int32_t maxHp2 = 300; //二级生命之泉守关怪物血量 - SCCI int32_t maxHp3 = 400; //三级生命之泉守关怪物血量 - SCCI int32_t attack = 10; //生命之泉守关怪物攻击力 + SCCI int32_t score1 = 2000; // 一级生命之泉分数 + SCCI int32_t score2 = 3000; // 二级生命之泉分数 + SCCI int32_t score3 = 4000; // 三级生命之泉分数 + SCCI int32_t maxHp1 = 200; // 一级生命之泉守关怪物血量 + SCCI int32_t maxHp2 = 300; // 二级生命之泉守关怪物血量 + SCCI int32_t maxHp3 = 400; // 三级生命之泉守关怪物血量 + SCCI int32_t attack = 10; // 生命之泉守关怪物攻击力 }; - struct Attack_Boost //狂战士之力 + struct Attack_Boost // 狂战士之力 { SCCI int32_t attack_boost1 = 10; SCCI int32_t attack_boost2 = 15; SCCI int32_t attack_boost3 = 20; - SCCI int32_t time1 = 30; //一级狂战士之力持续时间 - SCCI int32_t time2 = 45; //二级狂战士之力持续时间 - SCCI int32_t time3 = 60; //三级狂战士之力持续时间 - SCCI int32_t score1 = 4000; //一级狂战士之力分数 - SCCI int32_t score2 = 5000; //二级狂战士之力分数 - SCCI int32_t score3 = 6000; //三级狂战士之力分数 - SCCI int32_t maxHp1 = 400; //一级狂战士之力守关怪物血量 - SCCI int32_t maxHp2 = 500; //二级狂战士之力守关怪物血量 - SCCI int32_t maxHp3 = 600; //三级狂战士之力守关怪物血量 - SCCI int32_t attack1 = 10; //一级狂战士之力守关怪物攻击力 - SCCI int32_t attack2 = 15; //二级狂战士之力守关怪物攻击力 - SCCI int32_t attack3 = 20; //三级狂战士之力守关怪物攻击力 + SCCI int32_t time1 = 30; // 一级狂战士之力持续时间 + SCCI int32_t time2 = 45; // 二级狂战士之力持续时间 + SCCI int32_t time3 = 60; // 三级狂战士之力持续时间 + SCCI int32_t score1 = 4000; // 一级狂战士之力分数 + SCCI int32_t score2 = 5000; // 二级狂战士之力分数 + SCCI int32_t score3 = 6000; // 三级狂战士之力分数 + SCCI int32_t maxHp1 = 400; // 一级狂战士之力守关怪物血量 + SCCI int32_t maxHp2 = 500; // 二级狂战士之力守关怪物血量 + SCCI int32_t maxHp3 = 600; // 三级狂战士之力守关怪物血量 + SCCI int32_t attack1 = 10; // 一级狂战士之力守关怪物攻击力 + SCCI int32_t attack2 = 15; // 二级狂战士之力守关怪物攻击力 + SCCI int32_t attack3 = 20; // 三级狂战士之力守关怪物攻击力 }; struct Speed_Boost @@ -168,7 +168,7 @@ namespace Constants SCCI int32_t time_cost = 10; }; - struct Trap + struct Hole { SCCI int32_t cost = 1000; SCCI int32_t time = 5; @@ -182,7 +182,7 @@ namespace Constants SCCI int32_t time = 5; SCCI int32_t continous_time = 30; }; - //商店商品 + // 商店商品 struct blood_vial { SCCI int32_t cost1 = 1500; @@ -226,9 +226,9 @@ namespace Constants { SCCI int32_t cost = 10000; SCCI int32_t time = 30; - SCCI int32_t attack_boost = 1.2; //注意这是提升的倍数 - SCCI int32_t speed_boost = 300; //注意这是直接叠加 - SCCI int32_t attack_freq_boost = 1.25; //注意这是提升的倍数 + SCCI int32_t attack_boost = 1.2; // 注意这是提升的倍数 + SCCI int32_t speed_boost = 300; // 注意这是直接叠加 + SCCI int32_t attack_freq_boost = 1.25; // 注意这是提升的倍数 }; } // namespace Constants #endif \ No newline at end of file diff --git a/CAPI/cpp/API/src/AI.cpp b/CAPI/cpp/API/src/AI.cpp index 005eb2f..1518c32 100644 --- a/CAPI/cpp/API/src/AI.cpp +++ b/CAPI/cpp/API/src/AI.cpp @@ -8,23 +8,26 @@ // 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新,大致一帧更新一次 extern const bool asynchronous = false; -// 选手需要依次将player1到player4的角色类型在这里定义 -extern const std::array CharacterTypeDict = { +// 选手需要依次将player1到player5的角色类型在这里定义 +extern const std::array BuddhistsCharacterTypeDict = { THUAI8::CharacterType::Monk, THUAI8::CharacterType::MonkeyKing, THUAI8::CharacterType::Pigsy, THUAI8::CharacterType::ShaWujing, THUAI8::CharacterType::Whitedragonhorse, +}; + +extern const std::array MonstersCharacterTypeDict = { THUAI8::CharacterType::JiuTouYuanSheng, THUAI8::CharacterType::Honghaier, THUAI8::CharacterType::Gyuumao, THUAI8::CharacterType::Princess_Iron_Fan, THUAI8::CharacterType::Spider, -}; +} // 可以在AI.cpp内部声明变量与函数 -void AI::play(ICharacterAPI& api) +void AI::play(ICharacterAPI & api) { if (this->playerID == 1) { diff --git a/CAPI/cpp/API/src/logic.cpp b/CAPI/cpp/API/src/logic.cpp index 4240e45..645040c 100644 --- a/CAPI/cpp/API/src/logic.cpp +++ b/CAPI/cpp/API/src/logic.cpp @@ -27,9 +27,9 @@ Logic::Logic(int32_t pID, int32_t tID, THUAI8::PlayerType pType, THUAI8::Charact bufferState->gameInfo = std::make_shared(); bufferState->mapInfo = std::make_shared(); if (teamID == 0) - playerTeam = THUAI8::PlayerTeam::Red; + playerTeam = THUAI8::PlayerTeam::BuddhistsTeam; else if (teamID == 1) - playerTeam = THUAI8::PlayerTeam::Blue; + playerTeam = THUAI8::PlayerTeam::MonstersTeam; else playerTeam = THUAI8::PlayerTeam::NullTeam; } @@ -42,7 +42,7 @@ std::vector> Logic::GetCharacters() con return temp; } -std::vector> Logic::GetEnemySCharacters() const +std::vector> Logic::GetEnemyCharacters() const { std::unique_lock lock(mtxState); std::vector> temp(currentState->enemyCharacters.begin(), currentState->enemyCharacters.end()); diff --git a/CAPI/python/AI.py b/CAPI/python/AI.py index 7e4ed7c..7cf5dca 100644 --- a/CAPI/python/AI.py +++ b/CAPI/python/AI.py @@ -1,10 +1,12 @@ -import PyAPI.structures as THUAI8 -from PyAPI.Interface import ICharacterAPI, ITeamAPI, IAI -from PyAPI.utils import AssistFunction -from typing import Union, Final, cast, List -from PyAPI.constants import Constants import queue import time +from typing import Final, List, Union, cast + +import PyAPI.structures as THUAI8 +from PyAPI.constants import Constants +from PyAPI.Interface import IAI, ICharacterAPI, ITeamAPI +from PyAPI.utils import AssistFunction + class Setting: # 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新,大致一帧更新一次 @@ -13,6 +15,22 @@ class Setting: return False @staticmethod +<<<<<<< HEAD + def BuddhistsCharacterTypes() -> List[THUAI8.CharacterType]: + return [ + THUAI8.CharacterType.Monk, + THUAI8.CharacterType.MonkyKing, + THUAI8.CharacterType.Pigsy, + THUAI8.CharacterType.ShaWujing, + THUAI8.CharacterType.Whitedragonhorse, + ] + + @staticmethod + def MonsterCharacterTypes() -> List[THUAI8.CharacterType]: + return [ + THUAI8.CharacterType.JiuTouYuanSheng, + THUAI8.CharacterType.HongHaier, +======= def ShipTypes() -> List[THUAI8.CharacterType]: return [ THUAI8.CharacterType.Monk, @@ -22,17 +40,30 @@ class Setting: THUAI8.CharacterType.Whitedragonhorse, THUAI8.CharacterType.JiuTouYuanSheng, THUAI8.CharacterType.Honghaier, +>>>>>>> 5a1751dc64f09ba19aaa818e5dc99172d15f4c69 THUAI8.CharacterType.Gyuumao, THUAI8.CharacterType.Princess_Iron_Fan, THUAI8.CharacterType.Spider, ] +<<<<<<< HEAD + + numOfGridPerCell: Final[int] = 1000 + +======= +numOfGridPerCell: Final[int] = 1000 + +>>>>>>> 5a1751dc64f09ba19aaa818e5dc99172d15f4c69 class AI(IAI): def __init__(self, pID: int): self.__playerID = pID +<<<<<<< HEAD + def CharacterPlay(self, api: ICharacterAPI) -> None: +======= def ShipPlay(self, api: IShipAPI) -> None: +>>>>>>> 5a1751dc64f09ba19aaa818e5dc99172d15f4c69 # 公共操作 if self.__playerID == 1: # player1的操作 @@ -46,9 +77,13 @@ class AI(IAI): elif self.__playerID == 4: # player4的操作 return +<<<<<<< HEAD + return +======= elif self.__playerID == 5: # player4的操作 return +>>>>>>> 5a1751dc64f09ba19aaa818e5dc99172d15f4c69 def TeamPlay(self, api: ITeamAPI) -> None: # player0的操作 diff --git a/CAPI/python/constants.py b/CAPI/python/constants.py new file mode 100644 index 0000000..ffcbcef --- /dev/null +++ b/CAPI/python/constants.py @@ -0,0 +1,199 @@ +class Constants: + frameDuration = 50 + + numofGridPerCell = 1000 + rows = 50 + cols = 50 + + destroyBarracksBonus = 6000 + destroySpringBonus = 3000 + destroyFarmBonus = 4000 + + sizeofCharacter = 800 + speed = 2500 + + +class Monk: + maxHp = 1000 + + +class MonkyKing: + maxHp = 200 + commonAttackPower = 30 + attackRange = 1 + cost = 5000 + + +class Pigsy: + maxHp = 300 + commonAttackPower = 20 + attackRange = 2 + cost = 4000 + + +class ShaWujing: + maxHp = 150 + commonAttackPower = 10 + attackRange = 5 + cost = 3000 + + +class Whitedragonhorse: + maxHp = 150 + commonAttackPower = 10 + attackRange = 5 + cost = 4000 + + +class JiuTouYuanSheng: + maxHp = 1000 + + +class HongHaier: + maxHp = 200 + commonAttackPower = 25 + attackRange = 1 + cost = 5000 + + +class Gyuumao: + maxHp = 300 + commonAttackPower = 20 + attackRange = 2 + cost = 4000 + + +class Princess_Iron_Fan: + maxHp = 150 + commonAttackPower = 10 + attackRange = 5 + cost = 3000 + + +class Spider: + maxHp = 150 + commonAttackPower = 10 + attackRange = 5 + cost = 3000 + + +class resumption: + recovery1 = 50 + recovery2 = 100 + recovery3 = 150 + score1 = 2000 + score2 = 3000 + score3 = 4000 + maxHp1 = 200 + maxHp2 = 300 + maxHp3 = 400 + attack = 10 + + +class Attack_Boost: + attackBoost1 = 10 + attackBoost2 = 15 + attackBoost3 = 20 + time1 = 30 + time2 = 45 + time3 = 60 + score1 = 4000 + score2 = 5000 + score3 = 6000 + maxHp1 = 400 + maxHp2 = 500 + maxHp3 = 600 + attack1 = 10 + attack2 = 15 + attack3 = 20 + + +class Speed_Boost: + speedBoost1 = 500 + time = 60 + score = 3000 + maxHp = 300 + attack = 10 + + +class View_Boost: + time = 60 + score = 3000 + maxHp = 300 + attack = 10 + + +class Barracks: + maxHp = 600 + cost = 10000 + sabotage_score = 6000 + time_cost = 15 + + +class Spring: + maxHp = 300 + cost = 8000 + sabotage_score = 3000 + time_cost = 10 + + +class Farm: + maxHp = 400 + cost = 8000 + sabotage_score = 3000 + time_cost = 10 + + +class Hole: + cost = 1000 + time = 5 + attack = 20 + continous_time = 5 + + +class Cage: + cost = 1000 + time = 5 + continueous_time = 30 + + +class blood_vial: + cost1 = 1500 + cost2 = 3000 + cost3 = 4500 + recovery1 = 50 + recovery2 = 100 + recovery3 = 150 + + +class Shield: + cost1 = 2000 + cost2 = 3500 + cost3 = 5000 + defence1 = 50 + defence2 = 100 + defence3 = 150 + + +class Speed_shoes: + speedBoost = 500 + time = 60 + cost = 1500 + + +class purification_medicine: + cost = 2000 + time = 30 + + +class invisibility: + cost = 4000 + time = 10 + + +class berserk: + cost = 10000 + time = 30 + attack_boost = 1.2 # 注意这是提升的倍数 + speed_boost = 300 # 注意这是直接叠加 + attack_freq_boost = 1.25 # 注意这是提升的倍数 diff --git a/interface/AvaloniaUI_debug_interface/debug_interface/App.axaml.cs b/interface/AvaloniaUI_debug_interface/debug_interface/App.axaml.cs index 998c8c8..0eb0be0 100644 --- a/interface/AvaloniaUI_debug_interface/debug_interface/App.axaml.cs +++ b/interface/AvaloniaUI_debug_interface/debug_interface/App.axaml.cs @@ -1,20 +1,18 @@ using Avalonia; using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Data.Core; -using Avalonia.Data.Core.Plugins; using Avalonia.Markup.Xaml; +using debug_interface.Services; using debug_interface.ViewModels; using debug_interface.Views; -using System.Linq; +using System; +using System.IO; +using installer.Model; +using installer.Data; namespace debug_interface { - /// - /// Ӧóĺô룬ʼڡ - /// public partial class App : Application { - public override void Initialize() { AvaloniaXamlLoader.Load(this); @@ -24,34 +22,43 @@ namespace debug_interface { if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - // Avoid duplicate validations from both Avalonia and the CommunityToolkit. - // More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins - DisableAvaloniaDataAnnotationValidation(); + // + var config = new ConfigData(); - var mainWindowViewModel = new MainWindowViewModel(); + // ־Ŀ¼ + string logDir = Path.Combine(config.InstallPath, "Logs"); + Directory.CreateDirectory(logDir); + // ־¼ + var logFilePath = Path.Combine(logDir, $"debug_interface_{DateTime.Now:yyyyMMdd_HHmmss}.log"); + var logger = new FileLogger(logFilePath); + + // ͼģ + var mainWindowViewModel = new MainWindowViewModel(logger, config); + + // ͨŷ + var serverCommunicationService = new ServerCommunicationService(mainWindowViewModel, logger, config); + + // desktop.MainWindow = new MainWindow { - DataContext = new MainWindowViewModel(), + DataContext = mainWindowViewModel }; + + // ӷط + if (string.IsNullOrEmpty(config.Commands.PlaybackFile)) + { + // ӵ + _ = serverCommunicationService.ConnectToServer(); + } + else + { + // طģʽ + serverCommunicationService.StartPlaybackMode(); + } } base.OnFrameworkInitializationCompleted(); } - - private void DisableAvaloniaDataAnnotationValidation() - { - // Get an array of plugins to remove - var dataValidationPluginsToRemove = - BindingPlugins.DataValidators.OfType().ToArray(); - - // remove each entry found - foreach (var plugin in dataValidationPluginsToRemove) - { - BindingPlugins.DataValidators.Remove(plugin); - } - } - - } } \ No newline at end of file diff --git a/interface/AvaloniaUI_debug_interface/debug_interface/Models/MapCell.cs b/interface/AvaloniaUI_debug_interface/debug_interface/Models/MapCell.cs index 6006d95..c7e9e15 100644 --- a/interface/AvaloniaUI_debug_interface/debug_interface/Models/MapCell.cs +++ b/interface/AvaloniaUI_debug_interface/debug_interface/Models/MapCell.cs @@ -1,6 +1,7 @@ //MapCell.cs using Avalonia.Media; using CommunityToolkit.Mvvm.ComponentModel; +using debug_interface.ViewModels; using System; using System.Collections.Generic; using System.Linq; 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..111579c --- /dev/null +++ b/interface/AvaloniaUI_debug_interface/debug_interface/Services/ServerCommunicationService.cs @@ -0,0 +1,776 @@ +using System; +using System.Threading.Tasks; +using Avalonia.Threading; +using debug_interface.ViewModels; +using Grpc.Core; +using installer.Model; +using installer.Data; + +namespace debug_interface.Services +{ + public class ServerCommunicationService + { + private readonly MainWindowViewModel _viewModel; + private readonly Logger _logger; + private readonly ConfigData _config; + private bool _isConnected = false; + private bool _isPlaybackMode = false; + + public ServerCommunicationService(MainWindowViewModel viewModel, Logger logger, ConfigData config) + { + _viewModel = viewModel; + _logger = logger; + _config = config; + } + + public async Task ConnectToServer() + { + try + { + string ip = _config.Commands.IP; + string port = _config.Commands.Port; + + _logger.LogInfo($"尝试连接服务器 {ip}:{port}"); + + // 由于没有正确的Proto引用,这里暂时只模拟连接行为 + await Task.Delay(1000); // 模拟连接延迟 + + await Dispatcher.UIThread.InvokeAsync(() => { + _viewModel.GameLog = $"已连接到服务器 {ip}:{port}"; + }); + + _isConnected = true; + _logger.LogInfo("已模拟连接到服务器"); + } + catch (Exception ex) + { + _logger.LogError($"连接失败: {ex.Message}"); + + await Dispatcher.UIThread.InvokeAsync(() => { + _viewModel.GameLog = $"连接失败: {ex.Message}"; + }); + } + } + + public void StartPlaybackMode() + { + try + { + _isPlaybackMode = true; + string playbackFile = _config.Commands.PlaybackFile ?? ""; + + _logger.LogInfo($"模拟回放: {playbackFile}"); + + Dispatcher.UIThread.InvokeAsync(() => { + _viewModel.GameLog = $"模拟回放: {playbackFile}"; + }); + } + catch (Exception ex) + { + _logger.LogError($"回放错误: {ex.Message}"); + + Dispatcher.UIThread.InvokeAsync(() => { + _viewModel.GameLog = $"回放错误: {ex.Message}"; + }); + } + } + } +} + + +//using System; +//using System.Linq; +//using System.Threading.Tasks; +//using Avalonia.Threading; +//using debug_interface.ViewModels; +//using Grpc.Core; +//using Google.Protobuf; // 假设这是proto文件生成的命名空间 +//using installer.Model; // Logger的命名空间 +//using installer.Data; // ConfigData的命名空间 +//using System.Collections.Generic; +//using Avalonia.Data; +//using System.Threading.Channels; + +//namespace debug_interface.Services +//{ +// public class ServerCommunicationService +// { +// private readonly MainWindowViewModel _viewModel; +// private readonly Logger _logger; +// private readonly ConfigData _config; +// private AvailableService.AvailableServiceClient? _client; +// private AsyncServerStreamingCall? _responseStream; +// private bool _isConnected = false; +// private bool _isPlaybackMode = false; + +// public ServerCommunicationService(MainWindowViewModel viewModel, Logger logger, ConfigData config) +// { +// _viewModel = viewModel; +// _logger = logger; +// _config = config; +// } + +// public async Task ConnectToServer() +// { +// try +// { +// if (_isPlaybackMode) +// return; + +// string ip = _config.Commands.IP; +// string port = _config.Commands.Port; +// long playerId = _config.Commands.PlayerID; +// long teamId = _config.Commands.TeamID; +// int characterType = _config.Commands.CharacterType; + +// string connectionString = $"{ip}:{port}"; +// _logger.LogInfo($"正在连接到服务器 {connectionString}"); + +// // 创建gRPC通道和客户端 +// var channel = new Channel(connectionString, ChannelCredentials.Insecure); +// _client = new AvailableService.AvailableServiceClient(channel); + +// // 创建连接消息 +// var characterMsg = new CharacterMsg +// { +// CharacterId = playerId, +// TeamId = teamId, +// CharacterType = (CharacterType)characterType +// }; + +// // 连接到服务器 +// _responseStream = _client.AddCharacter(characterMsg); +// _isConnected = true; + +// // 开始接收消息 +// _ = StartReceivingMessagesAsync(); + +// _logger.LogInfo("成功连接到服务器"); +// } +// catch (Exception ex) +// { +// _isConnected = false; +// _logger.LogError($"连接服务器失败: {ex.Message}"); + +// // 在UI中显示错误 +// await Dispatcher.UIThread.InvokeAsync(() => { +// _viewModel.GameLog = $"连接服务器错误: {ex.Message}"; +// }); + +// throw; +// } +// } + +// public void StartPlaybackMode() +// { +// _isPlaybackMode = true; +// string playbackFile = _config.Commands.PlaybackFile ?? ""; +// double playbackSpeed = _config.Commands.PlaybackSpeed; + +// _logger.LogInfo($"正在从{playbackFile}以{playbackSpeed}倍速开始回放模式"); + +// // 这里可以实现回放逻辑,读取文件并模拟服务器消息 +// // 例如启动一个单独的任务来读取和处理文件 +// _ = Task.Run(async () => { +// try +// { +// // 简单的回放逻辑示例 +// if (System.IO.File.Exists(playbackFile)) +// { +// // 读取文件内容... +// _logger.LogInfo("回放文件存在,开始读取数据"); + +// // 这里是简化实现,实际应根据文件格式处理 +// var fileBytes = System.IO.File.ReadAllBytes(playbackFile); + +// // 通知UI +// await Dispatcher.UIThread.InvokeAsync(() => { +// _viewModel.GameLog = "正在回放..."; +// }); +// } +// else +// { +// _logger.LogError($"回放文件不存在: {playbackFile}"); +// await Dispatcher.UIThread.InvokeAsync(() => { +// _viewModel.GameLog = "回放文件不存在!"; +// }); +// } +// } +// catch (Exception ex) +// { +// _logger.LogError($"回放过程中出错: {ex.Message}"); +// await Dispatcher.UIThread.InvokeAsync(() => { +// _viewModel.GameLog = $"回放错误: {ex.Message}"; +// }); +// } +// }); +// } + +// private async Task StartReceivingMessagesAsync() +// { +// if (_responseStream == null) +// return; + +// try +// { +// _logger.LogInfo("开始接收服务器消息"); + +// while (await _responseStream.ResponseStream.MoveNext(default)) +// { +// var message = _responseStream.ResponseStream.Current; + +// // 在UI线程上处理消息,以安全地更新UI +// await Dispatcher.UIThread.InvokeAsync(() => { +// ProcessServerMessage(message); +// }); +// } +// } +// catch (RpcException ex) when (ex.StatusCode == StatusCode.Cancelled) +// { +// _logger.LogInfo("服务器流已取消"); +// } +// catch (Exception ex) +// { +// _logger.LogError($"接收服务器消息错误: {ex.Message}"); + +// await Dispatcher.UIThread.InvokeAsync(() => { +// _viewModel.GameLog = $"连接错误: {ex.Message}"; +// }); + +// // 尝试重新连接 +// await TryReconnectAsync(); +// } +// finally +// { +// _isConnected = false; +// } +// } + +// private async Task TryReconnectAsync() +// { +// _logger.LogInfo("尝试重新连接服务器..."); + +// // 等待一段时间后重试 +// await Task.Delay(5000); + +// if (!_isConnected && !_isPlaybackMode) +// { +// try +// { +// await ConnectToServer(); +// } +// catch +// { +// // 重连失败,等待更长时间后再次尝试 +// await Task.Delay(10000); +// _ = TryReconnectAsync(); +// } +// } +// } + +// private void ProcessServerMessage(MessageToClient message) +// { +// try +// { +// // 更新游戏状态 +// switch (message.GameState) +// { +// case GameState.GameStart: +// _logger.LogInfo("游戏开始"); +// _viewModel.GameLog = "游戏开始..."; +// break; + +// case GameState.GameRunning: +// // 处理运行中的游戏数据 +// _viewModel.GameLog = "游戏运行中..."; +// break; + +// case GameState.GameEnd: +// _logger.LogInfo("游戏结束"); +// _viewModel.GameLog = "游戏结束"; +// break; +// } + +// // 更新全局游戏信息 +// if (message.AllMessage != null) +// { +// UpdateGlobalGameInfo(message.AllMessage); +// } + +// // 处理单个对象消息 +// foreach (var obj in message.ObjMessage) +// { +// ProcessObjectMessage(obj); +// } +// } +// catch (Exception ex) +// { +// _logger.LogError($"处理服务器消息错误: {ex.Message}"); +// } +// } + +// private void UpdateGlobalGameInfo(MessageOfAll allMessage) +// { +// try +// { +// // 更新游戏时间 +// _viewModel.CurrentTime = FormatGameTime(allMessage.GameTime); + +// // 更新队伍得分 +// _viewModel.RedScore = allMessage.BuddhistsTeamScore; +// _viewModel.BlueScore = allMessage.MonstersTeamScore; + +// // 更新队伍经济/资源 +// _viewModel.BuddhistTeamEconomy = allMessage.BuddhistsTeamEconomy; +// _viewModel.MonstersTeamEconomy = allMessage.MonstersTeamEconomy; + +// // 更新英雄HP (如果ViewModel中有对应属性) +// if (typeof(MainWindowViewModel).GetProperty("BuddhistHeroHp") != null) +// { +// _viewModel.BuddhistHeroHp = allMessage.BuddhistsHeroHp; +// _viewModel.MonstersHeroHp = allMessage.MonstersHeroHp; +// } +// } +// catch (Exception ex) +// { +// _logger.LogError($"更新全局游戏信息失败: {ex.Message}"); +// } +// } + +// private void ProcessObjectMessage(MessageOfObj objMessage) +// { +// try +// { +// switch (objMessage.MessageOfObjCase) +// { +// case MessageOfObj.MessageOfObjOneofCase.CharacterMessage: +// UpdateCharacter(objMessage.CharacterMessage); +// break; + +// case MessageOfObj.MessageOfObjOneofCase.BarracksMessage: +// UpdateBuilding(objMessage.BarracksMessage, "兵营"); +// break; + +// case MessageOfObj.MessageOfObjOneofCase.SpringMessage: +// UpdateBuilding(objMessage.SpringMessage, "泉水"); +// break; + +// case MessageOfObj.MessageOfObjOneofCase.FarmMessage: +// UpdateBuilding(objMessage.FarmMessage, "农场"); +// break; + +// case MessageOfObj.MessageOfObjOneofCase.TrapMessage: +// UpdateTrap(objMessage.TrapMessage); +// break; + +// case MessageOfObj.MessageOfObjOneofCase.EconomyResourceMessage: +// UpdateResource(objMessage.EconomyResourceMessage); +// break; + +// case MessageOfObj.MessageOfObjOneofCase.AdditionResourceMessage: +// UpdateAdditionResource(objMessage.AdditionResourceMessage); +// break; + +// case MessageOfObj.MessageOfObjOneofCase.MapMessage: +// UpdateMap(objMessage.MapMessage); +// break; +// } +// } +// catch (Exception ex) +// { +// _logger.LogError($"处理对象消息失败: {ex.Message} (类型: {objMessage.MessageOfObjCase})"); +// } +// } + +// private void UpdateCharacter(MessageOfCharacter character) +// { +// try +// { +// // 在适当的团队集合中查找角色 +// var isRedTeam = character.TeamId == 1; // 1表示取经队 +// var collection = isRedTeam +// ? _viewModel.RedTeamCharacters +// : _viewModel.BlueTeamCharacters; + +// // 计算网格坐标 +// int gridX = character.X / 1000; +// int gridY = character.Y / 1000; + +// // 尝试查找现有角色 +// var existingCharacter = collection.FirstOrDefault(c => c.CharacterId == character.PlayerId); + +// if (existingCharacter != null) +// { +// // 更新现有角色 +// existingCharacter.Name = GetCharacterTypeName(character.CharacterType); +// existingCharacter.Hp = character.Hp; +// existingCharacter.PosX = gridX; +// existingCharacter.PosY = gridY; + +// // 更新主动状态 +// existingCharacter.ActiveState = GetCharacterStateText(character.CharacterActiveState); + +// // 更新被动状态 +// existingCharacter.PassiveStates.Clear(); + +// // 根据需要添加被动状态 +// if (character.BlindState != CharacterState.NullCharacterState) +// existingCharacter.PassiveStates.Add("致盲"); +// if (character.StunnedState != CharacterState.NullCharacterState) +// existingCharacter.PassiveStates.Add("定身"); +// if (character.InvisibleState != CharacterState.NullCharacterState) +// existingCharacter.PassiveStates.Add("隐身"); +// if (character.BurnedState != CharacterState.NullCharacterState) +// existingCharacter.PassiveStates.Add("灼烧"); + +// // 更新装备 +// existingCharacter.EquipmentInventory.Clear(); +// if (character.ShieldEquipment > 0) +// existingCharacter.EquipmentInventory.Add(new EquipmentItem("护盾", character.ShieldEquipment)); +// if (character.ShoesEquipment > 0) +// existingCharacter.EquipmentInventory.Add(new EquipmentItem("鞋子", 1)); +// if (character.PurificationEquipmentTime > 0) +// existingCharacter.EquipmentInventory.Add(new EquipmentItem("净化药水", 1)); + +// // 通知UI更新显示的状态和装备文本 +// existingCharacter.OnPropertyChanged(nameof(CharacterViewModel.DisplayStates)); +// existingCharacter.OnPropertyChanged(nameof(CharacterViewModel.DisplayEquipments)); +// } +// else +// { +// // 创建新角色 +// var newCharacter = new CharacterViewModel +// { +// CharacterId = character.PlayerId, +// Name = GetCharacterTypeName(character.CharacterType), +// Hp = character.Hp, +// PosX = gridX, +// PosY = gridY, +// ActiveState = GetCharacterStateText(character.CharacterActiveState) +// }; + +// // 添加被动状态 +// if (character.BlindState != CharacterState.NullCharacterState) +// newCharacter.PassiveStates.Add("致盲"); +// if (character.StunnedState != CharacterState.NullCharacterState) +// newCharacter.PassiveStates.Add("定身"); +// if (character.InvisibleState != CharacterState.NullCharacterState) +// newCharacter.PassiveStates.Add("隐身"); +// if (character.BurnedState != CharacterState.NullCharacterState) +// newCharacter.PassiveStates.Add("灼烧"); + +// // 添加装备 +// if (character.ShieldEquipment > 0) +// newCharacter.EquipmentInventory.Add(new EquipmentItem("护盾", character.ShieldEquipment)); +// if (character.ShoesEquipment > 0) +// newCharacter.EquipmentInventory.Add(new EquipmentItem("鞋子", 1)); +// if (character.PurificationEquipmentTime > 0) +// newCharacter.EquipmentInventory.Add(new EquipmentItem("净化药水", 1)); + +// // 添加到集合 +// collection.Add(newCharacter); +// } + +// // 更新地图上的角色位置 +// _viewModel.MapVM.UpdateCharacterPosition( +// character.PlayerId, +// character.TeamId, +// gridX, +// gridY, +// GetCharacterTypeName(character.CharacterType) +// ); +// } +// catch (Exception ex) +// { +// _logger.LogError($"更新角色失败: {ex.Message}"); +// } +// } + +// private string GetCharacterTypeName(CharacterType type) +// { +// return type switch +// { +// CharacterType.TangSeng => "唐僧", +// CharacterType.SunWukong => "孙悟空", +// CharacterType.ZhuBajie => "猪八戒", +// CharacterType.ShaWujing => "沙悟净", +// CharacterType.BaiLongma => "白龙马", +// CharacterType.Monkid => "小和尚", +// CharacterType.JiuLing => "九灵元圣", +// CharacterType.HongHaier => "红孩儿", +// CharacterType.NiuMowang => "牛魔王", +// CharacterType.TieShan => "铁扇公主", +// CharacterType.ZhiZhujing => "蜘蛛精", +// CharacterType.Pawn => "小妖", +// _ => "未知角色" +// }; +// } + +// private string GetCharacterStateText(CharacterState state) +// { +// return state switch +// { +// CharacterState.Idle => "空置", +// CharacterState.Harvesting => "开采", +// CharacterState.Attacking => "攻击", +// CharacterState.SkillCasting => "释放技能", +// CharacterState.Constructing => "建造", +// CharacterState.Moving => "移动", +// _ => "未知状态" +// }; +// } + +// private void UpdateBuilding(MessageOfBarracks building, string buildingType) +// { +// try +// { +// // 转换为网格坐标 +// int gridX = building.X / 1000; +// int gridY = building.Y / 1000; + +// // 确保坐标在有效范围内 +// if (gridX >= 0 && gridX < 50 && gridY >= 0 && gridY < 50) +// { +// // 在地图上更新建筑 +// _viewModel.MapVM.UpdateBuildingCell( +// gridX, +// gridY, +// building.TeamId == 1 ? "取经队" : "妖怪队", +// buildingType, +// building.Hp +// ); + +// // 更新建筑信息文本 (假设ViewModel有这些属性) +// string buildingInfo = $"{buildingType} 位置:({gridX},{gridY}) 血量:{building.Hp}"; +// if (building.TeamId == 1) // 取经队 +// { +// // 尝试更新建筑信息,如果属性存在的话 +// if (typeof(MainWindowViewModel).GetProperty("SomeBuildingInfo") != null) +// { +// _viewModel.SomeBuildingInfo = buildingInfo; +// } +// } +// else // 妖怪队 +// { +// if (typeof(MainWindowViewModel).GetProperty("AnotherBuildingInfo") != null) +// { +// _viewModel.AnotherBuildingInfo = buildingInfo; +// } +// } +// } +// } +// catch (Exception ex) +// { +// _logger.LogError($"更新建筑(兵营)失败: {ex.Message}"); +// } +// } + +// private void UpdateBuilding(MessageOfSpring building, string buildingType) +// { +// try +// { +// // 类似于UpdateBuilding(MessageOfBarracks...)的实现 +// int gridX = building.X / 1000; +// int gridY = building.Y / 1000; + +// if (gridX >= 0 && gridX < 50 && gridY >= 0 && gridY < 50) +// { +// _viewModel.MapVM.UpdateBuildingCell( +// gridX, +// gridY, +// building.TeamId == 1 ? "取经队" : "妖怪队", +// buildingType, +// building.Hp +// ); + +// string buildingInfo = $"{buildingType} 位置:({gridX},{gridY}) 血量:{building.Hp}"; +// if (building.TeamId == 1 && +// typeof(MainWindowViewModel).GetProperty("SomeBuildingInfo") != null) +// { +// _viewModel.SomeBuildingInfo += "\n" + buildingInfo; +// } +// else if (building.TeamId != 1 && +// typeof(MainWindowViewModel).GetProperty("AnotherBuildingInfo") != null) +// { +// _viewModel.AnotherBuildingInfo += "\n" + buildingInfo; +// } +// } +// } +// catch (Exception ex) +// { +// _logger.LogError($"更新建筑(泉水)失败: {ex.Message}"); +// } +// } + +// private void UpdateBuilding(MessageOfFarm building, string buildingType) +// { +// try +// { +// // 类似于其他建筑更新方法 +// int gridX = building.X / 1000; +// int gridY = building.Y / 1000; + +// if (gridX >= 0 && gridX < 50 && gridY >= 0 && gridY < 50) +// { +// _viewModel.MapVM.UpdateBuildingCell( +// gridX, +// gridY, +// building.TeamId == 1 ? "取经队" : "妖怪队", +// buildingType, +// building.Hp +// ); + +// string buildingInfo = $"{buildingType} 位置:({gridX},{gridY}) 血量:{building.Hp}"; +// if (building.TeamId == 1 && +// typeof(MainWindowViewModel).GetProperty("SomeBuildingInfo") != null) +// { +// _viewModel.SomeBuildingInfo += "\n" + buildingInfo; +// } +// else if (building.TeamId != 1 && +// typeof(MainWindowViewModel).GetProperty("AnotherBuildingInfo") != null) +// { +// _viewModel.AnotherBuildingInfo += "\n" + buildingInfo; +// } +// } +// } +// catch (Exception ex) +// { +// _logger.LogError($"更新建筑(农场)失败: {ex.Message}"); +// } +// } + +// private void UpdateTrap(MessageOfTrap trap) +// { +// try +// { +// int gridX = trap.X / 1000; +// int gridY = trap.Y / 1000; + +// if (gridX >= 0 && gridX < 50 && gridY >= 0 && gridY < 50) +// { +// string trapTypeName = trap.TrapType switch +// { +// TrapType.Hole => "陷阱坑", +// TrapType.Cage => "牢笼", +// _ => "未知陷阱" +// }; + +// _viewModel.MapVM.UpdateTrapCell( +// gridX, +// gridY, +// trap.TeamId == 1 ? "取经队" : "妖怪队", +// trapTypeName +// ); +// } +// } +// catch (Exception ex) +// { +// _logger.LogError($"更新陷阱失败: {ex.Message}"); +// } +// } + +// private void UpdateResource(MessageOfEconomyResource resource) +// { +// try +// { +// int gridX = resource.X / 1000; +// int gridY = resource.Y / 1000; + +// if (gridX >= 0 && gridX < 50 && gridY >= 0 && gridY < 50) +// { +// string resourceTypeName = resource.EconomyResourceType switch +// { +// EconomyResourceType.SmallEconomyResource => "小经济资源", +// EconomyResourceType.MediumEconomyResource => "中经济资源", +// EconomyResourceType.LargeEconomyResource => "大经济资源", +// _ => "未知资源" +// }; + +// _viewModel.MapVM.UpdateResourceCell( +// gridX, +// gridY, +// resourceTypeName, +// resource.Process +// ); +// } +// } +// catch (Exception ex) +// { +// _logger.LogError($"更新经济资源失败: {ex.Message}"); +// } +// } + +// private void UpdateAdditionResource(MessageOfAdditionResource resource) +// { +// try +// { +// int gridX = resource.X / 1000; +// int gridY = resource.Y / 1000; + +// if (gridX >= 0 && gridX < 50 && gridY >= 0 && gridY < 50) +// { +// string resourceName = GetAdditionResourceName(resource.AdditionResourceType); + +// _viewModel.MapVM.UpdateAdditionResourceCell( +// gridX, +// gridY, +// resourceName, +// resource.Hp +// ); +// } +// } +// catch (Exception ex) +// { +// _logger.LogError($"更新附加资源失败: {ex.Message}"); +// } +// } + +// private string GetAdditionResourceName(AdditionResourceType type) +// { +// return type switch +// { +// AdditionResourceType.LifePool1 => "生命池(小)", +// AdditionResourceType.LifePool2 => "生命池(中)", +// AdditionResourceType.LifePool3 => "生命池(大)", +// AdditionResourceType.CrazyMan1 => "疯人(小)", +// AdditionResourceType.CrazyMan2 => "疯人(中)", +// AdditionResourceType.CrazyMan3 => "疯人(大)", +// AdditionResourceType.QuickStep => "神行步", +// AdditionResourceType.WideView => "千里眼", +// _ => "未知加成资源" +// }; +// } + +// private void UpdateMap(MessageOfMap map) +// { +// try +// { +// // 将地图数据转换为二维数组 +// int[,] mapData = new int[50, 50]; + +// for (int i = 0; i < map.Rows.Count && i < 50; i++) +// { +// for (int j = 0; j < map.Rows[i].Cols.Count && j < 50; j++) +// { +// mapData[i, j] = (int)map.Rows[i].Cols[j]; +// } +// } + +// // 更新地图视图模型 +// _viewModel.MapVM.UpdateMap(mapData); + +// _logger.LogInfo("地图数据已更新"); +// } +// catch (Exception ex) +// { +// _logger.LogError($"更新地图数据时出错: {ex.Message}"); +// } +// } + +// private string FormatGameTime(int milliseconds) +// { +// TimeSpan time = TimeSpan.FromMilliseconds(milliseconds); +// return $"{time.Minutes:00}:{time.Seconds:00}"; +// } +// } +//} \ No newline at end of file diff --git a/interface/AvaloniaUI_debug_interface/debug_interface/ViewModels/CharacterViewModel.cs b/interface/AvaloniaUI_debug_interface/debug_interface/ViewModels/CharacterViewModel.cs index ec1c2ba..560c59a 100644 --- a/interface/AvaloniaUI_debug_interface/debug_interface/ViewModels/CharacterViewModel.cs +++ b/interface/AvaloniaUI_debug_interface/debug_interface/ViewModels/CharacterViewModel.cs @@ -1,102 +1,55 @@ -//CharacterViewModel.cs +using System.Collections.ObjectModel; using CommunityToolkit.Mvvm.ComponentModel; -using System.Collections.ObjectModel; -using System.Linq; -using System.Text; namespace debug_interface.ViewModels { public partial class CharacterViewModel : ViewModelBase { [ObservableProperty] - private string name = "角色"; // 默认角色名,可由服务器更新 + private long characterId; [ObservableProperty] - private int hp = 1000; // 血量,可由服务器动态更新 + private string name = ""; [ObservableProperty] - private int posX = 0; + private int hp; [ObservableProperty] - private int posY = 0; + private int posX; - // 主动状态(单一) - // 可能值: "空置","开采","攻击","释放技能","建造","移动" [ObservableProperty] - private string activeState = "空置"; + private int posY; - // 被动状态(可叠加) - // 可能值: "致盲","击退","定身","隐身" 等,可由服务器控制增减 - public ObservableCollection PassiveStates { get; } = new ObservableCollection(); + [ObservableProperty] + private string activeState = ""; - // 装备清单:用名称+数量表示。如 {"小血瓶":2, "鞋子":1, "大护盾":1, "净化药水":3} - // 为了方便绑定,用 ObservableCollection 来存储装备条目,每个条目包含Name和Count - public ObservableCollection EquipmentInventory { get; } = new ObservableCollection(); + public ObservableCollection PassiveStates { get; } = new(); - // 状态选项列表和装备选项列表已不再使用ComboBox选择,而是纯展示。 - // 如果需要仍保留可由服务器更新,但这里不会再用于交互。 + public ObservableCollection EquipmentInventory { get; } = new(); - // 构造函数 - public CharacterViewModel() - { - PassiveStates = new ObservableCollection(); - EquipmentInventory = new ObservableCollection(); - } + // 格式化状态文本的属性 + public string DisplayStates => + $"{ActiveState} {(PassiveStates.Count > 0 ? $"[{string.Join(", ", PassiveStates)}]" : "")}"; - // 用于UI展示状态字符串 - // 格式: (主动:xx 被动:xx yy zz) - public string DisplayStates - { - get - { - var sb = new StringBuilder(); - sb.Append("(主动:").Append(ActiveState).Append(" 被动:"); - if (PassiveStates.Count > 0) - sb.Append(string.Join(" ", PassiveStates)); - else - sb.Append("无"); - sb.Append(")"); - return sb.ToString(); - } - } - - // 用于UI展示装备字符串 - // 格式: 装备: 小血瓶x2 鞋子x1 大护盾x1 净化药水x3 - public string DisplayEquipments - { - get - { - if (EquipmentInventory.Count == 0) - { - return "装备:无"; - } - return "装备: " + string.Join(", ", - EquipmentInventory.Select(e => $"{e.Name}×{e.Count}")); - } - } - - // 当ActiveState或PassiveStates变化后,通知UI更新 DisplayStates - partial void OnActiveStateChanged(string oldValue, string newValue) - { - OnPropertyChanged(nameof(DisplayStates)); - } - - // 如果被动状态列表更新,需要调用OnPropertyChanged(nameof(DisplayStates)) - // 可以在服务器更新逻辑中调用。 - - // 同理,当EquipmentInventory变化时,需要更新DisplayEquipments - // 可以在添加/移除装备后调用OnPropertyChanged(nameof(DisplayEquipments)) + // 格式化装备文本的属性 + public string DisplayEquipments => + EquipmentInventory.Count > 0 ? string.Join(", ", EquipmentInventory) : "无"; } - // 定义装备类 public class EquipmentItem { - public string Name { get; set; } - public int Count { get; set; } + public string Name { get; } + public int Count { get; } + public EquipmentItem(string name, int count) { Name = name; Count = count; } + + public override string ToString() + { + return Count > 1 ? $"{Name}x{Count}" : Name; + } } -} +} \ No newline at end of file diff --git a/interface/AvaloniaUI_debug_interface/debug_interface/ViewModels/MainWindowViewModel.cs b/interface/AvaloniaUI_debug_interface/debug_interface/ViewModels/MainWindowViewModel.cs index 7803f2c..c1b33ef 100644 --- a/interface/AvaloniaUI_debug_interface/debug_interface/ViewModels/MainWindowViewModel.cs +++ b/interface/AvaloniaUI_debug_interface/debug_interface/ViewModels/MainWindowViewModel.cs @@ -1,29 +1,19 @@ -// ViewModels/MainWindowViewModel.cs -using CommunityToolkit.Mvvm.ComponentModel; +using System; using System.Collections.ObjectModel; -using System; -using System.Timers; -using debug_interface.ViewModels; +using CommunityToolkit.Mvvm.ComponentModel; +using installer.Model; +using installer.Data; namespace debug_interface.ViewModels { public partial class MainWindowViewModel : ViewModelBase { - // Keep only one definition of MapVM + // 属性定义 [ObservableProperty] - private MapViewModel mapVM; - - public ObservableCollection RedTeamCharacters { get; } - public ObservableCollection BlueTeamCharacters { get; } + private string gameLog = "等待连接..."; [ObservableProperty] - private string someBuildingInfo = "红方建筑信息..."; - - [ObservableProperty] - private string anotherBuildingInfo = "蓝方建筑信息..."; - - [ObservableProperty] - private string currentTime = DateTime.Now.ToString("HH:mm:ss"); + private string currentTime = "00:00"; [ObservableProperty] private int redScore = 0; @@ -32,85 +22,74 @@ namespace debug_interface.ViewModels private int blueScore = 0; [ObservableProperty] - private bool isBlueView = true; - - public bool IsRedView - { - get => !IsBlueView; - set => IsBlueView = !value; - } + private string someBuildingInfo = ""; [ObservableProperty] - private string gameLog = "地图..."; + private string anotherBuildingInfo = ""; - private Timer _timer; + [ObservableProperty] + private int buddhistTeamEconomy = 0; - public MainWindowViewModel() + [ObservableProperty] + private int monstersTeamEconomy = 0; + + [ObservableProperty] + private MapViewModel mapVM; + + // 团队角色集合 + public ObservableCollection RedTeamCharacters { get; } = new(); + public ObservableCollection BlueTeamCharacters { get; } = new(); + + // 构造函数 + public MainWindowViewModel(Logger logger, ConfigData config) : base(logger) { - // Initialize collections first - RedTeamCharacters = new ObservableCollection(); - BlueTeamCharacters = new ObservableCollection(); - - // Initialize characters - for (int i = 0; i < 6; i++) - { - var redChar = new CharacterViewModel() - { - Name = "红方角色" + (i + 1), - Hp = 1000 * (i + 1), - ActiveState = i % 2 == 0 ? "攻击" : "移动", - }; - redChar.PassiveStates.Add("致盲"); - if (i % 3 == 0) redChar.PassiveStates.Add("定身"); - redChar.EquipmentInventory.Add(new EquipmentItem("小血瓶", 2)); - if (i % 2 == 0) - redChar.EquipmentInventory.Add(new EquipmentItem("大护盾", 1)); - - RedTeamCharacters.Add(redChar); - - var blueChar = new CharacterViewModel() - { - Name = "蓝方角色" + (i + 1), - Hp = 1500 + i * 500, - ActiveState = "空置", - }; - blueChar.PassiveStates.Add("隐身"); - blueChar.EquipmentInventory.Add(new EquipmentItem("净化药水", 3)); - if (i % 2 == 1) - blueChar.EquipmentInventory.Add(new EquipmentItem("鞋子", 1)); - - BlueTeamCharacters.Add(blueChar); - } - - // Initialize MapViewModel + // 初始化MapViewModel MapVM = new MapViewModel(); - // Assign random initial positions to characters - Random rnd = new Random(); - foreach (var character in RedTeamCharacters) + // 如果在设计模式下,可以添加一些测试数据 + if (Avalonia.Controls.Design.IsDesignMode) { - character.PosX = rnd.Next(10, 40); - character.PosY = rnd.Next(10, 40); + InitializeDesignTimeData(); } - foreach (var character in BlueTeamCharacters) - { - character.PosX = rnd.Next(10, 40); - character.PosY = rnd.Next(10, 40); - } - - _timer = new Timer(1000); - _timer.Elapsed += Timer_Elapsed; - _timer.Start(); + // 启动UI更新定时器 + StartUiUpdateTimer(); } - private void Timer_Elapsed(object? sender, ElapsedEventArgs e) + // 设计时数据 + private void InitializeDesignTimeData() { - CurrentTime = DateTime.Now.ToString("HH:mm:ss"); - Avalonia.Threading.Dispatcher.UIThread.Post(() => + GameLog = "设计模式 - 模拟数据"; + CurrentTime = "12:34"; + RedScore = 50; + BlueScore = 30; + + // 添加一些测试角色 + for (int i = 0; i < 3; i++) { - OnPropertyChanged(nameof(CurrentTime)); - }); + RedTeamCharacters.Add(new CharacterViewModel + { + CharacterId = i + 1, + Name = $"取经队角色{i + 1}", + Hp = 1000, + ActiveState = "空置" + }); + + BlueTeamCharacters.Add(new CharacterViewModel + { + CharacterId = i + 101, + Name = $"妖怪队角色{i + 1}", + Hp = 1200, + ActiveState = "移动" + }); + } + } + + // 定时器更新方法 + protected override void OnTimerTick(object? sender, EventArgs e) + { + // 更新当前时间显示 + CurrentTime = DateTime.Now.ToString("HH:mm:ss"); } } } \ No newline at end of file diff --git a/interface/AvaloniaUI_debug_interface/debug_interface/ViewModels/MapViewModel.cs b/interface/AvaloniaUI_debug_interface/debug_interface/ViewModels/MapViewModel.cs index b61b8b0..1911830 100644 --- a/interface/AvaloniaUI_debug_interface/debug_interface/ViewModels/MapViewModel.cs +++ b/interface/AvaloniaUI_debug_interface/debug_interface/ViewModels/MapViewModel.cs @@ -1,137 +1,201 @@ -//MapViewModel.cs -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.ObjectModel; using CommunityToolkit.Mvvm.ComponentModel; -using System.Collections.ObjectModel; -using debug_interface.Models; using Avalonia.Media; +using debug_interface.Models; namespace debug_interface.ViewModels { - // 地图视图模型,管理整个 50×50 的地图数据 - public partial class MapViewModel : ObservableObject + public partial class MapViewModel : ViewModelBase { - // 定义地图网格大小为 50(行)× 50(列) - public const int GridSize = 50; + private const int GridSize = 50; - // ObservableCollection 存放 2500 个 MapCell 对象,每个对象代表一个地图格子 - // 数据绑定到视图后,界面会显示出整个地图 - public ObservableCollection MapCells { get; } - public ObservableCollection RedTeamCharacters { get; } - public ObservableCollection BlueTeamCharacters { get; } + [ObservableProperty] + private ObservableCollection mapCells = new(); - public MapViewModel(ObservableCollection redTeam, ObservableCollection blueTeam) - { - MapCells = new ObservableCollection(); - RedTeamCharacters = redTeam; - BlueTeamCharacters = blueTeam; - InitializeDefaultMap(); - } - // 构造函数,用于测试 public MapViewModel() { - MapCells = new ObservableCollection(); - InitializeDefaultMap(); + // 初始化地图单元格 + InitializeMapCells(); } - // 初始化默认地图数据,用于测试效果 - private void InitializeDefaultMap() + private void InitializeMapCells() { - // 遍历所有行和列 - for (int i = 0; i < GridSize; i++) + MapCells.Clear(); + for (int i = 0; i < GridSize * GridSize; i++) { - for (int j = 0; j < GridSize; j++) + MapCells.Add(new MapCell { - // 创建一个 MapCell 对象,并设置行列信息 - var cell = new MapCell - { - CellX = i, - CellY = j, - // 根据坐标决定默认单元格类型 - CellType = GetDefaultCellType(i, j), - DisplayText = "" // 默认无文本显示,可后续根据需要设置 - }; - // 设置显示颜色,根据单元格类型获取颜色 - cell.DisplayColor = new SolidColorBrush(GetColorForCellType(cell.CellType)); - - MapCells.Add(cell); - } + Row = i / GridSize, + Col = i % GridSize, + CellType = MapCellType.Empty, + DisplayText = "", + DisplayColor = new SolidColorBrush(Colors.White), + BackgroundColor = new SolidColorBrush(Colors.LightGray) + }); } } - // 根据单元格在地图中的坐标决定默认类型 - private MapCellType GetDefaultCellType(int i, int j) + // 更新整个地图 + public void UpdateMap(int[,] mapData) { - // 1. 边界(第一行、最后一行、第一列、最后一列)均设为障碍物 - if (i == 0 || i == GridSize - 1 || j == 0 || j == GridSize - 1) - { - return MapCellType.Obstacle; - } - // 2. 在特定位置放置资源点(测试用) - if ((i == 10 && j == 10) || (i == 20 && j == 20) || (i == 30 && j == 30)) - { - return MapCellType.Resource; - } - // 3. 在特定位置放置草丛(测试用) - if ((i == 15 && j == 35) || (i == 35 && j == 15)) - { - return MapCellType.Grass; - } - // 4. 可预留一个建筑点,例如 (25,25) - if (i == 25 && j == 25) - { - return MapCellType.Building; - } - // 5. 其他区域默认为空地 - return MapCellType.OpenLand; - } - - // 根据单元格类型返回对应的颜色(可根据需要调整颜色) - private Color GetColorForCellType(MapCellType type) - { - switch (type) - { - case MapCellType.Obstacle: - return Colors.DarkGray; - case MapCellType.OpenLand: - return Colors.LightGreen; - case MapCellType.Grass: - return Colors.Green; - case MapCellType.Resource: - return Colors.Yellow; - case MapCellType.Building: - return Colors.Orange; - default: - return Colors.Black; - } - } - - // 用于更新地图数据的方法, - // newMapData 是一个 50x50 的二维整型数组,数值应能映射为 MapCellType 枚举值 - public void UpdateMap(int[,] newMapData) - { - if (newMapData.GetLength(0) != GridSize || newMapData.GetLength(1) != GridSize) - throw new ArgumentException("地图数据尺寸不正确"); - - // 遍历二维数组更新每个 MapCell 对象 for (int i = 0; i < GridSize; i++) { for (int j = 0; j < GridSize; j++) { int index = i * GridSize + j; - // 将整型转换为 MapCellType 枚举 - MapCellType newType = (MapCellType)newMapData[i, j]; - var cell = MapCells[index]; - cell.CellType = newType; - // 更新颜色 - cell.DisplayColor = new SolidColorBrush(GetColorForCellType(newType)); - // 如果需要,可以根据新数据更新文本(例如建筑血量、资源剩余) - cell.DisplayText = "123"; // 这里留空,可扩展 + if (index < MapCells.Count) + { + int cellType = mapData[i, j]; + UpdateCellType(MapCells[index], cellType); + } } } + + OnPropertyChanged(nameof(MapCells)); + } + + private void UpdateCellType(MapCell cell, int cellType) + { + // 根据cellType设置单元格属性 + // 这里简化处理 + switch (cellType) + { + case 0: // 空地 + cell.CellType = MapCellType.Empty; + cell.BackgroundColor = new SolidColorBrush(Colors.White); + break; + case 1: // 障碍物 + cell.CellType = MapCellType.Obstacle; + cell.BackgroundColor = new SolidColorBrush(Colors.DarkGray); + break; + case 2: // 资源 + cell.CellType = MapCellType.Resource; + cell.BackgroundColor = new SolidColorBrush(Colors.Green); + break; + default: + cell.CellType = MapCellType.Empty; + cell.BackgroundColor = new SolidColorBrush(Colors.LightGray); + break; + } + } + + // 更新角色位置 + public void UpdateCharacterPosition(long characterId, long teamId, int x, int y, string name) + { + // 简化实现 + int index = x * GridSize + y; + if (index >= 0 && index < MapCells.Count) + { + MapCells[index].DisplayText = name.Substring(0, 1); + MapCells[index].DisplayColor = teamId == 1 + ? new SolidColorBrush(Colors.Red) + : new SolidColorBrush(Colors.Blue); + + OnPropertyChanged(nameof(MapCells)); + } + } + + // 更新建筑 + public void UpdateBuildingCell(int x, int y, string team, string buildingType, int hp) + { + int index = x * GridSize + y; + if (index >= 0 && index < MapCells.Count) + { + MapCells[index].CellType = MapCellType.Building; + MapCells[index].DisplayText = buildingType.Substring(0, 1); + MapCells[index].DisplayColor = team == "取经队" + ? new SolidColorBrush(Colors.DarkRed) + : new SolidColorBrush(Colors.DarkBlue); + + OnPropertyChanged(nameof(MapCells)); + } + } + + // 更新陷阱 + public void UpdateTrapCell(int x, int y, string team, string trapType) + { + int index = x * GridSize + y; + if (index >= 0 && index < MapCells.Count) + { + MapCells[index].CellType = MapCellType.Obstacle; + MapCells[index].DisplayText = trapType.Substring(0, 1); + MapCells[index].DisplayColor = team == "取经队" + ? new SolidColorBrush(Colors.IndianRed) + : new SolidColorBrush(Colors.CornflowerBlue); + + OnPropertyChanged(nameof(MapCells)); + } + } + + // 更新资源 + public void UpdateResourceCell(int x, int y, string resourceType, int process) + { + int index = x * GridSize + y; + if (index >= 0 && index < MapCells.Count) + { + MapCells[index].CellType = MapCellType.Resource; + MapCells[index].DisplayText = process.ToString(); + MapCells[index].DisplayColor = new SolidColorBrush(Colors.DarkGreen); + + OnPropertyChanged(nameof(MapCells)); + } + } + + // 更新额外资源 + public void UpdateAdditionResourceCell(int x, int y, string resourceName, int value) + { + int index = x * GridSize + y; + if (index >= 0 && index < MapCells.Count) + { + MapCells[index].CellType = MapCellType.Resource; + MapCells[index].DisplayText = value.ToString(); + + // 根据资源类型选择颜色 + if (resourceName.Contains("生命池")) + { + MapCells[index].DisplayColor = new SolidColorBrush(Colors.LightGreen); + } + else if (resourceName.Contains("疯人")) + { + MapCells[index].DisplayColor = new SolidColorBrush(Colors.OrangeRed); + } + else + { + MapCells[index].DisplayColor = new SolidColorBrush(Colors.Purple); + } + + OnPropertyChanged(nameof(MapCells)); + } } } -} + + //public enum MapCellType + //{ + // Empty, + // Obstacle, + // Building, + // Resource, + // Character + //} + + //public partial class MapCell : ViewModelBase + //{ + // [ObservableProperty] + // private int row; + + // [ObservableProperty] + // private int col; + + // [ObservableProperty] + // private MapCellType cellType; + + // [ObservableProperty] + // private string displayText = ""; + + // [ObservableProperty] + // private IBrush displayColor = new SolidColorBrush(Colors.Black); + + // [ObservableProperty] + // private IBrush backgroundColor = new SolidColorBrush(Colors.White); + //} +} \ 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 8a1edbf..bb3ecb7 100644 --- a/interface/AvaloniaUI_debug_interface/debug_interface/ViewModels/ViewModelBase.cs +++ b/interface/AvaloniaUI_debug_interface/debug_interface/ViewModels/ViewModelBase.cs @@ -1,4 +1,3 @@ -//ViewModeBase.cs using System; using Avalonia.Threading; diff --git a/interface/AvaloniaUI_debug_interface/debug_interface/debug_interface.csproj b/interface/AvaloniaUI_debug_interface/debug_interface/debug_interface.csproj index b400419..6d85975 100644 --- a/interface/AvaloniaUI_debug_interface/debug_interface/debug_interface.csproj +++ b/interface/AvaloniaUI_debug_interface/debug_interface/debug_interface.csproj @@ -1,24 +1,22 @@  - - 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) - - @@ -30,26 +28,26 @@ + - - - - - - - - - None - All - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - + + + + + + + + None + All + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/logic/GameClass/GameObj/Character.cs b/logic/GameClass/GameObj/Character.cs index 7b1bb65..d9e59e7 100644 --- a/logic/GameClass/GameObj/Character.cs +++ b/logic/GameClass/GameObj/Character.cs @@ -253,6 +253,7 @@ public class Character : Movable, ICharacter Shield = new(0); NiuShield = new(0); AttackSize = new(Occupation.BaseAttackSize); + HP = new(Occupation.MaxHp); AttackPower = new(Occupation.AttackPower); MoneyPool = pool; Init(); @@ -340,10 +341,6 @@ public class Character : Movable, ICharacter } case EquipmentType.BERSERK_POTION: { - if (IsBerserk) - { - return false; - } IsBerserk = true; BerserkTime = Environment.TickCount64; SetCharacterState(CharacterState1, CharacterState.BERSERK);//此处缺少时间限制 diff --git a/logic/Gaming/CharacterManager.cs b/logic/Gaming/CharacterManager.cs index e42b3a2..6e6fc88 100644 --- a/logic/Gaming/CharacterManager.cs +++ b/logic/Gaming/CharacterManager.cs @@ -299,6 +299,7 @@ namespace Gaming character.Shoes.SubPositiveV(GameData.CrazySpeed); character.ATKFrequency = GameData.ATKFreq; character.BerserkTime = long.MaxValue; + character.IsBerserk = false; } } } @@ -314,7 +315,15 @@ namespace Gaming character.IsShoes = false; } } - + } + public void CheckInvisibility(Character character) + { + int nowtime = gameMap.Timer.NowTime(); + if (nowtime >= GameData.SevenMinutes + ) + { + character.visible = true; + } } } } diff --git a/logic/Gaming/Game.cs b/logic/Gaming/Game.cs index 8b83c86..3eeb302 100644 --- a/logic/Gaming/Game.cs +++ b/logic/Gaming/Game.cs @@ -35,7 +35,7 @@ namespace Gaming return GameObj.invalidID; } teamList[(int)playerInitInfo.teamID].CharacterNum.Add(1); - if (gameMap.TeamExists(playerInitInfo.teamID)) + if (!gameMap.TeamExists(playerInitInfo.teamID)) { return GameObj.invalidID; } @@ -423,6 +423,18 @@ namespace Gaming { if (!gameMap.Timer.IsGaming) return false; + int nowtime = gameMap.Timer.NowTime(); + if (nowtime >= GameData.SevenMinutes) + { + if (equiptype == EquipmentType.INVISIBILITY_POTION) + { + return false; + } + } + else if (equiptype == EquipmentType.BERSERK_POTION) + { + return false; + } Character? character = gameMap.FindCharacterInPlayerID(teamID, characterID); if (character != null && character.IsRemoved == false) return equipManager.GetEquipment(character, equiptype); diff --git a/logic/Preparation/Utility/GameData.cs b/logic/Preparation/Utility/GameData.cs index 3ef8aae..9b0c142 100644 --- a/logic/Preparation/Utility/GameData.cs +++ b/logic/Preparation/Utility/GameData.cs @@ -214,5 +214,6 @@ namespace Preparation.Utility public const int InitialMoney = 5000; public const int CharacterTotalNumMax = 6; public const double RecycleRate = 0.5; + public const int SevenMinutes = 420000; } }