From ee967567b822b5e3d92475e09593120b95754e9f Mon Sep 17 00:00:00 2001 From: hanachiru Date: Wed, 27 Aug 2025 02:27:59 +0900 Subject: [PATCH] refactor --- README.md | 4 +- README_JA.md | 3 +- sandbox/ConsoleApp1/Program.cs | 153 ++-- src/AssetBundleMCP/Entity/Animation.cs | 2 +- src/AssetBundleMCP/Entity/Asset.cs | 2 +- .../Entity/AssetDependencies.cs | 2 +- src/AssetBundleMCP/Entity/AudioClip.cs | 2 +- src/AssetBundleMCP/Entity/BreakdownByType.cs | 2 +- src/AssetBundleMCP/Entity/BreakdownShaders.cs | 2 +- .../Entity/MaterialShaderRefs.cs | 2 +- .../Entity/MaterialTextureRefs.cs | 2 +- src/AssetBundleMCP/Entity/Mesh.cs | 2 +- src/AssetBundleMCP/Entity/Object.cs | 2 +- .../Entity/PotentialDuplicates.cs | 2 +- src/AssetBundleMCP/Entity/Shader.cs | 2 +- .../Entity/ShaderKeywordRatio.cs | 2 +- src/AssetBundleMCP/Entity/ShaderSubprogram.cs | 2 +- src/AssetBundleMCP/Entity/Texture.cs | 2 +- src/AssetBundleMCP/Internal/Paginate.cs | 2 +- src/AssetBundleMCP/Program.cs | 5 +- .../Repository/AssetRepository.cs | 686 ++++++------------ .../Repository/IAssetRepository.cs | 39 +- src/AssetBundleMCP/Service/AnalyzerService.cs | 61 ++ .../Service/AssetBundleService.cs | 128 ++++ .../Service/IAnalyzerService.cs | 8 + .../Service/IAssetBundleService.cs | 27 + src/AssetBundleMCP/Tool/AssetBundleTools.cs | 164 ++--- .../AssetBundleMCP.Tests.csproj | 7 + .../AssetBundleToolsTest.cs | 172 +++-- tests/AssetBundleMCP.Tests/PaginateTest.cs | 2 +- 30 files changed, 716 insertions(+), 775 deletions(-) create mode 100644 src/AssetBundleMCP/Service/AnalyzerService.cs create mode 100644 src/AssetBundleMCP/Service/AssetBundleService.cs create mode 100644 src/AssetBundleMCP/Service/IAnalyzerService.cs create mode 100644 src/AssetBundleMCP/Service/IAssetBundleService.cs diff --git a/README.md b/README.md index 6fb3c4a..69621e4 100644 --- a/README.md +++ b/README.md @@ -181,5 +181,5 @@ This project is licensed under the [MIT License](LICENSE). The core analysis functionality of this tool uses [UnityDataTools](https://github.com/Unity-Technologies/UnityDataTools). Many thanks to the developers of this excellent library. ## Notes -None of the repo, the tool, nor the repo owner is affiliated with, or sponsored or authorized by, Unity Technologies or its affiliates. -This is intended for use in developing your own products, and should not be used for reverse engineering other companies' products. +None of the repo, the tool, nor the repo owner is affiliated with, or sponsored or authorized by, Unity Technologies or its affiliates. +Use it responsibly and ensure compliance with applicable laws and regulations. diff --git a/README_JA.md b/README_JA.md index fdafccf..43a4cdc 100644 --- a/README_JA.md +++ b/README_JA.md @@ -173,5 +173,4 @@ dotnet build -c Release このツールのコアな分析機能は [UnityDataTools](https://github.com/Unity-Technologies/UnityDataTools) を利用しています。素晴らしいライブラリの開発者に感謝します。 ## 注釈 -レポジトリ、ツール、レポジトリの所有者は、Unity Technologiesとは関係ありません。 -自身のプロダクト開発への利用を想定しており、他社製品へのリバースエンジニアリングなどには用いないでください。 +レポジトリ、ツール、レポジトリの所有者は、Unity Technologiesとは関係ありません。責任を持って使用し、法律および規制等を遵守してください。 \ No newline at end of file diff --git a/sandbox/ConsoleApp1/Program.cs b/sandbox/ConsoleApp1/Program.cs index 467e2a6..0da6b50 100644 --- a/sandbox/ConsoleApp1/Program.cs +++ b/sandbox/ConsoleApp1/Program.cs @@ -1,6 +1,7 @@ using System.Text.Json; -using AssetBundleMcpServer.Repository; -using AssetBundleMcpServer.Tool; +using AssetBundleMcp.Repository; +using AssetBundleMcp.Service; +using AssetBundleMcp.Tool; using Cocona; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -12,308 +13,310 @@ logging.AddConsole(); logging.SetMinimumLevel(LogLevel.Information); }); -builder.Services.AddSingleton(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddSingleton(); var app = builder.Build(); app.AddCommand("list-animations", ( ILogger logger, - IAssetRepository repository, + IAssetBundleService service, [Argument]string assetBundleDir, [Option]string? databasePath = null, [Option]int offset = 0, [Option]int pageSize = 100 ) => { - AssetBundleTools.LoadAssetBundle(assetBundleDir, databasePath); + AssetBundleTools.LoadAssetBundle(service, assetBundleDir, databasePath); - var animations = AssetBundleTools.ListAnimations(repository, offset, pageSize); + var animations = AssetBundleTools.ListAnimations(service, offset, pageSize); foreach (var animation in animations) { logger.LogInformation(JsonSerializer.Serialize(animation)); } - AssetBundleTools.UnLoadAssetBundle(); + AssetBundleTools.UnLoadAssetBundle(service); }); app.AddCommand("list-asset-dependencies", ( ILogger logger, - IAssetRepository repository, + IAssetBundleService service, [Argument]string assetBundleDir, [Option]string? databasePath = null, [Option]int offset = 0, [Option]int pageSize = 100 ) => { - AssetBundleTools.LoadAssetBundle(assetBundleDir, databasePath); + AssetBundleTools.LoadAssetBundle(service, assetBundleDir, databasePath); - var dependencies = AssetBundleTools.ListAssetDependencies(repository, offset, pageSize); + var dependencies = AssetBundleTools.ListAssetDependencies(service, offset, pageSize); foreach (var dependency in dependencies) { logger.LogInformation(JsonSerializer.Serialize(dependency)); } - AssetBundleTools.UnLoadAssetBundle(); + AssetBundleTools.UnLoadAssetBundle(service); }); app.AddCommand("list-assets", ( ILogger logger, - IAssetRepository repository, + IAssetBundleService service, [Argument]string assetBundleDir, [Option]string? databasePath = null, [Option]int offset = 0, [Option]int pageSize = 100 ) => { - AssetBundleTools.LoadAssetBundle(assetBundleDir, databasePath); + AssetBundleTools.LoadAssetBundle(service, assetBundleDir, databasePath); - var assets = AssetBundleTools.ListAssets(repository, offset, pageSize); + var assets = AssetBundleTools.ListAssets(service, offset, pageSize); foreach (var asset in assets) { logger.LogInformation(JsonSerializer.Serialize(asset)); } - AssetBundleTools.UnLoadAssetBundle(); + AssetBundleTools.UnLoadAssetBundle(service); }); app.AddCommand("list-audio-clips", ( ILogger logger, - IAssetRepository repository, + IAssetBundleService service, [Argument]string assetBundleDir, [Option]string? databasePath = null, [Option]int offset = 0, [Option]int pageSize = 100 ) => { - AssetBundleTools.LoadAssetBundle(assetBundleDir, databasePath); - - var audioClips = AssetBundleTools.ListAudioClips(repository, offset, pageSize); + AssetBundleTools.LoadAssetBundle(service, assetBundleDir, databasePath); + + var audioClips = AssetBundleTools.ListAudioClips(service, offset, pageSize); foreach (var audioClip in audioClips) { logger.LogInformation(JsonSerializer.Serialize(audioClip)); } - AssetBundleTools.UnLoadAssetBundle(); + AssetBundleTools.UnLoadAssetBundle(service); }); app.AddCommand("list-meshes", ( ILogger logger, - IAssetRepository repository, + IAssetBundleService service, [Argument]string assetBundleDir, [Option]string? databasePath = null, [Option]int offset = 0, [Option]int pageSize = 100 ) => { - AssetBundleTools.LoadAssetBundle(assetBundleDir, databasePath); - - var meshes = AssetBundleTools.ListMeshes(repository, offset, pageSize); + AssetBundleTools.LoadAssetBundle(service, assetBundleDir, databasePath); + + var meshes = AssetBundleTools.ListMeshes(service, offset, pageSize); foreach (var mesh in meshes) { logger.LogInformation(JsonSerializer.Serialize(mesh)); } - AssetBundleTools.UnLoadAssetBundle(); + AssetBundleTools.UnLoadAssetBundle(service); }); app.AddCommand("list-objects", ( ILogger logger, - IAssetRepository repository, + IAssetBundleService service, [Argument]string assetBundleDir, [Option]string? databasePath = null, [Option]int offset = 0, [Option]int pageSize = 100 ) => { - AssetBundleTools.LoadAssetBundle(assetBundleDir, databasePath); - - var objects = AssetBundleTools.ListObjects(repository, offset, pageSize); + AssetBundleTools.LoadAssetBundle(service, assetBundleDir, databasePath); + + var objects = AssetBundleTools.ListObjects(service, offset, pageSize); foreach (var obj in objects) { logger.LogInformation(JsonSerializer.Serialize(obj)); } - AssetBundleTools.UnLoadAssetBundle(); + AssetBundleTools.UnLoadAssetBundle(service); }); app.AddCommand("list-shader-keyword-ratios", ( ILogger logger, - IAssetRepository repository, + IAssetBundleService service, [Argument]string assetBundleDir, [Option]string? databasePath = null, [Option]int offset = 0, [Option]int pageSize = 100 ) => { - AssetBundleTools.LoadAssetBundle(assetBundleDir, databasePath); - - var shaderKeywordRatios = AssetBundleTools.ListShaderKeywordRatios(repository, offset, pageSize); + AssetBundleTools.LoadAssetBundle(service, assetBundleDir, databasePath); + + var shaderKeywordRatios = AssetBundleTools.ListShaderKeywordRatios(service, offset, pageSize); foreach (var ratio in shaderKeywordRatios) { logger.LogInformation(JsonSerializer.Serialize(ratio)); } - AssetBundleTools.UnLoadAssetBundle(); + AssetBundleTools.UnLoadAssetBundle(service); }); app.AddCommand("list-shader-subprograms", ( ILogger logger, - IAssetRepository repository, + IAssetBundleService service, [Argument]string assetBundleDir, [Option]string? databasePath = null, [Option]int offset = 0, [Option]int pageSize = 100 ) => { - AssetBundleTools.LoadAssetBundle(assetBundleDir, databasePath); - - var shaderSubprograms = AssetBundleTools.ListShaderSubprograms(repository, offset, pageSize); + AssetBundleTools.LoadAssetBundle(service, assetBundleDir, databasePath); + + var shaderSubprograms = AssetBundleTools.ListShaderSubprograms(service, offset, pageSize); foreach (var subprogram in shaderSubprograms) { logger.LogInformation(JsonSerializer.Serialize(subprogram)); } - AssetBundleTools.UnLoadAssetBundle(); + AssetBundleTools.UnLoadAssetBundle(service); }); app.AddCommand("list-shaders", ( ILogger logger, - IAssetRepository repository, + IAssetBundleService service, [Argument]string assetBundleDir, [Option]string? databasePath = null, [Option]int offset = 0, [Option]int pageSize = 100 ) => { - AssetBundleTools.LoadAssetBundle(assetBundleDir, databasePath); - - var shaders = AssetBundleTools.ListShaders(repository, offset, pageSize); + AssetBundleTools.LoadAssetBundle(service, assetBundleDir, databasePath); + + var shaders = AssetBundleTools.ListShaders(service, offset, pageSize); foreach (var shader in shaders) { logger.LogInformation(JsonSerializer.Serialize(shader)); } - AssetBundleTools.UnLoadAssetBundle(); + AssetBundleTools.UnLoadAssetBundle(service); }); app.AddCommand("list-textures", ( ILogger logger, - IAssetRepository repository, + IAssetBundleService service, [Argument]string assetBundleDir, [Option]string? databasePath = null, [Option]int offset = 0, [Option]int pageSize = 100 ) => { - AssetBundleTools.LoadAssetBundle(assetBundleDir, databasePath); - - var textures = AssetBundleTools.ListTextures(repository, offset, pageSize); + AssetBundleTools.LoadAssetBundle(service, assetBundleDir, databasePath); + + var textures = AssetBundleTools.ListTextures(service, offset, pageSize); foreach (var texture in textures) { logger.LogInformation(JsonSerializer.Serialize(texture)); } - AssetBundleTools.UnLoadAssetBundle(); + AssetBundleTools.UnLoadAssetBundle(service); }); app.AddCommand("list-breakdown-by-type", ( ILogger logger, - IAssetRepository repository, + IAssetBundleService service, [Argument]string assetBundleDir, [Option]string? databasePath = null, [Option]int offset = 0, [Option]int pageSize = 100 ) => { - AssetBundleTools.LoadAssetBundle(assetBundleDir, databasePath); - - var breakdown = AssetBundleTools.ListBreakdownByType(repository, offset, pageSize); + AssetBundleTools.LoadAssetBundle(service, assetBundleDir, databasePath); + + var breakdown = AssetBundleTools.ListBreakdownByType(service, offset, pageSize); foreach (var item in breakdown) { logger.LogInformation(JsonSerializer.Serialize(item)); } - AssetBundleTools.UnLoadAssetBundle(); + AssetBundleTools.UnLoadAssetBundle(service); }); app.AddCommand("list-breakdown-shaders", ( ILogger logger, - IAssetRepository repository, + IAssetBundleService service, [Argument]string assetBundleDir, [Option]string? databasePath = null, [Option]int offset = 0, [Option]int pageSize = 100 ) => { - AssetBundleTools.LoadAssetBundle(assetBundleDir, databasePath); - - var breakdownShaders = AssetBundleTools.ListBreakdownShaders(repository, offset, pageSize); + AssetBundleTools.LoadAssetBundle(service, assetBundleDir, databasePath); + + var breakdownShaders = AssetBundleTools.ListBreakdownShaders(service, offset, pageSize); foreach (var item in breakdownShaders) { logger.LogInformation(JsonSerializer.Serialize(item)); } - AssetBundleTools.UnLoadAssetBundle(); + AssetBundleTools.UnLoadAssetBundle(service); }); app.AddCommand("list-material-shader-refs", ( ILogger logger, - IAssetRepository repository, + IAssetBundleService service, [Argument]string assetBundleDir, [Option]string? databasePath = null, [Option]int offset = 0, [Option]int pageSize = 100 ) => { - AssetBundleTools.LoadAssetBundle(assetBundleDir, databasePath); - - var materialShaderRefs = AssetBundleTools.ListMaterialShaderRefs(repository, offset, pageSize); + AssetBundleTools.LoadAssetBundle(service, assetBundleDir, databasePath); + + var materialShaderRefs = AssetBundleTools.ListMaterialShaderRefs(service, offset, pageSize); foreach (var refItem in materialShaderRefs) { logger.LogInformation(JsonSerializer.Serialize(refItem)); } - AssetBundleTools.UnLoadAssetBundle(); + AssetBundleTools.UnLoadAssetBundle(service); }); app.AddCommand("list-material-texture-refs", ( ILogger logger, - IAssetRepository repository, + IAssetBundleService service, [Argument]string assetBundleDir, [Option]string? databasePath = null, [Option]int offset = 0, [Option]int pageSize = 100 ) => { - AssetBundleTools.LoadAssetBundle(assetBundleDir, databasePath); - - var materialTextureRefs = AssetBundleTools.ListMaterialTextureRefs(repository, offset, pageSize); + AssetBundleTools.LoadAssetBundle(service, assetBundleDir, databasePath); + + var materialTextureRefs = AssetBundleTools.ListMaterialTextureRefs(service, offset, pageSize); foreach (var refItem in materialTextureRefs) { logger.LogInformation(JsonSerializer.Serialize(refItem)); } - AssetBundleTools.UnLoadAssetBundle(); + AssetBundleTools.UnLoadAssetBundle(service); }); app.AddCommand("list-potential-duplicates", ( ILogger logger, - IAssetRepository repository, + IAssetBundleService service, [Argument]string assetBundleDir, [Option]string? databasePath = null, [Option]int offset = 0, [Option]int pageSize = 100 ) => { - AssetBundleTools.LoadAssetBundle(assetBundleDir, databasePath); - - var potentialDuplicates = AssetBundleTools.ListPotentialDuplicates(repository, offset, pageSize); + AssetBundleTools.LoadAssetBundle(service, assetBundleDir, databasePath); + + var potentialDuplicates = AssetBundleTools.ListPotentialDuplicates(service, offset, pageSize); foreach (var duplicate in potentialDuplicates) { logger.LogInformation(JsonSerializer.Serialize(duplicate)); } - AssetBundleTools.UnLoadAssetBundle(); + AssetBundleTools.UnLoadAssetBundle(service); }); app.Run(); \ No newline at end of file diff --git a/src/AssetBundleMCP/Entity/Animation.cs b/src/AssetBundleMCP/Entity/Animation.cs index 0d79b99..ae2ec87 100644 --- a/src/AssetBundleMCP/Entity/Animation.cs +++ b/src/AssetBundleMCP/Entity/Animation.cs @@ -1,7 +1,7 @@ using System.ComponentModel; using System.Text.Json.Serialization; -namespace AssetBundleMcpServer.Entity; +namespace AssetBundleMcp.Entity; public record Animation { diff --git a/src/AssetBundleMCP/Entity/Asset.cs b/src/AssetBundleMCP/Entity/Asset.cs index a117d39..7066242 100644 --- a/src/AssetBundleMCP/Entity/Asset.cs +++ b/src/AssetBundleMCP/Entity/Asset.cs @@ -1,7 +1,7 @@ using System.ComponentModel; using System.Text.Json.Serialization; -namespace AssetBundleMcpServer.Entity; +namespace AssetBundleMcp.Entity; public record Asset { diff --git a/src/AssetBundleMCP/Entity/AssetDependencies.cs b/src/AssetBundleMCP/Entity/AssetDependencies.cs index ca8a724..9fbc7f3 100644 --- a/src/AssetBundleMCP/Entity/AssetDependencies.cs +++ b/src/AssetBundleMCP/Entity/AssetDependencies.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace AssetBundleMcpServer.Entity; +namespace AssetBundleMcp.Entity; public record AssetDependencies { diff --git a/src/AssetBundleMCP/Entity/AudioClip.cs b/src/AssetBundleMCP/Entity/AudioClip.cs index 08db8a6..4d686b3 100644 --- a/src/AssetBundleMCP/Entity/AudioClip.cs +++ b/src/AssetBundleMCP/Entity/AudioClip.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace AssetBundleMcpServer.Entity; +namespace AssetBundleMcp.Entity; public record AudioClip { diff --git a/src/AssetBundleMCP/Entity/BreakdownByType.cs b/src/AssetBundleMCP/Entity/BreakdownByType.cs index 4f76b0d..2f9d663 100644 --- a/src/AssetBundleMCP/Entity/BreakdownByType.cs +++ b/src/AssetBundleMCP/Entity/BreakdownByType.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace AssetBundleMcpServer.Entity; +namespace AssetBundleMcp.Entity; public record BreakdownByType { diff --git a/src/AssetBundleMCP/Entity/BreakdownShaders.cs b/src/AssetBundleMCP/Entity/BreakdownShaders.cs index dba5e30..3d45dd2 100644 --- a/src/AssetBundleMCP/Entity/BreakdownShaders.cs +++ b/src/AssetBundleMCP/Entity/BreakdownShaders.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace AssetBundleMcpServer.Entity; +namespace AssetBundleMcp.Entity; public record BreakdownShaders { diff --git a/src/AssetBundleMCP/Entity/MaterialShaderRefs.cs b/src/AssetBundleMCP/Entity/MaterialShaderRefs.cs index bee07fd..f971165 100644 --- a/src/AssetBundleMCP/Entity/MaterialShaderRefs.cs +++ b/src/AssetBundleMCP/Entity/MaterialShaderRefs.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace AssetBundleMcpServer.Entity; +namespace AssetBundleMcp.Entity; public record MaterialShaderRefs { diff --git a/src/AssetBundleMCP/Entity/MaterialTextureRefs.cs b/src/AssetBundleMCP/Entity/MaterialTextureRefs.cs index 3ba3633..8ecd88b 100644 --- a/src/AssetBundleMCP/Entity/MaterialTextureRefs.cs +++ b/src/AssetBundleMCP/Entity/MaterialTextureRefs.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace AssetBundleMcpServer.Entity; +namespace AssetBundleMcp.Entity; public record MaterialTextureRefs { diff --git a/src/AssetBundleMCP/Entity/Mesh.cs b/src/AssetBundleMCP/Entity/Mesh.cs index a6865a6..7d98f40 100644 --- a/src/AssetBundleMCP/Entity/Mesh.cs +++ b/src/AssetBundleMCP/Entity/Mesh.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace AssetBundleMcpServer.Entity; +namespace AssetBundleMcp.Entity; public record Mesh { diff --git a/src/AssetBundleMCP/Entity/Object.cs b/src/AssetBundleMCP/Entity/Object.cs index 5dbc551..03bd11e 100644 --- a/src/AssetBundleMCP/Entity/Object.cs +++ b/src/AssetBundleMCP/Entity/Object.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace AssetBundleMcpServer.Entity; +namespace AssetBundleMcp.Entity; public record Object { diff --git a/src/AssetBundleMCP/Entity/PotentialDuplicates.cs b/src/AssetBundleMCP/Entity/PotentialDuplicates.cs index ff04111..c6b30b2 100644 --- a/src/AssetBundleMCP/Entity/PotentialDuplicates.cs +++ b/src/AssetBundleMCP/Entity/PotentialDuplicates.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace AssetBundleMcpServer.Entity; +namespace AssetBundleMcp.Entity; public record PotentialDuplicates { diff --git a/src/AssetBundleMCP/Entity/Shader.cs b/src/AssetBundleMCP/Entity/Shader.cs index 9272dc4..22928bc 100644 --- a/src/AssetBundleMCP/Entity/Shader.cs +++ b/src/AssetBundleMCP/Entity/Shader.cs @@ -1,7 +1,7 @@ using System.ComponentModel; using System.Text.Json.Serialization; -namespace AssetBundleMcpServer.Entity; +namespace AssetBundleMcp.Entity; public record Shader { diff --git a/src/AssetBundleMCP/Entity/ShaderKeywordRatio.cs b/src/AssetBundleMCP/Entity/ShaderKeywordRatio.cs index 4043414..6ccfc46 100644 --- a/src/AssetBundleMCP/Entity/ShaderKeywordRatio.cs +++ b/src/AssetBundleMCP/Entity/ShaderKeywordRatio.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace AssetBundleMcpServer.Entity; +namespace AssetBundleMcp.Entity; public record ShaderKeywordRatio { diff --git a/src/AssetBundleMCP/Entity/ShaderSubprogram.cs b/src/AssetBundleMCP/Entity/ShaderSubprogram.cs index 1087891..0fdfc2c 100644 --- a/src/AssetBundleMCP/Entity/ShaderSubprogram.cs +++ b/src/AssetBundleMCP/Entity/ShaderSubprogram.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace AssetBundleMcpServer.Entity; +namespace AssetBundleMcp.Entity; public record ShaderSubprogram { diff --git a/src/AssetBundleMCP/Entity/Texture.cs b/src/AssetBundleMCP/Entity/Texture.cs index 995e91d..00fb884 100644 --- a/src/AssetBundleMCP/Entity/Texture.cs +++ b/src/AssetBundleMCP/Entity/Texture.cs @@ -1,7 +1,7 @@ using System.ComponentModel; using System.Text.Json.Serialization; -namespace AssetBundleMcpServer.Entity; +namespace AssetBundleMcp.Entity; public record Texture { diff --git a/src/AssetBundleMCP/Internal/Paginate.cs b/src/AssetBundleMCP/Internal/Paginate.cs index cb1f0fa..9429875 100644 --- a/src/AssetBundleMCP/Internal/Paginate.cs +++ b/src/AssetBundleMCP/Internal/Paginate.cs @@ -1,4 +1,4 @@ -namespace AssetBundleMcpServer.Internal; +namespace AssetBundleMcp.Internal; internal static class Paginate { diff --git a/src/AssetBundleMCP/Program.cs b/src/AssetBundleMCP/Program.cs index 5825f65..a7b2d44 100644 --- a/src/AssetBundleMCP/Program.cs +++ b/src/AssetBundleMCP/Program.cs @@ -1,4 +1,5 @@ -using AssetBundleMcpServer.Repository; +using AssetBundleMcp.Repository; +using AssetBundleMcp.Service; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; @@ -13,6 +14,8 @@ .WithToolsFromAssembly() .WithResourcesFromAssembly(); +builder.Services.AddSingleton(); builder.Services.AddSingleton(); +builder.Services.AddSingleton(); await builder.Build().RunAsync(); \ No newline at end of file diff --git a/src/AssetBundleMCP/Repository/AssetRepository.cs b/src/AssetBundleMCP/Repository/AssetRepository.cs index 7f3bcfc..ae4fec1 100644 --- a/src/AssetBundleMCP/Repository/AssetRepository.cs +++ b/src/AssetBundleMCP/Repository/AssetRepository.cs @@ -1,552 +1,319 @@ - +using System.Data.Common; using System.Text; -using AssetBundleMcpServer.Entity; +using AssetBundleMcp.Entity; using Microsoft.Data.Sqlite; -using Object = AssetBundleMcpServer.Entity.Object; +using Object = AssetBundleMcp.Entity.Object; -namespace AssetBundleMcpServer.Repository; +namespace AssetBundleMcp.Repository; -public class AssetRepository : IAssetRepository, IDisposable +public class AssetRepository : IAssetRepository { private static string CreateConnectionString(string dbPath) { return $"Data Source={dbPath}"; } - public Animation[] GetAnimations(string dbPath) + private static T[] Query(string dbPath, string sql, Func map) { - var animations = new List(); - + var results = new List(); var connectionString = CreateConnectionString(dbPath); using var connection = new SqliteConnection(connectionString); connection.Open(); - var command = connection.CreateCommand(); - command.CommandText = - "SELECT id, object_id, asset_bundle, serialized_file, type, name, game_object, size, pretty_size, crc32, legacy, events FROM animation_view"; + using var command = connection.CreateCommand(); + command.CommandText = sql; using var reader = command.ExecuteReader(); while (reader.Read()) { - var animation = new Animation - { - Id = reader.GetInt64(reader.GetOrdinal("id")), - ObjectId = reader.GetInt64(reader.GetOrdinal("object_id")), - AssetBundle = reader.GetString(reader.GetOrdinal("asset_bundle")), - SerializedFile = reader.GetString(reader.GetOrdinal("serialized_file")), - Type = reader.GetString(reader.GetOrdinal("type")), - Name = reader.GetString(reader.GetOrdinal("name")), - GameObject = reader.GetInt64(reader.GetOrdinal("game_object")), - Size = reader.GetInt64(reader.GetOrdinal("size")), - PrettySize = reader.GetValue(reader.GetOrdinal("pretty_size")).ToString() ?? "0B", - Crc32 = reader.GetInt64(reader.GetOrdinal("crc32")), - Legacy = reader.GetInt64(reader.GetOrdinal("legacy")), - Events = reader.GetInt64(reader.GetOrdinal("events")) - }; - animations.Add(animation); + results.Add(map(reader)); } + return results.ToArray(); + } - return animations.OrderBy(animation => animation.Id).ToArray(); + public Animation[] GetAnimations(string dbPath) + { + const string sql = "SELECT id, object_id, asset_bundle, serialized_file, type, name, game_object, size, pretty_size, crc32, legacy, events FROM animation_view"; + return Query(dbPath, sql, static reader => new Animation + { + Id = reader.GetInt64(reader.GetOrdinal("id")), + ObjectId = reader.GetInt64(reader.GetOrdinal("object_id")), + AssetBundle = reader.GetString(reader.GetOrdinal("asset_bundle")), + SerializedFile = reader.GetString(reader.GetOrdinal("serialized_file")), + Type = reader.GetString(reader.GetOrdinal("type")), + Name = reader.GetString(reader.GetOrdinal("name")), + GameObject = reader.GetInt64(reader.GetOrdinal("game_object")), + Size = reader.GetInt64(reader.GetOrdinal("size")), + PrettySize = reader.GetValue(reader.GetOrdinal("pretty_size")).ToString() ?? "0B", + Crc32 = reader.GetInt64(reader.GetOrdinal("crc32")), + Legacy = reader.GetInt64(reader.GetOrdinal("legacy")), + Events = reader.GetInt64(reader.GetOrdinal("events")) + }).OrderBy(a => a.Id).ToArray(); } public AssetDependencies[] GetAssetDependencies(string dbPath) { - var dependencies = new List(); - - var connectionString = CreateConnectionString(dbPath); - using var connection = new SqliteConnection(connectionString); - connection.Open(); - - var command = connection.CreateCommand(); - command.CommandText = - "SELECT id, asset_name, asset_bundle, type, dep_id, dep_asset_bundle, dep_name, dep_type FROM asset_dependencies_view"; - - using var reader = command.ExecuteReader(); - while (reader.Read()) + const string sql = "SELECT id, asset_name, asset_bundle, type, dep_id, dep_asset_bundle, dep_name, dep_type FROM asset_dependencies_view"; + return Query(dbPath, sql, static reader => new AssetDependencies { - var dependency = new AssetDependencies - { - Id = reader.GetInt64(reader.GetOrdinal("id")), - AssetName = reader.GetString(reader.GetOrdinal("asset_name")), - AssetBundle = reader.GetString(reader.GetOrdinal("asset_bundle")), - Type = reader.GetString(reader.GetOrdinal("type")), - DepId = reader.GetInt64(reader.GetOrdinal("dep_id")), - DepAssetBundle = reader.GetString(reader.GetOrdinal("dep_asset_bundle")), - DepName = reader.GetString(reader.GetOrdinal("dep_name")), - DepType = reader.GetString(reader.GetOrdinal("dep_type")) - }; - dependencies.Add(dependency); - } - - return dependencies.OrderBy(dep => dep.Id).ToArray(); + Id = reader.GetInt64(reader.GetOrdinal("id")), + AssetName = reader.GetString(reader.GetOrdinal("asset_name")), + AssetBundle = reader.GetString(reader.GetOrdinal("asset_bundle")), + Type = reader.GetString(reader.GetOrdinal("type")), + DepId = reader.GetInt64(reader.GetOrdinal("dep_id")), + DepAssetBundle = reader.GetString(reader.GetOrdinal("dep_asset_bundle")), + DepName = reader.GetString(reader.GetOrdinal("dep_name")), + DepType = reader.GetString(reader.GetOrdinal("dep_type")) + }).OrderBy(dep => dep.Id).ToArray(); } public Asset[] GetAssets(string dbPath) { - var assets = new List(); - - var connectionString = CreateConnectionString(dbPath); - using var connection = new SqliteConnection(connectionString); - connection.Open(); - - var command = connection.CreateCommand(); - command.CommandText = - "SELECT asset_name, id, object_id, asset_bundle, serialized_file, type, name, game_object, size, pretty_size, crc32 FROM asset_view"; - - using var reader = command.ExecuteReader(); - while (reader.Read()) + const string sql = "SELECT asset_name, id, object_id, asset_bundle, serialized_file, type, name, game_object, size, pretty_size, crc32 FROM asset_view"; + return Query(dbPath, sql, static reader => new Asset { - var asset = new Asset - { - AssetName = reader.GetString(reader.GetOrdinal("asset_name")), - Id = reader.GetInt64(reader.GetOrdinal("id")), - ObjectId = reader.GetInt64(reader.GetOrdinal("object_id")), - AssetBundle = reader.GetString(reader.GetOrdinal("asset_bundle")), - SerializedFile = reader.GetString(reader.GetOrdinal("serialized_file")), - Type = reader.GetString(reader.GetOrdinal("type")), - Name = reader.GetString(reader.GetOrdinal("name")), - GameObject = reader.GetInt64(reader.GetOrdinal("game_object")), - Size = reader.GetInt64(reader.GetOrdinal("size")), - PrettySize = reader.GetValue(reader.GetOrdinal("pretty_size")).ToString() ?? "0B", - Crc32 = reader.GetInt64(reader.GetOrdinal("crc32")) - }; - assets.Add(asset); - } - - return assets.OrderBy(asset => asset.Id).ToArray(); + AssetName = reader.GetString(reader.GetOrdinal("asset_name")), + Id = reader.GetInt64(reader.GetOrdinal("id")), + ObjectId = reader.GetInt64(reader.GetOrdinal("object_id")), + AssetBundle = reader.GetString(reader.GetOrdinal("asset_bundle")), + SerializedFile = reader.GetString(reader.GetOrdinal("serialized_file")), + Type = reader.GetString(reader.GetOrdinal("type")), + Name = reader.GetString(reader.GetOrdinal("name")), + GameObject = reader.GetInt64(reader.GetOrdinal("game_object")), + Size = reader.GetInt64(reader.GetOrdinal("size")), + PrettySize = reader.GetValue(reader.GetOrdinal("pretty_size")).ToString() ?? "0B", + Crc32 = reader.GetInt64(reader.GetOrdinal("crc32")) + }).OrderBy(asset => asset.Id).ToArray(); } public AudioClip[] GetAudioClips(string dbPath) { - var audioClips = new List(); - - var connectionString = CreateConnectionString(dbPath); - using var connection = new SqliteConnection(connectionString); - connection.Open(); - - var command = connection.CreateCommand(); - command.CommandText = - "SELECT id, object_id, asset_bundle, serialized_file, type, name, game_object, size, pretty_size, crc32, bits_per_sample, frequency, channels, load_type, format FROM audio_clip_view"; - - using var reader = command.ExecuteReader(); - while (reader.Read()) + const string sql = "SELECT id, object_id, asset_bundle, serialized_file, type, name, game_object, size, pretty_size, crc32, bits_per_sample, frequency, channels, load_type, format FROM audio_clip_view"; + return Query(dbPath, sql, static reader => new AudioClip { - var audioClip = new AudioClip - { - Id = reader.GetInt64(reader.GetOrdinal("id")), - ObjectId = reader.GetInt64(reader.GetOrdinal("object_id")), - AssetBundle = reader.GetString(reader.GetOrdinal("asset_bundle")), - SerializedFile = reader.GetString(reader.GetOrdinal("serialized_file")), - Type = reader.GetString(reader.GetOrdinal("type")), - Name = reader.GetString(reader.GetOrdinal("name")), - GameObject = reader.GetInt64(reader.GetOrdinal("game_object")), - Size = reader.GetInt64(reader.GetOrdinal("size")), - PrettySize = reader.GetValue(reader.GetOrdinal("pretty_size")).ToString() ?? "0B", - Crc32 = reader.GetInt64(reader.GetOrdinal("crc32")), - BitsPerSample = reader.GetInt64(reader.GetOrdinal("bits_per_sample")), - Frequency = reader.GetInt64(reader.GetOrdinal("frequency")), - Channels = reader.GetInt64(reader.GetOrdinal("channels")), - LoadType = reader.GetString(reader.GetOrdinal("load_type")), - Format = reader.GetString(reader.GetOrdinal("format")) - }; - audioClips.Add(audioClip); - } - - return audioClips.OrderBy(clip => clip.Id).ToArray(); + Id = reader.GetInt64(reader.GetOrdinal("id")), + ObjectId = reader.GetInt64(reader.GetOrdinal("object_id")), + AssetBundle = reader.GetString(reader.GetOrdinal("asset_bundle")), + SerializedFile = reader.GetString(reader.GetOrdinal("serialized_file")), + Type = reader.GetString(reader.GetOrdinal("type")), + Name = reader.GetString(reader.GetOrdinal("name")), + GameObject = reader.GetInt64(reader.GetOrdinal("game_object")), + Size = reader.GetInt64(reader.GetOrdinal("size")), + PrettySize = reader.GetValue(reader.GetOrdinal("pretty_size")).ToString() ?? "0B", + Crc32 = reader.GetInt64(reader.GetOrdinal("crc32")), + BitsPerSample = reader.GetInt64(reader.GetOrdinal("bits_per_sample")), + Frequency = reader.GetInt64(reader.GetOrdinal("frequency")), + Channels = reader.GetInt64(reader.GetOrdinal("channels")), + LoadType = reader.GetString(reader.GetOrdinal("load_type")), + Format = reader.GetString(reader.GetOrdinal("format")) + }).OrderBy(clip => clip.Id).ToArray(); } public Mesh[] GetMeshes(string dbPath) { - var meshes = new List(); - - var connectionString = CreateConnectionString(dbPath); - using var connection = new SqliteConnection(connectionString); - connection.Open(); - - var command = connection.CreateCommand(); - command.CommandText = - "SELECT id, object_id, asset_bundle, serialized_file, type, name, game_object, size, pretty_size, crc32, sub_meshes, blend_shapes, bones, indices, vertices, compression, rw_enabled, vertex_size, channels FROM mesh_view"; - - using var reader = command.ExecuteReader(); - while (reader.Read()) + const string sql = "SELECT id, object_id, asset_bundle, serialized_file, type, name, game_object, size, pretty_size, crc32, sub_meshes, blend_shapes, bones, indices, vertices, compression, rw_enabled, vertex_size, channels FROM mesh_view"; + return Query(dbPath, sql, static reader => new Mesh { - var mesh = new Mesh - { - Id = reader.GetInt64(reader.GetOrdinal("id")), - ObjectId = reader.GetInt64(reader.GetOrdinal("object_id")), - AssetBundle = reader.GetString(reader.GetOrdinal("asset_bundle")), - SerializedFile = reader.GetString(reader.GetOrdinal("serialized_file")), - Type = reader.GetString(reader.GetOrdinal("type")), - Name = reader.GetString(reader.GetOrdinal("name")), - GameObject = reader.GetInt64(reader.GetOrdinal("game_object")), - Size = reader.GetInt64(reader.GetOrdinal("size")), - PrettySize = reader.GetValue(reader.GetOrdinal("pretty_size")).ToString() ?? "0B", - Crc32 = reader.GetInt64(reader.GetOrdinal("crc32")), - SubMeshes = reader.GetInt64(reader.GetOrdinal("sub_meshes")), - BlendShapes = reader.GetInt64(reader.GetOrdinal("blend_shapes")), - Bones = reader.GetInt64(reader.GetOrdinal("bones")), - Indices = reader.GetInt64(reader.GetOrdinal("indices")), - Vertices = reader.GetInt64(reader.GetOrdinal("vertices")), - Compression = reader.GetInt64(reader.GetOrdinal("compression")), - RwEnabled = reader.GetInt64(reader.GetOrdinal("rw_enabled")), - VertexSize = reader.GetInt64(reader.GetOrdinal("vertex_size")), - Channels = reader.IsDBNull(reader.GetOrdinal("channels")) - ? string.Empty - : reader.GetString(reader.GetOrdinal("channels")) - }; - meshes.Add(mesh); - } - - return meshes.OrderBy(mesh => mesh.Id).ToArray(); + Id = reader.GetInt64(reader.GetOrdinal("id")), + ObjectId = reader.GetInt64(reader.GetOrdinal("object_id")), + AssetBundle = reader.GetString(reader.GetOrdinal("asset_bundle")), + SerializedFile = reader.GetString(reader.GetOrdinal("serialized_file")), + Type = reader.GetString(reader.GetOrdinal("type")), + Name = reader.GetString(reader.GetOrdinal("name")), + GameObject = reader.GetInt64(reader.GetOrdinal("game_object")), + Size = reader.GetInt64(reader.GetOrdinal("size")), + PrettySize = reader.GetValue(reader.GetOrdinal("pretty_size")).ToString() ?? "0B", + Crc32 = reader.GetInt64(reader.GetOrdinal("crc32")), + SubMeshes = reader.GetInt64(reader.GetOrdinal("sub_meshes")), + BlendShapes = reader.GetInt64(reader.GetOrdinal("blend_shapes")), + Bones = reader.GetInt64(reader.GetOrdinal("bones")), + Indices = reader.GetInt64(reader.GetOrdinal("indices")), + Vertices = reader.GetInt64(reader.GetOrdinal("vertices")), + Compression = reader.GetInt64(reader.GetOrdinal("compression")), + RwEnabled = reader.GetInt64(reader.GetOrdinal("rw_enabled")), + VertexSize = reader.GetInt64(reader.GetOrdinal("vertex_size")), + Channels = reader.GetValue(reader.GetOrdinal("channels")).ToString() ?? string.Empty, + }).OrderBy(mesh => mesh.Id).ToArray(); } public Object[] GetObjects(string dbPath) { - var objects = new List(); - - var connectionString = CreateConnectionString(dbPath); - using var connection = new SqliteConnection(connectionString); - connection.Open(); - - var command = connection.CreateCommand(); - command.CommandText = - "SELECT id, object_id, asset_bundle, serialized_file, type, name, game_object, size, pretty_size, crc32 FROM object_view"; - - using var reader = command.ExecuteReader(); - while (reader.Read()) + const string sql = "SELECT id, object_id, asset_bundle, serialized_file, type, name, game_object, size, pretty_size, crc32 FROM object_view"; + return Query(dbPath, sql, static reader => new Object { - var obj = new Object - { - Id = reader.GetInt64(reader.GetOrdinal("id")), - ObjectId = reader.GetInt64(reader.GetOrdinal("object_id")), - AssetBundle = reader.GetString(reader.GetOrdinal("asset_bundle")), - SerializedFile = reader.GetString(reader.GetOrdinal("serialized_file")), - Type = reader.GetString(reader.GetOrdinal("type")), - Name = reader.GetString(reader.GetOrdinal("name")), - GameObject = reader.GetInt64(reader.GetOrdinal("game_object")), - Size = reader.GetInt64(reader.GetOrdinal("size")), - PrettySize = reader.GetValue(reader.GetOrdinal("pretty_size")).ToString() ?? "0B", - Crc32 = reader.GetInt64(reader.GetOrdinal("crc32")) - }; - objects.Add(obj); - } - - return objects.OrderBy(obj => obj.Id).ToArray(); + Id = reader.GetInt64(reader.GetOrdinal("id")), + ObjectId = reader.GetInt64(reader.GetOrdinal("object_id")), + AssetBundle = reader.GetString(reader.GetOrdinal("asset_bundle")), + SerializedFile = reader.GetString(reader.GetOrdinal("serialized_file")), + Type = reader.GetString(reader.GetOrdinal("type")), + Name = reader.GetString(reader.GetOrdinal("name")), + GameObject = reader.GetInt64(reader.GetOrdinal("game_object")), + Size = reader.GetInt64(reader.GetOrdinal("size")), + PrettySize = reader.GetValue(reader.GetOrdinal("pretty_size")).ToString() ?? "0B", + Crc32 = reader.GetInt64(reader.GetOrdinal("crc32")) + }).OrderBy(obj => obj.Id).ToArray(); } public ShaderKeywordRatio[] GetShaderKeywordRatios(string dbPath) { - var shaderKeywordRatios = new List(); - - var connectionString = CreateConnectionString(dbPath); - using var connection = new SqliteConnection(connectionString); - connection.Open(); - - var command = connection.CreateCommand(); - command.CommandText = - "SELECT shader_id, name, sub_shader, hw_tier, pass, api, pass_name, shader_type, total_variants, keyword, variants, ratio FROM shader_keyword_ratios"; - - using var reader = command.ExecuteReader(); - while (reader.Read()) + const string sql = "SELECT shader_id, name, sub_shader, hw_tier, pass, api, pass_name, shader_type, total_variants, keyword, variants, ratio FROM shader_keyword_ratios"; + return Query(dbPath, sql, static reader => new ShaderKeywordRatio { - var ratio = new ShaderKeywordRatio - { - ShaderId = reader.GetInt64(reader.GetOrdinal("shader_id")), - Name = reader.GetString(reader.GetOrdinal("name")), - SubShader = reader.GetInt64(reader.GetOrdinal("sub_shader")), - HwTier = reader.GetInt64(reader.GetOrdinal("hw_tier")), - Pass = reader.GetInt64(reader.GetOrdinal("pass")), - Api = reader.GetString(reader.GetOrdinal("api")), - PassName = reader.GetString(reader.GetOrdinal("pass_name")), - ShaderType = reader.GetString(reader.GetOrdinal("shader_type")), - TotalVariants = reader.GetValue(reader.GetOrdinal("total_variants")).ToString() ?? "", - Keyword = reader.GetString(reader.GetOrdinal("keyword")), - Variants = reader.GetValue(reader.GetOrdinal("variants")).ToString() ?? "", - Ratio = reader.GetValue(reader.GetOrdinal("ratio")).ToString() ?? "" - }; - shaderKeywordRatios.Add(ratio); - } - - return shaderKeywordRatios.OrderBy(r => r.ShaderId).ToArray(); + ShaderId = reader.GetInt64(reader.GetOrdinal("shader_id")), + Name = reader.GetString(reader.GetOrdinal("name")), + SubShader = reader.GetInt64(reader.GetOrdinal("sub_shader")), + HwTier = reader.GetInt64(reader.GetOrdinal("hw_tier")), + Pass = reader.GetInt64(reader.GetOrdinal("pass")), + Api = reader.GetString(reader.GetOrdinal("api")), + PassName = reader.GetString(reader.GetOrdinal("pass_name")), + ShaderType = reader.GetString(reader.GetOrdinal("shader_type")), + TotalVariants = reader.GetValue(reader.GetOrdinal("total_variants")).ToString() ?? "", + Keyword = reader.GetString(reader.GetOrdinal("keyword")), + Variants = reader.GetValue(reader.GetOrdinal("variants")).ToString() ?? "", + Ratio = reader.GetValue(reader.GetOrdinal("ratio")).ToString() ?? "" + }).OrderBy(r => r.ShaderId).ToArray(); } public ShaderSubprogram[] GetShaderSubprograms(string dbPath) { - var shaderSubprograms = new List(); - - var connectionString = CreateConnectionString(dbPath); - using var connection = new SqliteConnection(connectionString); - connection.Open(); - - var command = connection.CreateCommand(); - command.CommandText = - "SELECT shader_id, name, sub_shader, hw_tier, api, pass, pass_name, shader_type, sub_program, keywords FROM shader_subprogram_view"; - - using var reader = command.ExecuteReader(); - while (reader.Read()) + const string sql = "SELECT shader_id, name, sub_shader, hw_tier, api, pass, pass_name, shader_type, sub_program, keywords FROM shader_subprogram_view"; + return Query(dbPath, sql, static reader => new ShaderSubprogram { - var subprogram = new ShaderSubprogram - { - ShaderId = reader.GetInt64(reader.GetOrdinal("shader_id")), - Name = reader.GetString(reader.GetOrdinal("name")), - SubShader = reader.GetInt64(reader.GetOrdinal("sub_shader")), - HwTier = reader.GetInt64(reader.GetOrdinal("hw_tier")), - Api = reader.GetString(reader.GetOrdinal("api")), - Pass = reader.GetInt64(reader.GetOrdinal("pass")), - PassName = reader.GetString(reader.GetOrdinal("pass_name")), - ShaderType = reader.GetString(reader.GetOrdinal("shader_type")), - SubProgram = reader.GetInt64(reader.GetOrdinal("sub_program")), - Keywords = reader.GetValue(reader.GetOrdinal("keywords")).ToString() ?? "" - }; - shaderSubprograms.Add(subprogram); - } - - return shaderSubprograms.OrderBy(sp => sp.ShaderId).ToArray(); + ShaderId = reader.GetInt64(reader.GetOrdinal("shader_id")), + Name = reader.GetString(reader.GetOrdinal("name")), + SubShader = reader.GetInt64(reader.GetOrdinal("sub_shader")), + HwTier = reader.GetInt64(reader.GetOrdinal("hw_tier")), + Api = reader.GetString(reader.GetOrdinal("api")), + Pass = reader.GetInt64(reader.GetOrdinal("pass")), + PassName = reader.GetString(reader.GetOrdinal("pass_name")), + ShaderType = reader.GetString(reader.GetOrdinal("shader_type")), + SubProgram = reader.GetInt64(reader.GetOrdinal("sub_program")), + Keywords = reader.GetValue(reader.GetOrdinal("keywords")).ToString() ?? "" + }).OrderBy(sp => sp.ShaderId).ToArray(); } public Shader[] GetShaders(string dbPath) { - var shaders = new List(); - - var connectionString = CreateConnectionString(dbPath); - using var connection = new SqliteConnection(connectionString); - connection.Open(); - - var command = connection.CreateCommand(); - command.CommandText = - "SELECT id, object_id, asset_bundle, serialized_file, type, name, game_object, size, pretty_size, crc32, decompressed_size, sub_shaders, sub_programs, unique_programs, keywords FROM shader_view"; - - using var reader = command.ExecuteReader(); - while (reader.Read()) + const string sql = "SELECT id, object_id, asset_bundle, serialized_file, type, name, game_object, size, pretty_size, crc32, decompressed_size, sub_shaders, sub_programs, unique_programs, keywords FROM shader_view"; + return Query(dbPath, sql, static reader => new Shader { - var shader = new Shader - { - Id = reader.GetInt64(reader.GetOrdinal("id")), - ObjectId = reader.GetInt64(reader.GetOrdinal("object_id")), - AssetBundle = reader.GetString(reader.GetOrdinal("asset_bundle")), - SerializedFile = reader.GetString(reader.GetOrdinal("serialized_file")), - Type = reader.GetString(reader.GetOrdinal("type")), - Name = reader.GetString(reader.GetOrdinal("name")), - GameObject = reader.GetInt64(reader.GetOrdinal("game_object")), - Size = reader.GetInt64(reader.GetOrdinal("size")), - PrettySize = reader.GetValue(reader.GetOrdinal("pretty_size")).ToString() ?? "0B", - Crc32 = reader.GetInt64(reader.GetOrdinal("crc32")), - DecompressedSize = reader.GetInt64(reader.GetOrdinal("decompressed_size")), - SubShaders = reader.GetValue(reader.GetOrdinal("sub_shaders")).ToString() ?? "", - SubPrograms = reader.GetValue(reader.GetOrdinal("sub_programs")).ToString() ?? "", - UniquePrograms = reader.GetInt64(reader.GetOrdinal("unique_programs")), - Keywords = reader.GetValue(reader.GetOrdinal("keywords")).ToString() ?? "" - }; - shaders.Add(shader); - } - - return shaders.OrderBy(shader => shader.Id).ToArray(); + Id = reader.GetInt64(reader.GetOrdinal("id")), + ObjectId = reader.GetInt64(reader.GetOrdinal("object_id")), + AssetBundle = reader.GetString(reader.GetOrdinal("asset_bundle")), + SerializedFile = reader.GetString(reader.GetOrdinal("serialized_file")), + Type = reader.GetString(reader.GetOrdinal("type")), + Name = reader.GetString(reader.GetOrdinal("name")), + GameObject = reader.GetInt64(reader.GetOrdinal("game_object")), + Size = reader.GetInt64(reader.GetOrdinal("size")), + PrettySize = reader.GetValue(reader.GetOrdinal("pretty_size")).ToString() ?? "0B", + Crc32 = reader.GetInt64(reader.GetOrdinal("crc32")), + DecompressedSize = reader.GetInt64(reader.GetOrdinal("decompressed_size")), + SubShaders = reader.GetValue(reader.GetOrdinal("sub_shaders")).ToString() ?? "", + SubPrograms = reader.GetValue(reader.GetOrdinal("sub_programs")).ToString() ?? "", + UniquePrograms = reader.GetInt64(reader.GetOrdinal("unique_programs")), + Keywords = reader.GetValue(reader.GetOrdinal("keywords")).ToString() ?? "" + }).OrderBy(shader => shader.Id).ToArray(); } public Texture[] GetTextures(string dbPath) { - var textures = new List(); - - var connectionString = CreateConnectionString(dbPath); - using var connection = new SqliteConnection(connectionString); - connection.Open(); - - var command = connection.CreateCommand(); - command.CommandText = - "SELECT id, object_id, asset_bundle, serialized_file, type, name, game_object, size, pretty_size, crc32, width, height, format, mip_count, rw_enabled FROM texture_view"; - - using var reader = command.ExecuteReader(); - while (reader.Read()) + const string sql = "SELECT id, object_id, asset_bundle, serialized_file, type, name, game_object, size, pretty_size, crc32, width, height, format, mip_count, rw_enabled FROM texture_view"; + return Query(dbPath, sql, static reader => new Texture { - var texture = new Texture - { - Id = reader.GetInt64(reader.GetOrdinal("id")), - ObjectId = reader.GetInt64(reader.GetOrdinal("object_id")), - AssetBundle = reader.GetString(reader.GetOrdinal("asset_bundle")), - SerializedFile = reader.GetString(reader.GetOrdinal("serialized_file")), - Type = reader.GetString(reader.GetOrdinal("type")), - Name = reader.GetString(reader.GetOrdinal("name")), - GameObject = reader.GetInt64(reader.GetOrdinal("game_object")), - Size = reader.GetInt64(reader.GetOrdinal("size")), - PrettySize = reader.GetValue(reader.GetOrdinal("pretty_size")).ToString() ?? "0B", - Crc32 = reader.GetInt64(reader.GetOrdinal("crc32")), - Width = reader.GetInt64(reader.GetOrdinal("width")), - Height = reader.GetInt64(reader.GetOrdinal("height")), - Format = reader.GetString(reader.GetOrdinal("format")), - MipCount = reader.GetInt64(reader.GetOrdinal("mip_count")), - RwEnabled = reader.GetInt64(reader.GetOrdinal("rw_enabled")) - }; - textures.Add(texture); - } - - return textures.OrderBy(texture => texture.Id).ToArray(); + Id = reader.GetInt64(reader.GetOrdinal("id")), + ObjectId = reader.GetInt64(reader.GetOrdinal("object_id")), + AssetBundle = reader.GetString(reader.GetOrdinal("asset_bundle")), + SerializedFile = reader.GetString(reader.GetOrdinal("serialized_file")), + Type = reader.GetString(reader.GetOrdinal("type")), + Name = reader.GetString(reader.GetOrdinal("name")), + GameObject = reader.GetInt64(reader.GetOrdinal("game_object")), + Size = reader.GetInt64(reader.GetOrdinal("size")), + PrettySize = reader.GetValue(reader.GetOrdinal("pretty_size")).ToString() ?? "0B", + Crc32 = reader.GetInt64(reader.GetOrdinal("crc32")), + Width = reader.GetInt64(reader.GetOrdinal("width")), + Height = reader.GetInt64(reader.GetOrdinal("height")), + Format = reader.GetString(reader.GetOrdinal("format")), + MipCount = reader.GetInt64(reader.GetOrdinal("mip_count")), + RwEnabled = reader.GetInt64(reader.GetOrdinal("rw_enabled")) + }).OrderBy(texture => texture.Id).ToArray(); } public BreakdownByType[] GetBreakdownByType(string dbPath) { - var breakdowns = new List(); - - var connectionString = CreateConnectionString(dbPath); - using var connection = new SqliteConnection(connectionString); - connection.Open(); - - var command = connection.CreateCommand(); - command.CommandText = "SELECT type, count, byte_size, pretty_size FROM view_breakdown_by_type"; - - using var reader = command.ExecuteReader(); - while (reader.Read()) + const string sql = "SELECT type, count, byte_size, pretty_size FROM view_breakdown_by_type"; + return Query(dbPath, sql, static reader => new BreakdownByType { - var breakdown = new BreakdownByType - { - Type = reader.GetString(reader.GetOrdinal("type")), - Count = reader.GetValue(reader.GetOrdinal("count")).ToString() ?? "0", - ByteSize = reader.GetValue(reader.GetOrdinal("byte_size")).ToString() ?? "0", - PrettySize = reader.GetValue(reader.GetOrdinal("pretty_size")).ToString() ?? "0B" - }; - breakdowns.Add(breakdown); - } - - return breakdowns.OrderBy(b => b.Type).ToArray(); + Type = reader.GetString(reader.GetOrdinal("type")), + Count = reader.GetValue(reader.GetOrdinal("count")).ToString() ?? "0", + ByteSize = reader.GetValue(reader.GetOrdinal("byte_size")).ToString() ?? "0", + PrettySize = reader.GetValue(reader.GetOrdinal("pretty_size")).ToString() ?? "0B" + }).OrderBy(b => b.Type).ToArray(); } public BreakdownShaders[] GetBreakdownShaders(string dbPath) { - var breakdowns = new List(); - - var connectionString = CreateConnectionString(dbPath); - using var connection = new SqliteConnection(connectionString); - connection.Open(); - - var command = connection.CreateCommand(); - command.CommandText = - "SELECT name, instances, pretty_total_size, total_size, in_bundles FROM view_breakdown_shaders"; - - using var reader = command.ExecuteReader(); - while (reader.Read()) + const string sql = "SELECT name, instances, pretty_total_size, total_size, in_bundles FROM view_breakdown_shaders"; + return Query(dbPath, sql, static reader => new BreakdownShaders { - var breakdown = new BreakdownShaders - { - Name = reader.GetString(reader.GetOrdinal("name")), - Instances = reader.GetValue(reader.GetOrdinal("instances")).ToString() ?? "0", - PrettyTotalSize = reader.GetValue(reader.GetOrdinal("pretty_total_size")).ToString() ?? "0B", - TotalSize = reader.GetValue(reader.GetOrdinal("total_size")).ToString() ?? "0", - InBundles = reader.GetValue(reader.GetOrdinal("in_bundles")).ToString() ?? "0" - }; - breakdowns.Add(breakdown); - } - - return breakdowns.OrderBy(b => b.Name).ToArray(); + Name = reader.GetString(reader.GetOrdinal("name")), + Instances = reader.GetValue(reader.GetOrdinal("instances")).ToString() ?? "0", + PrettyTotalSize = reader.GetValue(reader.GetOrdinal("pretty_total_size")).ToString() ?? "0B", + TotalSize = reader.GetValue(reader.GetOrdinal("total_size")).ToString() ?? "0", + InBundles = reader.GetValue(reader.GetOrdinal("in_bundles")).ToString() ?? "0" + }).OrderBy(b => b.Name).ToArray(); } public MaterialShaderRefs[] GetMaterialShaderRefs(string dbPath) { - var materialShaderRefs = new List(); - - var connectionString = CreateConnectionString(dbPath); - using var connection = new SqliteConnection(connectionString); - connection.Open(); - - var command = connection.CreateCommand(); - command.CommandText = - "SELECT material_id, material_name, material_path, material_asset_bundle, shader_id, shader_name, shader_asset_bundle FROM view_material_shader_refs"; - - using var reader = command.ExecuteReader(); - while (reader.Read()) + const string sql = "SELECT material_id, material_name, material_path, material_asset_bundle, shader_id, shader_name, shader_asset_bundle FROM view_material_shader_refs"; + return Query(dbPath, sql, static reader => new MaterialShaderRefs { - var refItem = new MaterialShaderRefs - { - MaterialId = reader.GetInt64(reader.GetOrdinal("material_id")), - MaterialName = reader.GetString(reader.GetOrdinal("material_name")), - MaterialPath = reader.GetString(reader.GetOrdinal("material_path")), - MaterialAssetBundle = reader.GetString(reader.GetOrdinal("material_asset_bundle")), - ShaderId = reader.GetInt64(reader.GetOrdinal("shader_id")), - ShaderName = reader.GetString(reader.GetOrdinal("shader_name")), - ShaderAssetBundle = reader.GetString(reader.GetOrdinal("shader_asset_bundle")) - }; - materialShaderRefs.Add(refItem); - } - - return materialShaderRefs.OrderBy(m => m.MaterialId).ToArray(); + MaterialId = reader.GetInt64(reader.GetOrdinal("material_id")), + MaterialName = reader.GetString(reader.GetOrdinal("material_name")), + MaterialPath = reader.GetString(reader.GetOrdinal("material_path")), + MaterialAssetBundle = reader.GetString(reader.GetOrdinal("material_asset_bundle")), + ShaderId = reader.GetInt64(reader.GetOrdinal("shader_id")), + ShaderName = reader.GetString(reader.GetOrdinal("shader_name")), + ShaderAssetBundle = reader.GetString(reader.GetOrdinal("shader_asset_bundle")) + }).OrderBy(m => m.MaterialId).ToArray(); } public MaterialTextureRefs[] GetMaterialTextureRefs(string dbPath) { - var materialTextureRefs = new List(); - - var connectionString = CreateConnectionString(dbPath); - using var connection = new SqliteConnection(connectionString); - connection.Open(); - - var command = connection.CreateCommand(); - command.CommandText = - "SELECT material_id, material_name, material_path, material_asset_bundle, texture_id, texture_name, texture_asset_bundle FROM view_material_texture_refs"; - - using var reader = command.ExecuteReader(); - while (reader.Read()) + const string sql = "SELECT material_id, material_name, material_path, material_asset_bundle, texture_id, texture_name, texture_asset_bundle FROM view_material_texture_refs"; + return Query(dbPath, sql, static reader => new MaterialTextureRefs { - var refItem = new MaterialTextureRefs - { - MaterialId = reader.GetInt64(reader.GetOrdinal("material_id")), - MaterialName = reader.GetString(reader.GetOrdinal("material_name")), - MaterialPath = reader.GetString(reader.GetOrdinal("material_path")), - MaterialAssetBundle = reader.GetString(reader.GetOrdinal("material_asset_bundle")), - TextureId = reader.GetInt64(reader.GetOrdinal("texture_id")), - TextureName = reader.GetString(reader.GetOrdinal("texture_name")), - TextureAssetBundle = reader.GetString(reader.GetOrdinal("texture_asset_bundle")) - }; - materialTextureRefs.Add(refItem); - } - - return materialTextureRefs.OrderBy(m => m.MaterialId).ToArray(); + MaterialId = reader.GetInt64(reader.GetOrdinal("material_id")), + MaterialName = reader.GetString(reader.GetOrdinal("material_name")), + MaterialPath = reader.GetString(reader.GetOrdinal("material_path")), + MaterialAssetBundle = reader.GetString(reader.GetOrdinal("material_asset_bundle")), + TextureId = reader.GetInt64(reader.GetOrdinal("texture_id")), + TextureName = reader.GetString(reader.GetOrdinal("texture_name")), + TextureAssetBundle = reader.GetString(reader.GetOrdinal("texture_asset_bundle")) + }).OrderBy(m => m.MaterialId).ToArray(); } public PotentialDuplicates[] GetPotentialDuplicates(string dbPath) { - var potentialDuplicates = new List(); - - var connectionString = CreateConnectionString(dbPath); - using var connection = new SqliteConnection(connectionString); - connection.Open(); - - var command = connection.CreateCommand(); - command.CommandText = - "SELECT instances, name, type, pretty_total_size, total_size, size, pretty_size, in_files FROM view_potential_duplicates"; - - using var reader = command.ExecuteReader(); - while (reader.Read()) + const string sql = "SELECT instances, name, type, pretty_total_size, total_size, size, pretty_size, in_files FROM view_potential_duplicates"; + return Query(dbPath, sql, static reader => new PotentialDuplicates { - var duplicate = new PotentialDuplicates - { - Instances = reader.GetValue(reader.GetOrdinal("instances")).ToString() ?? "0", - Name = reader.GetString(reader.GetOrdinal("name")), - Type = reader.GetString(reader.GetOrdinal("type")), - PrettyTotalSize = reader.GetValue(reader.GetOrdinal("pretty_total_size")).ToString() ?? "0B", - TotalSize = reader.GetValue(reader.GetOrdinal("total_size")).ToString() ?? "0", - Size = reader.GetInt64(reader.GetOrdinal("size")), - PrettySize = reader.GetValue(reader.GetOrdinal("pretty_size")).ToString() ?? "0B", - InFiles = reader.GetValue(reader.GetOrdinal("in_files")).ToString() ?? "0" - }; - potentialDuplicates.Add(duplicate); - } - - return potentialDuplicates.OrderBy(d => d.Name).ToArray(); + Instances = reader.GetValue(reader.GetOrdinal("instances")).ToString() ?? "0", + Name = reader.GetString(reader.GetOrdinal("name")), + Type = reader.GetString(reader.GetOrdinal("type")), + PrettyTotalSize = reader.GetValue(reader.GetOrdinal("pretty_total_size")).ToString() ?? "0B", + TotalSize = reader.GetValue(reader.GetOrdinal("total_size")).ToString() ?? "0", + Size = reader.GetInt64(reader.GetOrdinal("size")), + PrettySize = reader.GetValue(reader.GetOrdinal("pretty_size")).ToString() ?? "0B", + InFiles = reader.GetValue(reader.GetOrdinal("in_files")).ToString() ?? "0" + }).OrderBy(d => d.Name).ToArray(); } public string[] ExecuteCustomQuery(string dbPath, string query) { - var results = new List(); - - var connectionString = CreateConnectionString(dbPath); - using var connection = new SqliteConnection(connectionString); - connection.Open(); - - using var command = connection.CreateCommand(); - command.CommandText = query; - - using var reader = command.ExecuteReader(); - var builder = new StringBuilder(); - while (reader.Read()) + return Query(dbPath, query, static reader => { + var builder = new StringBuilder(); builder.Append("{ "); for (var i = 0; i < reader.FieldCount; i++) { @@ -554,19 +321,16 @@ public string[] ExecuteCustomQuery(string dbPath, string query) { builder.Append(", "); } - - builder.Append($"\"{reader.GetName(i)}\" : \"{reader.GetValue(i).ToString() ?? string.Empty}\""); + builder.Append($"\"{reader.GetName(i)}\" : \"{reader.GetValue(i)}\""); } - builder.Append(" }"); - results.Add(builder.ToString()); + var result = builder.ToString(); builder.Clear(); - } - - return results.ToArray(); + return result; + }); } - public void Dispose() + public void RefreshCache() { SqliteConnection.ClearAllPools(); } diff --git a/src/AssetBundleMCP/Repository/IAssetRepository.cs b/src/AssetBundleMCP/Repository/IAssetRepository.cs index 0d396a0..8d70b57 100644 --- a/src/AssetBundleMCP/Repository/IAssetRepository.cs +++ b/src/AssetBundleMCP/Repository/IAssetRepository.cs @@ -1,24 +1,25 @@ +using AssetBundleMcp.Entity; +using Object = AssetBundleMcp.Entity.Object; -using AssetBundleMcpServer.Entity; - -namespace AssetBundleMcpServer.Repository; +namespace AssetBundleMcp.Repository; public interface IAssetRepository { - public Animation[] GetAnimations(string dbPath); - public AssetDependencies[] GetAssetDependencies(string dbPath); - public Asset[] GetAssets(string dbPath); - public AudioClip[] GetAudioClips(string dbPath); - public Mesh[] GetMeshes(string dbPath); - public Entity.Object[] GetObjects(string dbPath); - public ShaderKeywordRatio[] GetShaderKeywordRatios(string dbPath); - public ShaderSubprogram[] GetShaderSubprograms(string dbPath); - public Shader[] GetShaders(string dbPath); - public Texture[] GetTextures(string dbPath); - public BreakdownByType[] GetBreakdownByType(string dbPath); - public BreakdownShaders[] GetBreakdownShaders(string dbPath); - public MaterialShaderRefs[] GetMaterialShaderRefs(string dbPath); - public MaterialTextureRefs[] GetMaterialTextureRefs(string dbPath); - public PotentialDuplicates[] GetPotentialDuplicates(string dbPath); - public string[] ExecuteCustomQuery(string dbPath, string query); + Animation[] GetAnimations(string dbPath); + AssetDependencies[] GetAssetDependencies(string dbPath); + Asset[] GetAssets(string dbPath); + AudioClip[] GetAudioClips(string dbPath); + Mesh[] GetMeshes(string dbPath); + Object[] GetObjects(string dbPath); + ShaderKeywordRatio[] GetShaderKeywordRatios(string dbPath); + ShaderSubprogram[] GetShaderSubprograms(string dbPath); + Shader[] GetShaders(string dbPath); + Texture[] GetTextures(string dbPath); + BreakdownByType[] GetBreakdownByType(string dbPath); + BreakdownShaders[] GetBreakdownShaders(string dbPath); + MaterialShaderRefs[] GetMaterialShaderRefs(string dbPath); + MaterialTextureRefs[] GetMaterialTextureRefs(string dbPath); + PotentialDuplicates[] GetPotentialDuplicates(string dbPath); + string[] ExecuteCustomQuery(string dbPath, string query); + void RefreshCache(); } \ No newline at end of file diff --git a/src/AssetBundleMCP/Service/AnalyzerService.cs b/src/AssetBundleMCP/Service/AnalyzerService.cs new file mode 100644 index 0000000..a507b7f --- /dev/null +++ b/src/AssetBundleMCP/Service/AnalyzerService.cs @@ -0,0 +1,61 @@ +using ModelContextProtocol; +using UnityDataTools.Analyzer; +using UnityDataTools.FileSystem; + +namespace AssetBundleMcp.Service; + +public class AnalyzerService : IAnalyzerService +{ + private readonly AnalyzerTool _analyzerTool = new(); + + public string Analyze(string assetBundlePath, string? databaseFilePath = null) + { + if (!Directory.Exists(assetBundlePath) && !File.Exists(assetBundlePath)) + { + throw new McpException($"Failed to load AssetBundle. Directory or File does not exist: {assetBundlePath}"); + } + var isFile = File.Exists(assetBundlePath); + + try + { + UnityFileSystem.Init(); + + databaseFilePath ??= Path.Combine(Directory.GetCurrentDirectory(), $"{Guid.NewGuid()}.db"); + var result = _analyzerTool.Analyze( + isFile ? Directory.GetParent(assetBundlePath)!.FullName : assetBundlePath, + databaseFilePath, + isFile ? Path.GetFileNameWithoutExtension(assetBundlePath) : "*", + false, + false, + false + ); + + if (result != 0) + { + throw new McpException( + "[ERROR] Failed to analyze AssetBundle. Please check the logs for more details."); + } + + return databaseFilePath; + } + catch (Exception ex) + { + throw new McpException($"[ERROR] Failed to parse AssetBundle: {ex.Message}"); + } + } + + public void Unload(string databaseFilePath) + { + if (File.Exists(databaseFilePath)) + { + try + { + File.Delete(databaseFilePath); + } + catch (Exception ex) + { + throw new McpException($"[ERROR] Failed to unload AssetBundle: {ex.Message}"); + } + } + } +} diff --git a/src/AssetBundleMCP/Service/AssetBundleService.cs b/src/AssetBundleMCP/Service/AssetBundleService.cs new file mode 100644 index 0000000..463a937 --- /dev/null +++ b/src/AssetBundleMCP/Service/AssetBundleService.cs @@ -0,0 +1,128 @@ +using System.Runtime.CompilerServices; +using AssetBundleMcp.Entity; +using AssetBundleMcp.Internal; +using AssetBundleMcp.Repository; +using ModelContextProtocol; +using Object = AssetBundleMcp.Entity.Object; + +namespace AssetBundleMcp.Service; + +public class AssetBundleService : IAssetBundleService +{ + public string? DatabasePath { get; private set; } + public bool IsLoaded => !string.IsNullOrEmpty(DatabasePath) && File.Exists(DatabasePath); + + private readonly IAssetRepository _repository; + private readonly IAnalyzerService _analyzerService; + + public AssetBundleService(IAssetRepository repository, IAnalyzerService analyzerService) + { + _repository = repository; + _analyzerService = analyzerService; + } + + public string LoadAssetBundle(string assetBundlePath, string? databaseFilePath = null) + { + if (IsLoaded) + { + UnLoadAssetBundle(); + } + + var generatedDbPath = _analyzerService.Analyze(assetBundlePath, databaseFilePath); + DatabasePath = generatedDbPath; + + return + $"Analysis complete. Output saved to {generatedDbPath}. Remember to call UnLoadAssetBundle to free resources when done."; + } + + public string UnLoadAssetBundle() + { + if (!IsLoaded) + { + throw new McpException("No AssetBundle loaded or database file not found."); + } + + try + { + _repository.RefreshCache(); + _analyzerService.Unload(DatabasePath!); + DatabasePath = null; + return "AssetBundle unloaded successfully."; + } + catch (Exception ex) + { + throw new McpException($"[ERROR] Failed to unload AssetBundle: {ex.Message}"); + } + } + + public Animation[] ListAnimations(int offset = 0, int pageSize = 100) => + GetData(offset, pageSize, repo => repo.GetAnimations(DatabasePath!)); + + public AssetDependencies[] ListAssetDependencies(int offset = 0, int pageSize = 100) => + GetData(offset, pageSize, repo => repo.GetAssetDependencies(DatabasePath!)); + + public Asset[] ListAssets(int offset = 0, int pageSize = 100) => + GetData(offset, pageSize, repo => repo.GetAssets(DatabasePath!)); + + public AudioClip[] ListAudioClips(int offset = 0, int pageSize = 100) => + GetData(offset, pageSize, repo => repo.GetAudioClips(DatabasePath!)); + + public Mesh[] ListMeshes(int offset = 0, int pageSize = 100) => + GetData(offset, pageSize, repo => repo.GetMeshes(DatabasePath!)); + + public Object[] ListObjects(int offset = 0, int pageSize = 100) => + GetData(offset, pageSize, repo => repo.GetObjects(DatabasePath!)); + + public ShaderKeywordRatio[] ListShaderKeywordRatios(int offset = 0, int pageSize = 100) => + GetData(offset, pageSize, repo => repo.GetShaderKeywordRatios(DatabasePath!)); + + public ShaderSubprogram[] ListShaderSubprograms(int offset = 0, int pageSize = 100) => + GetData(offset, pageSize, repo => repo.GetShaderSubprograms(DatabasePath!)); + + public Shader[] ListShaders(int offset = 0, int pageSize = 100) => + GetData(offset, pageSize, repo => repo.GetShaders(DatabasePath!)); + + public Texture[] ListTextures(int offset = 0, int pageSize = 100) => + GetData(offset, pageSize, repo => repo.GetTextures(DatabasePath!)); + + public BreakdownByType[] ListBreakdownByType(int offset = 0, int pageSize = 100) => + GetData(offset, pageSize, repo => repo.GetBreakdownByType(DatabasePath!)); + + public BreakdownShaders[] ListBreakdownShaders(int offset = 0, int pageSize = 100) => + GetData(offset, pageSize, repo => repo.GetBreakdownShaders(DatabasePath!)); + + public MaterialShaderRefs[] ListMaterialShaderRefs(int offset = 0, int pageSize = 100) => + GetData(offset, pageSize, repo => repo.GetMaterialShaderRefs(DatabasePath!)); + + public MaterialTextureRefs[] ListMaterialTextureRefs(int offset = 0, int pageSize = 100) => + GetData(offset, pageSize, repo => repo.GetMaterialTextureRefs(DatabasePath!)); + + public PotentialDuplicates[] ListPotentialDuplicates(int offset = 0, int pageSize = 100) => + GetData(offset, pageSize, repo => repo.GetPotentialDuplicates(DatabasePath!)); + + public string[] ExecuteSqlQuery(string query, int offset = 0, int pageSize = 100) => + GetData(offset, pageSize, repo => repo.ExecuteCustomQuery(DatabasePath!, query)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private T[] GetData( + int offset, + int pageSize, + Func> repositoryCall + ) + { + try + { + if (!IsLoaded) + { + throw new McpException("Database file not found. Please run LoadAssetBundle command first."); + } + + var result = repositoryCall(_repository); + return Paginate.Execute(result, offset, pageSize).ToArray(); + } + catch (Exception ex) + { + throw new McpException($"An unexpected error has occurred: {ex.Message}"); + } + } +} \ No newline at end of file diff --git a/src/AssetBundleMCP/Service/IAnalyzerService.cs b/src/AssetBundleMCP/Service/IAnalyzerService.cs new file mode 100644 index 0000000..11e5e95 --- /dev/null +++ b/src/AssetBundleMCP/Service/IAnalyzerService.cs @@ -0,0 +1,8 @@ +namespace AssetBundleMcp.Service; + +public interface IAnalyzerService +{ + string Analyze(string assetBundlePath, string? databaseFilePath = null); + + public void Unload(string databaseFilePath); +} diff --git a/src/AssetBundleMCP/Service/IAssetBundleService.cs b/src/AssetBundleMCP/Service/IAssetBundleService.cs new file mode 100644 index 0000000..04afc29 --- /dev/null +++ b/src/AssetBundleMCP/Service/IAssetBundleService.cs @@ -0,0 +1,27 @@ + +using AssetBundleMcp.Entity; +using Object = AssetBundleMcp.Entity.Object; + +namespace AssetBundleMcp.Service; + +public interface IAssetBundleService +{ + string LoadAssetBundle(string assetBundlePath, string? databaseFilePath = null); + string UnLoadAssetBundle(); + Animation[] ListAnimations(int offset = 0, int pageSize = 100); + AssetDependencies[] ListAssetDependencies(int offset = 0, int pageSize = 100); + Asset[] ListAssets(int offset = 0, int pageSize = 100); + AudioClip[] ListAudioClips(int offset = 0, int pageSize = 100); + Mesh[] ListMeshes(int offset = 0, int pageSize = 100); + Object[] ListObjects(int offset = 0, int pageSize = 100); + ShaderKeywordRatio[] ListShaderKeywordRatios(int offset = 0, int pageSize = 100); + ShaderSubprogram[] ListShaderSubprograms(int offset = 0, int pageSize = 100); + Shader[] ListShaders(int offset = 0, int pageSize = 100); + Texture[] ListTextures(int offset = 0, int pageSize = 100); + BreakdownByType[] ListBreakdownByType(int offset = 0, int pageSize = 100); + BreakdownShaders[] ListBreakdownShaders(int offset = 0, int pageSize = 100); + MaterialShaderRefs[] ListMaterialShaderRefs(int offset = 0, int pageSize = 100); + MaterialTextureRefs[] ListMaterialTextureRefs(int offset = 0, int pageSize = 100); + PotentialDuplicates[] ListPotentialDuplicates(int offset = 0, int pageSize = 100); + string[] ExecuteSqlQuery(string query, int offset = 0, int pageSize = 100); +} diff --git a/src/AssetBundleMCP/Tool/AssetBundleTools.cs b/src/AssetBundleMCP/Tool/AssetBundleTools.cs index c560e41..ca6f84a 100644 --- a/src/AssetBundleMCP/Tool/AssetBundleTools.cs +++ b/src/AssetBundleMCP/Tool/AssetBundleTools.cs @@ -1,26 +1,18 @@ + using System.ComponentModel; -using System.Runtime.CompilerServices; -using AssetBundleMcpServer.Internal; -using AssetBundleMcpServer.Entity; -using AssetBundleMcpServer.Repository; -using ModelContextProtocol; +using AssetBundleMcp.Entity; +using AssetBundleMcp.Service; using ModelContextProtocol.Server; -using UnityDataTools.Analyzer; -using UnityDataTools.FileSystem; -using Object = AssetBundleMcpServer.Entity.Object; +using Object = AssetBundleMcp.Entity.Object; -namespace AssetBundleMcpServer.Tool; +namespace AssetBundleMcp.Tool; [McpServerToolType, Description("MCP Server for Unity AssetBundle Reverse Engineering")] public static class AssetBundleTools { - // NOTE: I added the static modifier because the state could not be shared between Tools in the MCP Server without it. - // I may change how this status is maintained. - public static string? DatabasePath { get; private set; } - public static bool IsLoaded() => !string.IsNullOrEmpty(DatabasePath) && File.Exists(DatabasePath); - [McpServerTool, Description("Load a AssetBundle for analysis")] public static string LoadAssetBundle( + IAssetBundleService service, [Description("A path to the directory or files to analyze.")] string assetBundlePath, [Description( @@ -28,248 +20,200 @@ public static string LoadAssetBundle( string? databaseFilePath = null ) { - if (!Directory.Exists(assetBundlePath) && !File.Exists(assetBundlePath)) - { - throw new McpException($"Failed to load AssetBundle. Directory or File does not exist: {assetBundlePath}"); - } - var isFile = File.Exists(assetBundlePath); - - try - { - UnityFileSystem.Init(); - var analyzer = new AnalyzerTool(); - - databaseFilePath ??= Path.Combine(Directory.GetCurrentDirectory(), $"{Guid.NewGuid()}.db"); - var result = analyzer.Analyze( - isFile ? Directory.GetParent(assetBundlePath)!.FullName : assetBundlePath, - databaseFilePath, - isFile ? Path.GetFileNameWithoutExtension(assetBundlePath) : "*", - false, - false, - false - ); - - if (result != 0) - { - throw new McpException( - "[ERROR] Failed to analyze AssetBundle. Please check the logs for more details."); - } - - DatabasePath = databaseFilePath; - return - $"Analysis complete. Output saved to {databaseFilePath}. Remember to call UnLoadAssetBundle to free resources when done."; - } - catch (Exception ex) - { - throw new McpException($"[ERROR] Failed to parse AssetBundle: {ex.Message}"); - } + return service.LoadAssetBundle(assetBundlePath, databaseFilePath); } [McpServerTool, Description("UnLoad database file")] - public static string UnLoadAssetBundle() + public static string UnLoadAssetBundle(IAssetBundleService service) { - if (!IsLoaded()) - { - throw new McpException("No AssetBundle loaded or database file not found."); - } - - try - { - File.Delete(DatabasePath!); - DatabasePath = null; - return "AssetBundle unloaded successfully."; - } - catch (Exception ex) - { - throw new McpException($"[ERROR] Failed to unload AssetBundle: {ex.Message}"); - } + return service.UnLoadAssetBundle(); } [McpServerTool, Description("List all animations in Assetbundle")] public static Animation[] ListAnimations( - IAssetRepository repository, + IAssetBundleService service, [Description("Offset to start listing from(start at 0)")] int offset = 0, [Description("Number of items to list(100 is a good number,0 means remainder)")] int pageSize = 100 ) { - return GetData(repository, offset, pageSize, repo => repo.GetAnimations(DatabasePath!)); + return service.ListAnimations(offset, pageSize); } [McpServerTool, Description("List all asset dependencies in Assetbundle")] public static AssetDependencies[] ListAssetDependencies( - IAssetRepository repository, + IAssetBundleService service, [Description("Offset to start listing from(start at 0)")] int offset = 0, [Description("Number of items to list(100 is a good number,0 means remainder)")] int pageSize = 100 ) { - return GetData(repository, offset, pageSize, repo => repo.GetAssetDependencies(DatabasePath!)); + return service.ListAssetDependencies(offset, pageSize); } [McpServerTool, Description("List all asset in Assetbundle")] public static Asset[] ListAssets( - IAssetRepository repository, + IAssetBundleService service, [Description("Offset to start listing from(start at 0)")] int offset = 0, [Description("Number of items to list(100 is a good number,0 means remainder)")] int pageSize = 100 ) { - return GetData(repository, offset, pageSize, repo => repo.GetAssets(DatabasePath!)); + return service.ListAssets(offset, pageSize); } [McpServerTool, Description("List all audio clips in Assetbundle")] public static AudioClip[] ListAudioClips( - IAssetRepository repository, + IAssetBundleService service, [Description("Offset to start listing from(start at 0)")] int offset = 0, [Description("Number of items to list(100 is a good number,0 means remainder)")] int pageSize = 100 ) { - return GetData(repository, offset, pageSize, repo => repo.GetAudioClips(DatabasePath!)); + return service.ListAudioClips(offset, pageSize); } [McpServerTool, Description("List all meshes in Assetbundle")] public static Mesh[] ListMeshes( - IAssetRepository repository, + IAssetBundleService service, [Description("Offset to start listing from(start at 0)")] int offset = 0, [Description("Number of items to list(100 is a good number,0 means remainder)")] int pageSize = 100 ) { - return GetData(repository, offset, pageSize, repo => repo.GetMeshes(DatabasePath!)); + return service.ListMeshes(offset, pageSize); } [McpServerTool, Description("List all objects in Assetbundle")] public static Object[] ListObjects( - IAssetRepository repository, + IAssetBundleService service, [Description("Offset to start listing from(start at 0)")] int offset = 0, [Description("Number of items to list(100 is a good number,0 means remainder)")] int pageSize = 100 ) { - return GetData(repository, offset, pageSize, repo => repo.GetObjects(DatabasePath!)); + return service.ListObjects(offset, pageSize); } [McpServerTool, Description("List all shader keyword ratios in Assetbundle")] public static ShaderKeywordRatio[] ListShaderKeywordRatios( - IAssetRepository repository, + IAssetBundleService service, [Description("Offset to start listing from(start at 0)")] int offset = 0, [Description("Number of items to list(100 is a good number,0 means remainder)")] int pageSize = 100 ) { - return GetData(repository, offset, pageSize, repo => repo.GetShaderKeywordRatios(DatabasePath!)); + return service.ListShaderKeywordRatios(offset, pageSize); } [McpServerTool, Description("List all shader subprograms in Assetbundle")] public static ShaderSubprogram[] ListShaderSubprograms( - IAssetRepository repository, + IAssetBundleService service, [Description("Offset to start listing from(start at 0)")] int offset = 0, [Description("Number of items to list(100 is a good number,0 means remainder)")] int pageSize = 100 ) { - return GetData(repository, offset, pageSize, repo => repo.GetShaderSubprograms(DatabasePath!)); + return service.ListShaderSubprograms(offset, pageSize); } [McpServerTool, Description("List all shaders in Assetbundle")] public static Shader[] ListShaders( - IAssetRepository repository, + IAssetBundleService service, [Description("Offset to start listing from(start at 0)")] int offset = 0, [Description("Number of items to list(100 is a good number,0 means remainder)")] int pageSize = 100 ) { - return GetData(repository, offset, pageSize, repo => repo.GetShaders(DatabasePath!)); + return service.ListShaders(offset, pageSize); } [McpServerTool, Description("List all textures in Assetbundle")] public static Texture[] ListTextures( - IAssetRepository repository, + IAssetBundleService service, [Description("Offset to start listing from(start at 0)")] int offset = 0, [Description("Number of items to list(100 is a good number,0 means remainder)")] int pageSize = 100 ) { - return GetData(repository, offset, pageSize, repo => repo.GetTextures(DatabasePath!)); + return service.ListTextures(offset, pageSize); } [McpServerTool, Description("List all breakdown by type in Assetbundle")] public static BreakdownByType[] ListBreakdownByType( - IAssetRepository repository, + IAssetBundleService service, [Description("Offset to start listing from(start at 0)")] int offset = 0, [Description("Number of items to list(100 is a good number,0 means remainder)")] int pageSize = 100 ) { - return GetData(repository, offset, pageSize, repo => repo.GetBreakdownByType(DatabasePath!)); + return service.ListBreakdownByType(offset, pageSize); } [McpServerTool, Description("List all breakdown shaders in Assetbundle")] public static BreakdownShaders[] ListBreakdownShaders( - IAssetRepository repository, + IAssetBundleService service, [Description("Offset to start listing from(start at 0)")] int offset = 0, [Description("Number of items to list(100 is a good number,0 means remainder)")] int pageSize = 100 ) { - return GetData(repository, offset, pageSize, repo => repo.GetBreakdownShaders(DatabasePath!)); + return service.ListBreakdownShaders(offset, pageSize); } [McpServerTool, Description("List all material shader references in Assetbundle")] public static MaterialShaderRefs[] ListMaterialShaderRefs( - IAssetRepository repository, + IAssetBundleService service, [Description("Offset to start listing from(start at 0)")] int offset = 0, [Description("Number of items to list(100 is a good number,0 means remainder)")] int pageSize = 100 ) { - return GetData(repository, offset, pageSize, repo => repo.GetMaterialShaderRefs(DatabasePath!)); + return service.ListMaterialShaderRefs(offset, pageSize); } [McpServerTool, Description("List all material texture references in Assetbundle")] public static MaterialTextureRefs[] ListMaterialTextureRefs( - IAssetRepository repository, + IAssetBundleService service, [Description("Offset to start listing from(start at 0)")] int offset = 0, [Description("Number of items to list(100 is a good number,0 means remainder)")] int pageSize = 100 ) { - return GetData(repository, offset, pageSize, repo => repo.GetMaterialTextureRefs(DatabasePath!)); + return service.ListMaterialTextureRefs(offset, pageSize); } [McpServerTool, Description("List all potential duplicates in Assetbundle")] public static PotentialDuplicates[] ListPotentialDuplicates( - IAssetRepository repository, + IAssetBundleService service, [Description("Offset to start listing from(start at 0)")] int offset = 0, [Description("Number of items to list(100 is a good number,0 means remainder)")] int pageSize = 100 ) { - return GetData(repository, offset, pageSize, repo => repo.GetPotentialDuplicates(DatabasePath!)); + return service.ListPotentialDuplicates(offset, pageSize); } [McpServerTool, Description( "Execute a SQL query on the AssetBundle database.Please call GetAssetBundleSchema in the Resources of MCPServer to reference the schema.")] public static string[] ExecuteSqlQuery( - IAssetRepository repository, + IAssetBundleService service, [Description("The SQL query to execute. Ensure it is a valid query for the AssetBundle database schema.")] string query, [Description("Offset to start listing from(start at 0)")] @@ -278,30 +222,6 @@ public static string[] ExecuteSqlQuery( int pageSize = 100 ) { - return GetData(repository, offset, pageSize, repo => repo.ExecuteCustomQuery(DatabasePath!, query)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static T[] GetData( - IAssetRepository repository, - int offset, - int pageSize, - Func> repositoryCall - ) - { - try - { - if (!IsLoaded()) - { - throw new McpException("Database file not found. Please run LoadAssetBundle command first."); - } - - var result = repositoryCall(repository); - return Paginate.Execute(result, offset, pageSize).ToArray(); - } - catch (Exception ex) - { - throw new McpException($"An unexpected error has occurred: {ex.Message}"); - } + return service.ExecuteSqlQuery(query, offset, pageSize); } -} \ No newline at end of file +} diff --git a/tests/AssetBundleMCP.Tests/AssetBundleMCP.Tests.csproj b/tests/AssetBundleMCP.Tests/AssetBundleMCP.Tests.csproj index ee400d7..d55fd45 100644 --- a/tests/AssetBundleMCP.Tests/AssetBundleMCP.Tests.csproj +++ b/tests/AssetBundleMCP.Tests/AssetBundleMCP.Tests.csproj @@ -28,6 +28,13 @@ PreserveNewest + + PreserveNewest + + + + + diff --git a/tests/AssetBundleMCP.Tests/AssetBundleToolsTest.cs b/tests/AssetBundleMCP.Tests/AssetBundleToolsTest.cs index 75e78ec..75ccea7 100644 --- a/tests/AssetBundleMCP.Tests/AssetBundleToolsTest.cs +++ b/tests/AssetBundleMCP.Tests/AssetBundleToolsTest.cs @@ -1,36 +1,35 @@ -using AssetBundleMcpServer.Repository; -using AssetBundleMcpServer.Tool; +using AssetBundleMcp.Repository; +using AssetBundleMcp.Service; +using AssetBundleMcp.Tool; namespace AssetBundleMCP.Tests; public class Tests { private string AssetBundleDirPath => Path.Combine(AppContext.BaseDirectory, "TestData"); - - [OneTimeTearDown] - public void OneTimeTearDown() - { - if (AssetBundleTools.IsLoaded()) - { - AssetBundleTools.UnLoadAssetBundle(); - } - } - + [Test] - public void LoadAssetBundle() + public void LoadAndUnLoadAssetBundle() { - AssetBundleTools.LoadAssetBundle(AssetBundleDirPath); + var assetBundleService = CreateAssetBundleService(); + + AssetBundleTools.LoadAssetBundle(assetBundleService, AssetBundleDirPath); + var loadedPath = assetBundleService.DatabasePath; + AssetBundleTools.UnLoadAssetBundle(assetBundleService); + var unloadedPath = assetBundleService.DatabasePath; - Assert.That(AssetBundleTools.DatabasePath, Is.Not.Null); + Assert.That(loadedPath, Is.Not.Null); + Assert.That(unloadedPath, Is.Null); } [Test] public void ListAnimations() { - var repository = new AssetRepository(); - - AssetBundleTools.LoadAssetBundle(AssetBundleDirPath); - var animations = AssetBundleTools.ListAnimations(repository); + var assetBundleService = CreateAssetBundleService(); + + AssetBundleTools.LoadAssetBundle(assetBundleService, AssetBundleDirPath); + var animations = AssetBundleTools.ListAnimations(assetBundleService); + AssetBundleTools.UnLoadAssetBundle(assetBundleService); Assert.That(animations, Is.Not.Null); } @@ -38,10 +37,11 @@ public void ListAnimations() [Test] public void ListAssetDependencies() { - var repository = new AssetRepository(); - - AssetBundleTools.LoadAssetBundle(AssetBundleDirPath); - var dependencies = AssetBundleTools.ListAssetDependencies(repository); + var assetBundleService = CreateAssetBundleService(); + + AssetBundleTools.LoadAssetBundle(assetBundleService, AssetBundleDirPath); + var dependencies = AssetBundleTools.ListAssetDependencies(assetBundleService); + AssetBundleTools.UnLoadAssetBundle(assetBundleService); Assert.That(dependencies, Is.Not.Null); } @@ -49,10 +49,11 @@ public void ListAssetDependencies() [Test] public void ListAssets() { - var repository = new AssetRepository(); - - AssetBundleTools.LoadAssetBundle(AssetBundleDirPath); - var assets = AssetBundleTools.ListAssets(repository); + var assetBundleService = CreateAssetBundleService(); + + AssetBundleTools.LoadAssetBundle(assetBundleService, AssetBundleDirPath); + var assets = AssetBundleTools.ListAssets(assetBundleService); + AssetBundleTools.UnLoadAssetBundle(assetBundleService); Assert.That(assets, Is.Not.Null); } @@ -60,10 +61,11 @@ public void ListAssets() [Test] public void ListAudioClips() { - var repository = new AssetRepository(); - - AssetBundleTools.LoadAssetBundle(AssetBundleDirPath); - var audioClips = AssetBundleTools.ListAudioClips(repository); + var assetBundleService = CreateAssetBundleService(); + + AssetBundleTools.LoadAssetBundle(assetBundleService, AssetBundleDirPath); + var audioClips = AssetBundleTools.ListAudioClips(assetBundleService); + AssetBundleTools.UnLoadAssetBundle(assetBundleService); Assert.That(audioClips, Is.Not.Null); } @@ -71,10 +73,11 @@ public void ListAudioClips() [Test] public void ListMeshes() { - var repository = new AssetRepository(); - - AssetBundleTools.LoadAssetBundle(AssetBundleDirPath); - var meshes = AssetBundleTools.ListMeshes(repository); + var assetBundleService = CreateAssetBundleService(); + + AssetBundleTools.LoadAssetBundle(assetBundleService, AssetBundleDirPath); + var meshes = AssetBundleTools.ListMeshes(assetBundleService); + AssetBundleTools.UnLoadAssetBundle(assetBundleService); Assert.That(meshes, Is.Not.Null); } @@ -82,10 +85,11 @@ public void ListMeshes() [Test] public void ListObjects() { - var repository = new AssetRepository(); - - AssetBundleTools.LoadAssetBundle(AssetBundleDirPath); - var objects = AssetBundleTools.ListObjects(repository); + var assetBundleService = CreateAssetBundleService(); + + AssetBundleTools.LoadAssetBundle(assetBundleService, AssetBundleDirPath); + var objects = AssetBundleTools.ListObjects(assetBundleService); + AssetBundleTools.UnLoadAssetBundle(assetBundleService); Assert.That(objects, Is.Not.Null); } @@ -93,10 +97,11 @@ public void ListObjects() [Test] public void ListShaderKeywordRatios() { - var repository = new AssetRepository(); - - AssetBundleTools.LoadAssetBundle(AssetBundleDirPath); - var shaderKeywords = AssetBundleTools.ListShaderKeywordRatios(repository); + var assetBundleService = CreateAssetBundleService(); + + AssetBundleTools.LoadAssetBundle(assetBundleService, AssetBundleDirPath); + var shaderKeywords = AssetBundleTools.ListShaderKeywordRatios(assetBundleService); + AssetBundleTools.UnLoadAssetBundle(assetBundleService); Assert.That(shaderKeywords, Is.Not.Null); } @@ -104,10 +109,11 @@ public void ListShaderKeywordRatios() [Test] public void ListShaderSubprograms() { - var repository = new AssetRepository(); - - AssetBundleTools.LoadAssetBundle(AssetBundleDirPath); - var shaderSubprograms = AssetBundleTools.ListShaderSubprograms(repository); + var assetBundleService = CreateAssetBundleService(); + + AssetBundleTools.LoadAssetBundle(assetBundleService, AssetBundleDirPath); + var shaderSubprograms = AssetBundleTools.ListShaderSubprograms(assetBundleService); + AssetBundleTools.UnLoadAssetBundle(assetBundleService); Assert.That(shaderSubprograms, Is.Not.Null); } @@ -115,10 +121,11 @@ public void ListShaderSubprograms() [Test] public void ListShaders() { - var repository = new AssetRepository(); - - AssetBundleTools.LoadAssetBundle(AssetBundleDirPath); - var shaders = AssetBundleTools.ListShaders(repository); + var assetBundleService = CreateAssetBundleService(); + + AssetBundleTools.LoadAssetBundle(assetBundleService, AssetBundleDirPath); + var shaders = AssetBundleTools.ListShaders(assetBundleService); + AssetBundleTools.UnLoadAssetBundle(assetBundleService); Assert.That(shaders, Is.Not.Null); } @@ -126,10 +133,11 @@ public void ListShaders() [Test] public void ListTextures() { - var repository = new AssetRepository(); - - AssetBundleTools.LoadAssetBundle(AssetBundleDirPath); - var textures = AssetBundleTools.ListTextures(repository); + var assetBundleService = CreateAssetBundleService(); + + AssetBundleTools.LoadAssetBundle(assetBundleService, AssetBundleDirPath); + var textures = AssetBundleTools.ListTextures(assetBundleService); + AssetBundleTools.UnLoadAssetBundle(assetBundleService); Assert.That(textures, Is.Not.Null); } @@ -137,10 +145,11 @@ public void ListTextures() [Test] public void BreakdownByType() { - var repository = new AssetRepository(); - - AssetBundleTools.LoadAssetBundle(AssetBundleDirPath); - var breakdown = AssetBundleTools.ListBreakdownByType(repository); + var assetBundleService = CreateAssetBundleService(); + + AssetBundleTools.LoadAssetBundle(assetBundleService, AssetBundleDirPath); + var breakdown = AssetBundleTools.ListBreakdownByType(assetBundleService); + AssetBundleTools.UnLoadAssetBundle(assetBundleService); Assert.That(breakdown, Is.Not.Null); } @@ -148,10 +157,11 @@ public void BreakdownByType() [Test] public void BreakdownShaders() { - var repository = new AssetRepository(); - - AssetBundleTools.LoadAssetBundle(AssetBundleDirPath); - var breakdownShaders = AssetBundleTools.ListBreakdownShaders(repository); + var assetBundleService = CreateAssetBundleService(); + + AssetBundleTools.LoadAssetBundle(assetBundleService, AssetBundleDirPath); + var breakdownShaders = AssetBundleTools.ListBreakdownShaders(assetBundleService); + AssetBundleTools.UnLoadAssetBundle(assetBundleService); Assert.That(breakdownShaders, Is.Not.Null); } @@ -159,10 +169,11 @@ public void BreakdownShaders() [Test] public void ListMaterialShaderRefs() { - var repository = new AssetRepository(); - - AssetBundleTools.LoadAssetBundle(AssetBundleDirPath); - var materialShaderRefs = AssetBundleTools.ListMaterialShaderRefs(repository); + var assetBundleService = CreateAssetBundleService(); + + AssetBundleTools.LoadAssetBundle(assetBundleService, AssetBundleDirPath); + var materialShaderRefs = AssetBundleTools.ListMaterialShaderRefs(assetBundleService); + AssetBundleTools.UnLoadAssetBundle(assetBundleService); Assert.That(materialShaderRefs, Is.Not.Null); } @@ -170,10 +181,11 @@ public void ListMaterialShaderRefs() [Test] public void ListMaterialTextureRefs() { - var repository = new AssetRepository(); - - AssetBundleTools.LoadAssetBundle(AssetBundleDirPath); - var materialTextureRefs = AssetBundleTools.ListMaterialTextureRefs(repository); + var assetBundleService = CreateAssetBundleService(); + + AssetBundleTools.LoadAssetBundle(assetBundleService, AssetBundleDirPath); + var materialTextureRefs = AssetBundleTools.ListMaterialTextureRefs(assetBundleService); + AssetBundleTools.UnLoadAssetBundle(assetBundleService); Assert.That(materialTextureRefs, Is.Not.Null); } @@ -181,11 +193,19 @@ public void ListMaterialTextureRefs() [Test] public void ListPotentialDuplicates() { - var repository = new AssetRepository(); - - AssetBundleTools.LoadAssetBundle(AssetBundleDirPath); - var potentialDuplicates = AssetBundleTools.ListPotentialDuplicates(repository); + var assetBundleService = CreateAssetBundleService(); + + AssetBundleTools.LoadAssetBundle(assetBundleService, AssetBundleDirPath); + var potentialDuplicates = AssetBundleTools.ListPotentialDuplicates(assetBundleService); + AssetBundleTools.UnLoadAssetBundle(assetBundleService); Assert.That(potentialDuplicates, Is.Not.Null); } -} \ No newline at end of file + + private static AssetBundleService CreateAssetBundleService() + { + var repository = new AssetRepository(); + var analyzerService = new AnalyzerService(); + return new AssetBundleService(repository, analyzerService); + } +} diff --git a/tests/AssetBundleMCP.Tests/PaginateTest.cs b/tests/AssetBundleMCP.Tests/PaginateTest.cs index 89e56b1..0cb4e10 100644 --- a/tests/AssetBundleMCP.Tests/PaginateTest.cs +++ b/tests/AssetBundleMCP.Tests/PaginateTest.cs @@ -1,4 +1,4 @@ -using AssetBundleMcpServer.Internal; +using AssetBundleMcp.Internal; namespace AssetBundleMCP.Tests;