Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion source/@MasterVersion.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v11.0.8
v11.1.0
4 changes: 2 additions & 2 deletions source/ACT.Hojoring.Common/Version.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Reflection;

[assembly: AssemblyVersion("11.0.0.8")]
[assembly: AssemblyFileVersion("11.0.0.8")]
[assembly: AssemblyVersion("11.1.0.0")]
[assembly: AssemblyFileVersion("11.1.0.0")]
83 changes: 82 additions & 1 deletion source/ACT.Hojoring.Shared/AssemblyResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,15 @@ public static class AssemblyResolver
private static bool isConflictChecked = false;
private static readonly object ConflictLock = new object();

// Costuraに埋め込まれているアセンブリ名のリスト
private static readonly HashSet<string> EmbeddedAssemblies = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

public static void Initialize(
Func<string> directoryResolver)
{
// 埋め込みアセンブリ名をスキャンして収集
ScanEmbeddedAssemblies();

DirectoryResolvers.Add(directoryResolver);
AppDomain.CurrentDomain.AssemblyResolve += CustomAssemblyResolve;

Expand All @@ -29,6 +35,63 @@ public static void Initialize(
}
}

private static void ScanEmbeddedAssemblies()
{
try
{
// 現在のAppDomainにロードされている全アセンブリを走査
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
var name = asm.GetName().Name;
if (string.IsNullOrEmpty(name)) continue;

// Hojoring関連アセンブリのみを走査対象にして無関係なスキャンを避ける
if (name.StartsWith("ACT.Hojoring", StringComparison.OrdinalIgnoreCase) ||
name.StartsWith("FFXIV.Framework", StringComparison.OrdinalIgnoreCase) ||
name.StartsWith("ACT.SpecialSpellTimer", StringComparison.OrdinalIgnoreCase) ||
name.StartsWith("ACT.TTSYukkuri", StringComparison.OrdinalIgnoreCase) ||
name.StartsWith("ACT.UltraScouter", StringComparison.OrdinalIgnoreCase) ||
name.StartsWith("ACT.XIVLog", StringComparison.OrdinalIgnoreCase))
{
var resourceNames = asm.GetManifestResourceNames();
if (resourceNames == null) continue;

foreach (var resName in resourceNames)
{
if (resName.StartsWith("costura.", StringComparison.OrdinalIgnoreCase))
{
string cleanName = resName.Substring("costura.".Length);
if (cleanName.EndsWith(".dll.compressed", StringComparison.OrdinalIgnoreCase))
{
cleanName = cleanName.Substring(0, cleanName.Length - ".dll.compressed".Length);
}
else if (cleanName.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
{
cleanName = cleanName.Substring(0, cleanName.Length - ".dll".Length);
}

if (!string.IsNullOrEmpty(cleanName))
{
EmbeddedAssemblies.Add(cleanName);
}
}
}
}
}
catch
{
// 個別アセンブリのスキャン失敗は無視
}
}
}
catch
{
// 全体的な例外は無視して安全性を確保
}
}

