146 lines
5.4 KiB
Plaintext
146 lines
5.4 KiB
Plaintext
using System.Text;
|
|
using System.Text.Json;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace ShrinkNetwork.ServerHost.Framework;
|
|
|
|
public sealed class UnityNetworkScanManifest
|
|
{
|
|
public string AssetsPath { get; set; } = string.Empty;
|
|
public DateTimeOffset ScannedAtUtc { get; set; }
|
|
public List<UnityNetworkMessageEntry> Messages { get; set; } = new();
|
|
public List<UnityNetworkSubscriberEntry> Subscribers { get; set; } = new();
|
|
}
|
|
|
|
public sealed class UnityNetworkMessageEntry
|
|
{
|
|
public string FilePath { get; set; } = string.Empty;
|
|
public string TypeName { get; set; } = string.Empty;
|
|
public int Opcode { get; set; }
|
|
public string Route { get; set; } = string.Empty;
|
|
}
|
|
|
|
public sealed class UnityNetworkSubscriberEntry
|
|
{
|
|
public string FilePath { get; set; } = string.Empty;
|
|
public string MemberName { get; set; } = string.Empty;
|
|
public string Authority { get; set; } = string.Empty;
|
|
public string Permission { get; set; } = string.Empty;
|
|
}
|
|
|
|
public static class UnityNetworkCodeScanner
|
|
{
|
|
private static readonly Regex MessageRegex = new(
|
|
@"\[ShrinkNetworkMessage\((?<opcode>-?\d+)\s*,\s*""(?<route>[^""]+)""\)\][\s\S]*?(?:class|struct)\s+(?<name>\w+)",
|
|
RegexOptions.Compiled);
|
|
|
|
private static readonly Regex SubscriberRegex = new(
|
|
@"\[ShrinkNetworkSubscribe\((?<args>.*?)\)\][\s\S]*?(?:UniTask<.*?>|UniTask|void|Task<.*?>|Task)\s+(?<name>\w+)\s*\(",
|
|
RegexOptions.Compiled);
|
|
|
|
private static readonly Regex AuthorityRegex = new(
|
|
@"Authority\s*=\s*ShrinkNetworkAuthority\.(?<value>\w+)",
|
|
RegexOptions.Compiled);
|
|
|
|
private static readonly Regex PermissionRegex = new(
|
|
@"Permission\s*=\s*""(?<value>[^""]+)""",
|
|
RegexOptions.Compiled);
|
|
|
|
public static UnityNetworkScanManifest Scan(string assetsPath)
|
|
{
|
|
var manifest = new UnityNetworkScanManifest
|
|
{
|
|
AssetsPath = assetsPath,
|
|
ScannedAtUtc = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
if (!Directory.Exists(assetsPath))
|
|
return manifest;
|
|
|
|
foreach (var file in Directory.EnumerateFiles(assetsPath, "*.cs", SearchOption.AllDirectories))
|
|
{
|
|
if (file.IndexOf($"{Path.DirectorySeparatorChar}Editor{Path.DirectorySeparatorChar}", StringComparison.OrdinalIgnoreCase) >= 0)
|
|
continue;
|
|
|
|
var content = File.ReadAllText(file);
|
|
var relativePath = Path.GetRelativePath(assetsPath, file).Replace('\\', '/');
|
|
|
|
foreach (Match match in MessageRegex.Matches(content))
|
|
{
|
|
manifest.Messages.Add(new UnityNetworkMessageEntry
|
|
{
|
|
FilePath = relativePath,
|
|
TypeName = match.Groups["name"].Value,
|
|
Opcode = int.Parse(match.Groups["opcode"].Value),
|
|
Route = match.Groups["route"].Value
|
|
});
|
|
}
|
|
|
|
foreach (Match match in SubscriberRegex.Matches(content))
|
|
{
|
|
var args = match.Groups["args"].Value;
|
|
manifest.Subscribers.Add(new UnityNetworkSubscriberEntry
|
|
{
|
|
FilePath = relativePath,
|
|
MemberName = match.Groups["name"].Value,
|
|
Authority = AuthorityRegex.Match(args).Groups["value"].Value,
|
|
Permission = PermissionRegex.Match(args).Groups["value"].Value
|
|
});
|
|
}
|
|
}
|
|
|
|
manifest.Messages = manifest.Messages
|
|
.OrderBy(item => item.Opcode)
|
|
.ThenBy(item => item.TypeName, StringComparer.Ordinal)
|
|
.ToList();
|
|
|
|
manifest.Subscribers = manifest.Subscribers
|
|
.OrderBy(item => item.Permission, StringComparer.Ordinal)
|
|
.ThenBy(item => item.MemberName, StringComparer.Ordinal)
|
|
.ToList();
|
|
|
|
return manifest;
|
|
}
|
|
|
|
public static void WriteOutputs(UnityNetworkScanManifest manifest, string outputDirectory)
|
|
{
|
|
Directory.CreateDirectory(outputDirectory);
|
|
|
|
var jsonPath = Path.Combine(outputDirectory, "unity-network-scan.json");
|
|
var markdownPath = Path.Combine(outputDirectory, "UNITY_NETWORK_SCAN.md");
|
|
|
|
File.WriteAllText(jsonPath, JsonSerializer.Serialize(manifest, new JsonSerializerOptions
|
|
{
|
|
WriteIndented = true
|
|
}));
|
|
|
|
var markdown = new StringBuilder();
|
|
markdown.AppendLine("# Unity 网络代码扫描清单");
|
|
markdown.AppendLine();
|
|
markdown.AppendLine($"扫描时间:{manifest.ScannedAtUtc:yyyy-MM-dd HH:mm:ss} UTC");
|
|
markdown.AppendLine($"Assets 路径:`{manifest.AssetsPath}`");
|
|
markdown.AppendLine();
|
|
markdown.AppendLine("## 网络消息");
|
|
markdown.AppendLine();
|
|
|
|
foreach (var message in manifest.Messages)
|
|
markdown.AppendLine($"- `{message.Opcode}` `{message.Route}` `{message.TypeName}` [{message.FilePath}]");
|
|
|
|
markdown.AppendLine();
|
|
markdown.AppendLine("## 订阅与权限");
|
|
markdown.AppendLine();
|
|
|
|
if (manifest.Subscribers.Count == 0)
|
|
{
|
|
markdown.AppendLine("- 本次扫描未发现 `[ShrinkNetworkSubscribe]`。");
|
|
}
|
|
else
|
|
{
|
|
foreach (var subscriber in manifest.Subscribers)
|
|
markdown.AppendLine($"- `{subscriber.MemberName}` authority=`{subscriber.Authority}` permission=`{subscriber.Permission}` [{subscriber.FilePath}]");
|
|
}
|
|
|
|
File.WriteAllText(markdownPath, markdown.ToString());
|
|
}
|
|
}
|