Skip to content

Commit

Permalink
feat: 完善版本与插件项目模板
Browse files Browse the repository at this point in the history
  • Loading branch information
SlimeNull committed Dec 29, 2024
1 parent a6e1661 commit c0686d8
Show file tree
Hide file tree
Showing 12 changed files with 334 additions and 35 deletions.
14 changes: 14 additions & 0 deletions src/CurvaLauncher.Common/CurvaLauncher.Common.csproj
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<Import Project="../CurvaLauncher.props" />

<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
Expand All @@ -11,6 +13,18 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RootNamespace>CurvaLauncher</RootNamespace>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
<Description>Common library of CurvaLauncher</Description>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/OrgEleCho/CurvaLauncher</RepositoryUrl>
<PackageIcon>Icon128.png</PackageIcon>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>

<ItemGroup>
<None Include="..\..\assets\Icon128.png">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>

</Project>
20 changes: 18 additions & 2 deletions src/CurvaLauncher.Plugins/CurvaLauncher.Plugins.csproj
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<Import Project="../CurvaLauncher.props" />

<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<RootNamespace>CurvaLauncher</RootNamespace>

<UseWPF>true</UseWPF>
<EnableWindowsTargeting>true</EnableWindowsTargeting>

<Description>Plugin library of CurvaLauncher</Description>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/OrgEleCho/CurvaLauncher</RepositoryUrl>
<PackageIcon>Icon128.png</PackageIcon>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>

<ItemGroup>
<None Include="..\..\assets\Icon128.png">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\CurvaLauncher.Common\CurvaLauncher.Common.csproj" />
</ItemGroup>
Expand Down
5 changes: 5 additions & 0 deletions src/CurvaLauncher.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Project>
<PropertyGroup>
<Version>0.7.1-beta</Version>
</PropertyGroup>
</Project>
18 changes: 18 additions & 0 deletions src/CurvaLauncher.sln
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "CurvaLauncher.Plugins.SHLoa
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CurvaLauncher.Plugins.Everything", "Plugins\CurvaLauncher.Plugins.Everything\CurvaLauncher.Plugins.Everything.csproj", "{C7AC6C75-89C6-42E5-8D2A-D06994949F05}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F36EDE5B-9C67-44F4-87A9-792390FECF85}"
ProjectSection(SolutionItems) = preProject
CurvaLauncher.props = CurvaLauncher.props
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Templates", "Templates", "{45D0660D-436E-4419-AEB9-B6ED5BC3E0ED}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CurvaLauncher.PluginTemplate", "Templates\CurvaLauncher.PluginTemplate\CurvaLauncher.PluginTemplate.csproj", "{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -165,6 +174,14 @@ Global
{C7AC6C75-89C6-42E5-8D2A-D06994949F05}.Release|Any CPU.Build.0 = Release|Any CPU
{C7AC6C75-89C6-42E5-8D2A-D06994949F05}.Release|x64.ActiveCfg = Release|x64
{C7AC6C75-89C6-42E5-8D2A-D06994949F05}.Release|x64.Build.0 = Release|x64
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Debug|Any CPU.Build.0 = Debug|Any CPU
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Debug|x64.ActiveCfg = Debug|Any CPU
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Debug|x64.Build.0 = Debug|Any CPU
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Release|Any CPU.ActiveCfg = Release|Any CPU
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Release|Any CPU.Build.0 = Release|Any CPU
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Release|x64.ActiveCfg = Release|Any CPU
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -181,6 +198,7 @@ Global
{F3F6F783-4636-457F-80E1-CC489F524B43} = {BAACD50D-2F94-4A65-8B13-49031D617CAC}
{8CFC1C29-51AA-45ED-A91F-01F513182002} = {4A86F98E-B276-4F75-9847-8D0E4280D887}
{C7AC6C75-89C6-42E5-8D2A-D06994949F05} = {BAACD50D-2F94-4A65-8B13-49031D617CAC}
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560} = {45D0660D-436E-4419-AEB9-B6ED5BC3E0ED}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3FC4E11A-3D67-43DE-84D8-DCA1841F0D71}
Expand Down
4 changes: 2 additions & 2 deletions src/CurvaLauncher/CurvaLauncher.csproj
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<Import Project="../CurvaLauncher.props"/>

<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
Expand All @@ -12,8 +14,6 @@
<ApplicationManifest>app.manifest</ApplicationManifest>
<ApplicationIcon>Assets\Icon.ico</ApplicationIcon>

<Version>0.7.1-beta</Version>

<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
</PropertyGroup>
Expand Down
122 changes: 91 additions & 31 deletions src/CurvaLauncher/Services/PluginService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
using CurvaLauncher.Plugins;
using CurvaLauncher.PluginInteraction;
using System.Diagnostics;
using System.IO.Compression;
using System.Runtime.Loader;

namespace CurvaLauncher.Services;

Expand Down Expand Up @@ -50,65 +52,123 @@ private void CoreLoadPlugins(out List<PluginInstance> plugins)
plugins = new List<PluginInstance>();

var dir = EnsurePluginDirectory();
var dllFiles = dir.GetFiles("*.dll");

AppConfig config = _configService.Config;

foreach (FileInfo dllFile in dllFiles)
if (CoreLoadPlugin(config, dllFile.FullName, out PluginInstance? plugin))
foreach (var dllFile in dir.GetFiles("*.dll"))
{
if (CoreLoadDllPlugin(config, dllFile.FullName, out PluginInstance? plugin))
{
plugins.Add(plugin);
}
}

foreach (var zipFile in dir.GetFiles("*.zip"))
{
if (CoreLoadZipPlugin(config, zipFile.FullName, out PluginInstance? plugin))
{
plugins.Add(plugin);
}
}
}