private static void CheckConflicts(string baseDir)
{
try
Expand Down Expand Up @@ -117,7 +180,7 @@ private static void ShowConflictWarning(List<string> conflicts)
$"■ 競合アセンブリの一覧:\n{details}\n\n" +
$"【推奨する解決方法】\n" +
$"1. ACTの「Plugins」➔「Plugin Listing」タブを開きます。\n" +
$"2. 「ACT.SpecialSpellTimer.dll」や「ACT.TTSYukkuri.dll」などのHojoringプラグインを右側の『UP (⬆️)』ボタンでリストの最上部(FFXIV_ACT_Plugin.dllのすぐ下)に引き上げてください。\n" +
$"2. 「ACT.SpecialSpellTimer.dll」や「ACT.TTSYukkuri.dll」などのHojoringプラグインを, 右側の『UP (⬆️)』ボタンでリストの最上部(FFXIV_ACT_Plugin.dllのすぐ下)に引き上げてください。\n" +
$"3. OverlayPluginやCactbotなどの併用プラグインをすべて最新版にアップデートしてください。\n" +
$"4. ACTを再起動してください。";

Expand Down Expand Up @@ -149,6 +212,24 @@ private static void ShowConflictWarning(List<string> conflicts)

private static Assembly CustomAssemblyResolve(object sender, ResolveEventArgs e)
{
try
{
var asmName = new AssemblyName(e.Name);
if (asmName != null && !string.IsNullOrEmpty(asmName.Name))
{
// Costura埋め込み対象のアセンブリである場合、物理ファイルからのロードを回避する。
// nullを返すことで.NET FrameworkはCostura自身のハンドラでアセンブリを解決する。
if (EmbeddedAssemblies.Contains(asmName.Name))
{
return null;
}
}
}
catch
{
// Ignore
}

var dirs = new List<string>();

foreach (var directoryResolver in DirectoryResolvers)
Expand Down
38 changes: 33 additions & 5 deletions source/ACT.Hojoring.Updater/AtomicUpdater.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
Expand Down Expand Up @@ -92,6 +92,8 @@ private static void ConfigureLogging()
public const string OldFileSuffix = ".old";
private static bool executed = false;



/// <summary>
/// 現在のプラグインディレクトリから .new ファイルを探し、可能な限り即時置換します。
/// 置換できなかったファイルは自動的に ACT 終了後のバッチ処理に回されます。
Expand All @@ -108,7 +110,8 @@ public static void Apply()
DeleteOldFiles(targetDir);

var newFiles = Directory.GetFiles(targetDir, "*" + NewFileSuffix, SearchOption.AllDirectories);
if (newFiles.Length == 0) return;
var pendingDeletes = Directory.GetFiles(targetDir, "*.pending_delete", SearchOption.AllDirectories);
if (newFiles.Length == 0 && pendingDeletes.Length == 0) return;

Log($"[AtomicUpdater] .new files detected. Starting replacement in {targetDir}");

Expand Down Expand Up @@ -143,7 +146,7 @@ public static void Apply()
}
}

if (lockedFiles.Count > 0)
if (lockedFiles.Count > 0 || pendingDeletes.Length > 0)
{
ScheduleExternalUpdate(lockedFiles);
}
Expand All @@ -167,9 +170,10 @@ public static void RequestExternalUpdate()
if (string.IsNullOrEmpty(targetDir)) return;

var newFiles = Directory.GetFiles(targetDir, "*" + NewFileSuffix, SearchOption.AllDirectories);
if (newFiles.Length == 0) return;
var pendingDeletes = Directory.GetFiles(targetDir, "*.pending_delete", SearchOption.AllDirectories);
if (newFiles.Length == 0 && pendingDeletes.Length == 0) return;

Log($"[AtomicUpdater] External update requested. {newFiles.Length} files scheduled.");
Log($"[AtomicUpdater] External update requested. {newFiles.Length} files scheduled, {pendingDeletes.Length} deletes scheduled.");
ScheduleExternalUpdate(newFiles);
}

Expand Down Expand Up @@ -206,6 +210,9 @@ private static bool IsFileLocked(string filePath)

