mirror of
https://github.com/denglihong2007/CRSim
synced 2026-08-08 10:45:35 +08:00
feat: 支持车站资源插件
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using CRSim.Core.Models.Plugin;
|
||||
using CRSim.Core.Models;
|
||||
using CRSim.Core.Models.Plugin;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace CRSim.Core.Abstractions;
|
||||
@@ -28,4 +29,5 @@ public interface IPluginService
|
||||
Task InstallPluginLocalAsync(string filePath);
|
||||
Task PackPluginAsync(PluginInfo plugin, string filePath);
|
||||
Task LoadOnlinePluginsAsync();
|
||||
List<(string, Station)> GetStationData();
|
||||
}
|
||||
@@ -83,4 +83,7 @@ public partial class PluginInfo : ObservableRecipient
|
||||
|
||||
[ObservableProperty]
|
||||
private StyleInfo? styleInfo;
|
||||
|
||||
[ObservableProperty]
|
||||
private Json? data;
|
||||
}
|
||||
@@ -65,6 +65,7 @@ public class PluginService(INetworkService networkService, ISettingsService sett
|
||||
PluginFolderPath = Path.GetFullPath(pluginDir),
|
||||
RealIconPath = Path.Combine(Path.GetFullPath(pluginDir), "icon.png"),
|
||||
StyleInfo = manifest.Type == "ScreenStyle" ? JsonSerializer.Deserialize(File.ReadAllText(Path.Combine(Path.GetFullPath(pluginDir), StyleInfoFileName)),JsonContextWithCamelCase.Default.StyleInfo) : null,
|
||||
Data = manifest.Type == "StationData" ? JsonSerializer.Deserialize(File.ReadAllText(Path.Combine(Path.GetFullPath(pluginDir), manifest.EntranceAssembly)), JsonContext.Default.Json) : null,
|
||||
};
|
||||
if (info.IsUninstalling)
|
||||
{
|
||||
@@ -77,8 +78,15 @@ public class PluginService(INetworkService networkService, ISettingsService sett
|
||||
}
|
||||
IPluginService.LoadedPluginsInternal.Add(info);
|
||||
}
|
||||
foreach (var info in IPluginService.LoadedPluginsInternal.Where(x => x.Manifest.Type == "StationData"))
|
||||
{
|
||||
if (info.LoadStatus != PluginLoadStatus.Disabled)
|
||||
{
|
||||
info.LoadStatus = PluginLoadStatus.Loaded;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var info in IPluginService.LoadedPluginsInternal)
|
||||
foreach (var info in IPluginService.LoadedPluginsInternal.Where(x => x.Manifest.Type == "ScreenStyle"))
|
||||
{
|
||||
if(info.LoadStatus == PluginLoadStatus.Disabled)
|
||||
{
|
||||
@@ -88,7 +96,7 @@ public class PluginService(INetworkService networkService, ISettingsService sett
|
||||
var pluginDir = info.PluginFolderPath;
|
||||
try
|
||||
{
|
||||
Console.WriteLine("尝试加载插件: " + manifest.Id);
|
||||
Console.WriteLine("尝试加载插件DLL: " + manifest.Id);
|
||||
var fullPath = Path.GetFullPath(Path.Combine(pluginDir, manifest.EntranceAssembly));
|
||||
var loadContext = new PluginLoadContext(fullPath);
|
||||
var assembly = loadContext.LoadFromAssemblyPath(fullPath);
|
||||
@@ -111,11 +119,11 @@ public class PluginService(INetworkService networkService, ISettingsService sett
|
||||
services.AddSingleton(typeof(PluginBase), entranceObj);
|
||||
services.AddSingleton(entrance, entranceObj);
|
||||
info.LoadStatus = PluginLoadStatus.Loaded;
|
||||
Console.WriteLine($"加载插件成功: {pluginDir} ({manifest.Version})");
|
||||
Console.WriteLine($"加载插件DLL成功: {pluginDir} ({manifest.Version})");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"加载插件失败: {ex}");
|
||||
Console.WriteLine($"加载插件DLL失败: {ex}");
|
||||
info.Exception = ex;
|
||||
info.LoadStatus = PluginLoadStatus.Error;
|
||||
}
|
||||
@@ -221,7 +229,14 @@ public class PluginService(INetworkService networkService, ISettingsService sett
|
||||
IPluginService.LoadedPluginsInternal.Add(info);
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public List<(string, Station)> GetStationData()
|
||||
{
|
||||
var result = IPluginService.LoadedPluginsInternal
|
||||
.Where(p => p.Manifest.Type == "StationData" && p.Data is not null)
|
||||
.SelectMany(p => p.Data.Stations.Select(s => (p.Manifest.Name, s)))
|
||||
.ToList();
|
||||
return result;
|
||||
}
|
||||
public async Task PackPluginAsync(PluginInfo plugin, string filePath)
|
||||
{
|
||||
var pluginDir = plugin.PluginFolderPath;
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
<RadioButton x:Name="Blank" GroupName="options" Content="新建空白车站" Margin="0,0,0,4" IsChecked="True" Checked="Validate"/>
|
||||
<TextBox x:Name="textBoxBlank" IsEnabled="{x:Bind ToBoolean(Blank.IsChecked), Mode=OneWay}"
|
||||
PlaceholderText="车站名" Margin="0,0,0,8" TextChanged="Validate"/>
|
||||
<RadioButton x:Name="Plugin" GroupName="options" Content="从插件资源导入" Margin="0,0,0,4" Checked="Validate"/>
|
||||
<ComboBox x:Name="comboBoxPlugin" IsEnabled="{x:Bind ToBoolean(Plugin.IsChecked), Mode=OneWay}" HorizontalAlignment="Stretch"
|
||||
PlaceholderText="车站" Margin="0,0,0,8" SelectionChanged="Validate" ItemsSource="{x:Bind StationRecords}" DisplayMemberPath="Name" SelectedValuePath="Station"/>
|
||||
<RadioButton x:Name="btnFile" GroupName="options" Content="从车站文件导入" Margin="0,0,0,4" Checked="Validate"/>
|
||||
<ContentControl IsEnabled="{x:Bind ToBoolean(btnFile.IsChecked), Mode=OneWay}" HorizontalContentAlignment="Stretch">
|
||||
<Grid Margin="0,0,0,8">
|
||||
|
||||
@@ -4,9 +4,16 @@ public sealed partial class CreateStationDialog : Page
|
||||
|
||||
private readonly IDialogService _dialogService = App.GetService<IDialogService>();
|
||||
|
||||
private readonly IPluginService _pluginService = App.GetService<IPluginService>();
|
||||
|
||||
private Station? _parsedStation = null;
|
||||
|
||||
public Station? GeneratedStation => ToBoolean(Blank.IsChecked) ? new Station
|
||||
private record StationRecord(string Name, Station Station);
|
||||
|
||||
private List<StationRecord> StationRecords { get; }
|
||||
|
||||
public Station? GeneratedStation => ToBoolean(Plugin.IsChecked) ? (Station)comboBoxPlugin.SelectedValue :
|
||||
ToBoolean(Blank.IsChecked) ? new Station
|
||||
{
|
||||
Name = textBoxBlank.Text,
|
||||
Platforms = [],
|
||||
@@ -23,12 +30,16 @@ public sealed partial class CreateStationDialog : Page
|
||||
|
||||
private void Validate(object sender, object e)
|
||||
{
|
||||
if (textBoxBlank == null) return;
|
||||
if (textBoxBlank == null) return;//检查窗体初始化
|
||||
bool isValid;
|
||||
if (ToBoolean(Blank.IsChecked))
|
||||
{
|
||||
isValid = !string.IsNullOrWhiteSpace(textBoxBlank.Text);
|
||||
}
|
||||
else if(ToBoolean(Plugin.IsChecked))
|
||||
{
|
||||
isValid = comboBoxPlugin.SelectedValue is not null;
|
||||
}
|
||||
else
|
||||
{
|
||||
isValid = _parsedStation != null;
|
||||
@@ -38,6 +49,7 @@ public sealed partial class CreateStationDialog : Page
|
||||
|
||||
public CreateStationDialog(Action<bool> onValidityChanged)
|
||||
{
|
||||
StationRecords = _pluginService.GetStationData().Select(x => new StationRecord($"{x.Item1}-{x.Item2.Name}",x.Item2)).ToList();
|
||||
_onValidityChanged = onValidityChanged;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user