private bool CoreLoadPlugin(AppConfig config, string dllFilePath, [NotNullWhen(true)] out PluginInstance? pluginInstance)
private bool CoreLoadPluginFromAssembly(AppConfig config, Assembly assembly, [NotNullWhen(true)] out PluginInstance? pluginInstance)
{
pluginInstance = null;

try
{
var assembly = Assembly.LoadFile(dllFilePath);

Type? pluginType = assembly.ExportedTypes
Type? pluginType = assembly.ExportedTypes
.Where(type => type.IsAssignableTo(typeof(ISyncPlugin)) || type.IsAssignableTo(typeof(IAsyncPlugin)))
.FirstOrDefault();

if (pluginType == null)
return false;
if (pluginType == null)
return false;

if (!PluginInstance.TryCreate(pluginType, out pluginInstance))
return false;
if (!PluginInstance.TryCreate(pluginType, out pluginInstance))
return false;

var typeName = pluginType.FullName!;
var typeName = pluginType.FullName!;

if (config.Plugins.TryGetValue(typeName, out var pluginConfig))
{
var props = pluginInstance.Plugin.GetType().GetProperties()
if (config.Plugins.TryGetValue(typeName, out var pluginConfig))
{
var props = pluginInstance.Plugin.GetType().GetProperties()
.Where(p => p.GetCustomAttribute<PluginOptionAttribute>() is not null
|| p.GetCustomAttribute<PluginI18nOptionAttribute>() is not null);

if (pluginConfig.Options != null)
if (pluginConfig.Options != null)
{
foreach (var property in props)
{
foreach (var property in props)
if (pluginConfig.Options.TryGetPropertyValue(property.Name, out var value))
{
if (pluginConfig.Options.TryGetPropertyValue(property.Name, out var value))
{
var type = property.PropertyType;
var val = JsonSerializer.Deserialize(value, type);
property.SetValue(pluginInstance.Plugin, val);
}
var type = property.PropertyType;
var val = JsonSerializer.Deserialize(value, type);
property.SetValue(pluginInstance.Plugin, val);
}
}

pluginInstance.IsEnabled = pluginConfig.IsEnabled;
pluginInstance.Weight = pluginConfig.Weight;
}
else

pluginInstance.IsEnabled = pluginConfig.IsEnabled;
pluginInstance.Weight = pluginConfig.Weight;
}
else
{
pluginInstance.IsEnabled = true;
}

return true;
}

private bool CoreLoadDllPlugin(AppConfig config, string dllFilePath, [NotNullWhen(true)] out PluginInstance? pluginInstance)
{
pluginInstance = null;

try
{
var assembly = Assembly.LoadFile(dllFilePath);
return CoreLoadPluginFromAssembly(config, assembly, out pluginInstance);
}
catch (Exception ex)
{
Debug.WriteLine($"Plugin load failed, {ex}");
return false;
}
}

private bool CoreLoadZipPlugin(AppConfig config, string zipFilePath, [NotNullWhen(true)] out PluginInstance? pluginInstance)
{
pluginInstance = null;

try
{
using var zipFile = File.OpenRead(zipFilePath);
using var zipArchive = new ZipArchive(zipFile, ZipArchiveMode.Read);
var assemblyLoadContext = new AssemblyLoadContext(null, false);

foreach (var entry in zipArchive.Entries)
{
pluginInstance.IsEnabled = true;
if (!entry.FullName.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
{
continue;
}

using var entryStream = entry.Open();

try
{
var assembly = assemblyLoadContext.LoadFromStream(entryStream);

if (pluginInstance is null)
{
CoreLoadPluginFromAssembly(config, assembly, out pluginInstance);
}
}
catch (Exception ex)
{
Debug.WriteLine($"DLL load failed, {ex}");
}
}

return true;
return pluginInstance is not null;
}
catch (Exception ex)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"$schema": "http://json.schemastore.org/template",
"author": "EleCho",
"identity": "CurvaLauncher.PluginTemplate",
"classifications": [
"CurvaLauncher",
"Library"
],
"name": "CurvaLauncher Plugin",
"description": "Creates a CurvaLauncher plugin",
"tags": {
"language": "C#",
"type": "project"
},
"shortName": "clp",
"sourceName": "CurvaLauncher.PluginTemplate",
"symbols": {
"EnableI18n": {
"type": "parameter",
"datatype": "bool",
"defaultValue": "true"
}
},
"sources": [
{
"modifiers": [
{
"condition": "(!EnableI18n)",
"exclude": [
"I18n/EnUs.xaml",
"I18n/ZhHans.xaml"
]
}
]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CurvaLauncher.Plugins" Version="0.7.1-beta" />
</ItemGroup>

<ItemGroup>
<Page Include="I18n\EnUs.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="I18n\ZhHans.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>

</Project>
9 changes: 9 additions & 0 deletions src/Templates/CurvaLauncher.PluginTemplate/I18n/EnUs.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String x:Key="StrPluginName">Sample Plugin</sys:String>
<sys:String x:Key="StrPluginDescription">This is a plugin with i18n support</sys:String>

<sys:String x:Key="StrTestResultTitle">Test Plugin</sys:String>
<sys:String x:Key="StrTestResultDescription">Your plugin is running well</sys:String>
</ResourceDictionary>
9 changes: 9 additions & 0 deletions src/Templates/CurvaLauncher.PluginTemplate/I18n/ZhHans.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String x:Key="StrPluginName">示例插件</sys:String>
<sys:String x:Key="StrPluginDescription">这是一个支持本地化的插件</sys:String>

<sys:String x:Key="StrTestResultTitle">测试插件</sys:String>
<sys:String x:Key="StrTestResultDescription">你的插件运行良好</sys:String>
</ResourceDictionary>
Loading

0 comments on commit c0686d8

Please sign in to comment.