private static void ScheduleExternalUpdate(IEnumerable<string> newFiles)
{
string targetDir = GetTargetDirectory();
if (string.IsNullOrEmpty(targetDir)) return;

try
{
var batchPath = Path.Combine(Path.GetTempPath(), $"hojoring_atomic_swap_{Guid.NewGuid():N}.bat");
Expand Down Expand Up @@ -245,6 +252,27 @@ private static void ScheduleExternalUpdate(IEnumerable<string> newFiles)
sw.WriteLine($")");
}

// 不要となったDLL(保留削除)のクリーンアップを更新(移動)処理の後に実行する
try
{
var pendingDeletes = Directory.GetFiles(targetDir, "*.pending_delete", SearchOption.AllDirectories);
if (pendingDeletes.Length > 0)
{
sw.WriteLine("echo 不要なアセンブリをクリーンアップしています...");
foreach (var pdFile in pendingDeletes)
{
string targetPath = pdFile.Substring(0, pdFile.Length - ".pending_delete".Length);
string fileName = Path.GetFileName(targetPath);

sw.WriteLine($"echo クリーンアップ中: {fileName}");
sw.WriteLine($"if exist \"{targetPath}\" attrib -r \"{targetPath}\" > nul");
sw.WriteLine($"del /f /q \"{targetPath}\" > nul 2>&1");
sw.WriteLine($"del /f /q \"{pdFile}\" > nul 2>&1");
}
}
}
catch { }

sw.WriteLine($"echo %date% %time% [INFO ] [Batch] External update session completed. >> \"{logFile}\"");
sw.WriteLine("echo すべての更新が完了しました。");
sw.WriteLine("pause");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
Expand Down Expand Up @@ -367,6 +367,14 @@
<PackageReference Include="System.Text.RegularExpressions">
<Version>4.3.1</Version>
</PackageReference>
<PackageReference Include="Fody">
<Version>6.9.3</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Costura.Fody">
<Version>6.0.0</Version>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Content Include="resources\icon\Common\Apple.png">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Costura IncludeDebugSymbols="false">
<IncludeAssemblies>
RazorLight
Microsoft.AspNetCore.Html.Abstractions
Microsoft.AspNetCore.Http.Abstractions
Microsoft.AspNetCore.Http.Features
Microsoft.AspNetCore.Mvc.Razor.Extensions
Microsoft.AspNetCore.Razor
Microsoft.AspNetCore.Razor.Language
Microsoft.AspNetCore.Razor.Runtime
Microsoft.CodeAnalysis.Razor
Microsoft.Extensions.Caching.Abstractions
Microsoft.Extensions.Caching.Memory
Microsoft.Extensions.Configuration.Abstractions
Microsoft.Extensions.DependencyInjection
Microsoft.Extensions.DependencyInjection.Abstractions
Microsoft.Extensions.FileProviders.Abstractions
Microsoft.Extensions.FileProviders.Physical
Microsoft.Extensions.FileSystemGlobbing
Microsoft.Extensions.Hosting.Abstractions
Microsoft.Extensions.Logging.Abstractions
Microsoft.Extensions.Options
Microsoft.Extensions.Primitives
Microsoft.IO.RecyclableMemoryStream
SixLabors.Fonts
SixLabors.ImageSharp
NPOI.Core
NPOI.OOXML
NPOI.OpenXml4Net
NPOI.OpenXmlFormats
ICSharpCode.SharpZipLib
Enums.NET
BouncyCastle.Cryptography
MathNet.Numerics
Xceed.Wpf.AvalonDock
Xceed.Wpf.AvalonDock.Themes.Aero
Xceed.Wpf.AvalonDock.Themes.Metro
Xceed.Wpf.AvalonDock.Themes.VS2010
Xceed.Wpf.Toolkit
ICSharpCode.AvalonEdit
Markdig.Signed
Hjson
MahApps.Metro.IconPacks
MahApps.Metro.IconPacks.Core
MahApps.Metro.IconPacks.BootstrapIcons
MahApps.Metro.IconPacks.BoxIcons
MahApps.Metro.IconPacks.Codicons
MahApps.Metro.IconPacks.Coolicons
MahApps.Metro.IconPacks.Entypo
MahApps.Metro.IconPacks.EvaIcons
MahApps.Metro.IconPacks.FeatherIcons
MahApps.Metro.IconPacks.FileIcons
MahApps.Metro.IconPacks.Fontaudio
MahApps.Metro.IconPacks.FontAwesome
MahApps.Metro.IconPacks.Fontisto
MahApps.Metro.IconPacks.ForkAwesome
MahApps.Metro.IconPacks.Ionicons
MahApps.Metro.IconPacks.JamIcons
MahApps.Metro.IconPacks.Material
MahApps.Metro.IconPacks.MaterialDesign
MahApps.Metro.IconPacks.MaterialLight
MahApps.Metro.IconPacks.Microns
MahApps.Metro.IconPacks.Modern
MahApps.Metro.IconPacks.Octicons
MahApps.Metro.IconPacks.PicolIcons
MahApps.Metro.IconPacks.PixelartIcons
MahApps.Metro.IconPacks.RadixIcons
MahApps.Metro.IconPacks.RemixIcon
MahApps.Metro.IconPacks.RPGAwesome
MahApps.Metro.IconPacks.SimpleIcons
MahApps.Metro.IconPacks.Typicons
MahApps.Metro.IconPacks.Unicons
MahApps.Metro.IconPacks.VaadinIcons
MahApps.Metro.IconPacks.WeatherIcons
MahApps.Metro.IconPacks.Zondicons
Microsoft.CodeAnalysis
Microsoft.CodeAnalysis.CSharp
Microsoft.CodeAnalysis.CSharp.Scripting
Microsoft.CodeAnalysis.Scripting
System.Collections.Immutable
System.Reflection.Metadata
System.Text.Encoding.CodePages
System.Threading.Tasks.Extensions
FontAwesome.WPF
System.Text.Encodings.Web
</IncludeAssemblies>
</Costura>
</Weavers>
Loading