chore: initialize standalone UPM package
Publish UPM package / publish (push) Failing after 1s

This commit is contained in:
2026-08-26 02:50:40 +08:00
commit 235bf38f58
21 changed files with 547 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
name: Publish UPM package
on:
push:
tags:
- 'v*'
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
env:
NODE_AUTH_TOKEN: ${{ secrets.SHRINKSDK_PACKAGE_TOKEN }}
steps:
- name: Fetch tagged revision
shell: bash
run: |
set -eu
ref="${{ gitea.sha }}"
test -n "$ref"
git init .
git remote add origin "https://git.crash.work/ShrinkSDK/ShrinkShared.CodeGen.git"
git fetch --depth=1 origin "$ref"
git checkout --detach FETCH_HEAD
- name: Validate immutable release version
shell: bash
run: |
set -eu
tag="$(git describe --exact-match --tags HEAD)"
version="$(node -p "require('./package.json').version")"
test "$tag" = "v$version"
npm pack --dry-run
- name: Publish to ShrinkSDK registry
shell: bash
run: |
set -eu
: "${NODE_AUTH_TOKEN:?SHRINKSDK_PACKAGE_TOKEN is required}"
npmrc="$HOME/.npmrc"
cleanup() { rm -f "$npmrc"; }
trap cleanup EXIT
printf '%s\n' \
'registry=https://git.crash.work/api/packages/ShrinkSDK/npm/' \
'//git.crash.work/api/packages/ShrinkSDK/npm/:_authToken=${NODE_AUTH_TOKEN}' > "$npmrc"
npm publish --registry=https://git.crash.work/api/packages/ShrinkSDK/npm/
+39
View File
@@ -0,0 +1,39 @@
name: Verify standalone Unity package
on:
workflow_dispatch:
jobs:
editmode:
runs-on: unity-2022.3.62f3
container:
image: docker.1panel.live/unityci/editor:ubuntu-2022.3.62f3-windows-mono-3
volumes:
- /www/dk_project/bt-recovery/gitea/runner/seedskey-unity-license:/root/.local/share/unity3d/Unity
- /www/dk_project/bt-recovery/gitea/runner/seedskey-unity-entitlements:/root/.config/unity3d/Unity/licenses
steps:
- name: Fetch selected revision
shell: bash
run: |
set -eu
ref="${{ gitea.sha }}"
git init .
git remote add origin "https://git.crash.work/ShrinkSDK/ShrinkShared.CodeGen.git"
git fetch --depth=1 origin "$ref"
git checkout --detach FETCH_HEAD
- name: Run package EditMode tests
shell: bash
run: |
set -eu
unity_bin="$(command -v unity-editor || command -v unity || command -v Unity || true)"
test -n "$unity_bin"
"$unity_bin" \
-batchmode \
-nographics \
-quit \
-projectPath "$PWD/Development~/UnityProject" \
-runTests \
-testPlatform EditMode \
-testResults "$PWD/TestResults/editmode.xml" \
-logFile "$PWD/TestResults/unity.log"
+10
View File
@@ -0,0 +1,10 @@
/Development~/UnityProject/[Ll]ibrary/
/Development~/UnityProject/[Tt]emp/
/Development~/UnityProject/[Oo]bj/
/Development~/UnityProject/[Ll]ogs/
/Development~/UnityProject/[Uu]ser[Ss]ettings/
/Development~/UnityProject/TestResults/
/Tools~/**/[Bb]in/
/Tools~/**/[Oo]bj/
*.user
*.DotSettings.user
+8
View File
@@ -0,0 +1,8 @@
.git/
.gitea/
Development~/
Tools~/
*.csproj
*.sln
*.user
*.DotSettings.user
+6
View File
@@ -0,0 +1,6 @@
[Ll]ibrary/
[Tt]emp/
[Oo]bj/
[Ll]ogs/
[Uu]ser[Ss]ettings/
TestResults/
@@ -0,0 +1,15 @@
{
"scopedRegistries": [
{
"name": "ShrinkSDK",
"url": "https://git.crash.work/api/packages/ShrinkSDK/npm/",
"scopes": [
"com.cneicy"
]
}
],
"dependencies": {
"com.unity.test-framework": "1.1.33",
"com.cneicy.shrink-shared-codegen": "file:../../.."
}
}
@@ -0,0 +1,2 @@
m_EditorVersion: 2022.3.62f3
m_EditorVersionWithRevision: 2022.3.62f3 (96770f904ca7)
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7881ad37b016fc84ea31b463403d901a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+84
View File
@@ -0,0 +1,84 @@
#nullable enable
using System.Collections.Generic;
using System.IO;
using System.Threading;
using Mono.Cecil;
using Unity.CompilationPipeline.Common.ILPostProcessing;
namespace ShrinkShared.CodeGen
{
internal sealed class PostProcessorAssemblyResolver : IAssemblyResolver
{
private readonly string[] _references;
private readonly Dictionary<string, AssemblyDefinition> _cache = new();
private AssemblyDefinition? _self;
public PostProcessorAssemblyResolver(ICompiledAssembly compiledAssembly)
{
_references = compiledAssembly.References;
}
public void AddAssemblyDefinitionBeingOperatedOn(AssemblyDefinition assemblyDefinition)
{
_self = assemblyDefinition;
}
public AssemblyDefinition? Resolve(AssemblyNameReference name)
=> Resolve(name, new ReaderParameters(ReadingMode.Deferred));
public AssemblyDefinition? Resolve(AssemblyNameReference name, ReaderParameters parameters)
{
lock (_cache)
{
if (name.Name == _self?.Name.Name)
return _self;
var path = FindPath(name);
if (path == null)
return null;
var key = $"{path}{File.GetLastWriteTime(path)}";
if (_cache.TryGetValue(key, out var cached))
return cached;
parameters.AssemblyResolver = this;
var assembly = AssemblyDefinition.ReadAssembly(ReadFileWithRetry(path), parameters);
_cache[key] = assembly;
return assembly;
}
}
private string? FindPath(AssemblyNameReference name)
{
foreach (var reference in _references)
{
if (Path.GetFileNameWithoutExtension(reference) == name.Name)
return reference;
}
return null;
}
private static MemoryStream ReadFileWithRetry(string path, int retries = 5)
{
for (var i = 0; i < retries; i++)
{
try
{
return new MemoryStream(File.ReadAllBytes(path));
}
catch (IOException) when (i < retries - 1)
{
Thread.Sleep(100);
}
}
throw new IOException($"[ShrinkShared.CodeGen] 无法读取文件: {path}");
}
public void Dispose()
{
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b750fb992bcdddc479a883b1b6bf5ef2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+34
View File
@@ -0,0 +1,34 @@
#nullable enable
using System.Linq;
using System.Reflection;
using Mono.Cecil;
namespace ShrinkShared.CodeGen
{
internal sealed class PostProcessorReflectionImporter : DefaultReflectionImporter
{
private const string CoreLibName = "System.Private.CoreLib";
private readonly AssemblyNameReference? _corlib;
public PostProcessorReflectionImporter(ModuleDefinition module)
: base(module)
{
_corlib = module.AssemblyReferences.FirstOrDefault(reference => reference.Name is "mscorlib" or "netstandard");
}
public override AssemblyNameReference ImportReference(AssemblyName reference)
{
if (_corlib != null && reference.Name == CoreLibName)
return _corlib;
return base.ImportReference(reference);
}
}
internal sealed class PostProcessorReflectionImporterProvider : IReflectionImporterProvider
{
public IReflectionImporter GetReflectionImporter(ModuleDefinition module)
=> new PostProcessorReflectionImporter(module);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 31170a0a3448b8f428b07fa251fe5d10
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+192
View File
@@ -0,0 +1,192 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Pdb;
using Unity.CompilationPipeline.Common.Diagnostics;
using Unity.CompilationPipeline.Common.ILPostProcessing;
namespace ShrinkShared.CodeGen
{
public sealed class ShrinkRegistryILPostProcessor : ILPostProcessor
{
public override ILPostProcessor GetInstance() => this;
public override bool WillProcess(ICompiledAssembly compiledAssembly)
{
// 注意:不能因为"引用了 ShrinkEventBus.Runtime"就处理该程序集。
// 一旦把 ShrinkApp.Core.Runtime 等核心程序集卷入 Cecil 读写,写回的 dll
// 会被 Unity 判定为 "references itself" 而整条依赖链拒绝加载。
// 只处理直接承载 Command/Network/App 注册表的程序集。
return compiledAssembly.References.Any(path =>
Path.GetFileNameWithoutExtension(path) is "ShrinkCommand.Runtime" or "ShrinkNetwork.Runtime"
or "ShrinkApp.Core.Runtime");
}
public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly)
{
var diagnostics = new List<DiagnosticMessage>();
if (!WillProcess(compiledAssembly))
return new ILPostProcessResult(compiledAssembly.InMemoryAssembly, diagnostics);
var assemblyDefinition = AssemblyDefinitionFor(compiledAssembly);
var module = assemblyDefinition.MainModule;
try
{
InjectShrinkCommandRegistry(module);
InjectShrinkNetworkRegistry(module);
InjectShrinkAppRegistry(module);
}
catch (Exception ex)
{
diagnostics.Add(new DiagnosticMessage
{
DiagnosticType = DiagnosticType.Error,
MessageData = $"[ShrinkShared.CodeGen] {ex.Message}"
});
}
return GetResult(assemblyDefinition, diagnostics);
}
private void InjectShrinkCommandRegistry(ModuleDefinition module)
{
var subscriberType = FindType(module, "ShrinkCommand.ShrinkCommandSubscriberAttribute", "ShrinkCommand.Runtime");
var commandAttributeType = FindType(module, "ShrinkCommand.ShrinkCommandAttribute", "ShrinkCommand.Runtime");
var registryCtor = FindTypeArrayConstructor(module,
"ShrinkCommand.ShrinkCommandStaticRegistryAttribute",
"ShrinkCommand.Runtime");
if (subscriberType == null || commandAttributeType == null || registryCtor == null)
return;
var subscriberTypes = module.Types
.Where(type => HasAttribute(type, subscriberType))
.Where(type => type.Methods.Any(method => method.IsStatic && HasAttribute(method, commandAttributeType)))
.Select(type => module.ImportReference(type))
.ToArray();
if (subscriberTypes.Length > 0)
AddAssemblyTypeArrayAttribute(module, registryCtor, subscriberTypes);
}
private void InjectShrinkNetworkRegistry(ModuleDefinition module)
{
var messageAttributeType = FindType(module, "ShrinkNetwork.ShrinkNetworkMessageAttribute", "ShrinkNetwork.Runtime");
var subscriberAttributeType = FindType(module, "ShrinkNetwork.ShrinkNetworkSubscriberAttribute", "ShrinkNetwork.Runtime");
var subscribeAttributeType = FindType(module, "ShrinkNetwork.ShrinkNetworkSubscribeAttribute", "ShrinkNetwork.Runtime");
var messageCtor = FindTypeArrayConstructor(module, "ShrinkNetwork.ShrinkNetworkMessageRegistryAttribute", "ShrinkNetwork.Runtime");
var subscriberCtor = FindTypeArrayConstructor(module, "ShrinkNetwork.ShrinkNetworkStaticSubscriberRegistryAttribute", "ShrinkNetwork.Runtime");
if (messageAttributeType != null && messageCtor != null)
{
var messageTypes = module.Types
.Where(type => HasAttribute(type, messageAttributeType))
.Select(type => module.ImportReference(type))
.ToArray();
if (messageTypes.Length > 0)
AddAssemblyTypeArrayAttribute(module, messageCtor, messageTypes);
}
if (subscriberAttributeType != null && subscribeAttributeType != null && subscriberCtor != null)
{
var subscriberTypes = module.Types
.Where(type => HasAttribute(type, subscriberAttributeType))
.Where(type => type.Methods.Any(method => method.IsStatic && HasAttribute(method, subscribeAttributeType)))
.Select(type => module.ImportReference(type))
.ToArray();
if (subscriberTypes.Length > 0)
AddAssemblyTypeArrayAttribute(module, subscriberCtor, subscriberTypes);
}
}
private void InjectShrinkAppRegistry(ModuleDefinition module)
{
var installerAttributeType = FindType(module, "ShrinkApp.ShrinkAppModuleInstallerAttribute", "ShrinkApp.Core.Runtime");
var installerInterfaceType = FindType(module, "ShrinkApp.IShrinkAppModuleInstaller", "ShrinkApp.Core.Runtime");
var registryCtor = FindTypeArrayConstructor(module, "ShrinkApp.ShrinkAppInstallerRegistryAttribute", "ShrinkApp.Core.Runtime");
if (installerAttributeType == null || installerInterfaceType == null || registryCtor == null)
return;
var installerTypes = module.Types
.Where(type => !type.IsAbstract)
.Where(type => HasAttribute(type, installerAttributeType))
.Where(type => type.Interfaces.Any(item => item.InterfaceType.FullName == installerInterfaceType.FullName))
.Select(type => module.ImportReference(type))
.ToArray();
if (installerTypes.Length > 0)
AddAssemblyTypeArrayAttribute(module, registryCtor, installerTypes);
}
private static bool HasAttribute(ICustomAttributeProvider provider, TypeReference expectedAttributeType)
{
return provider.CustomAttributes.Any(attribute => attribute.AttributeType.FullName == expectedAttributeType.FullName);
}
private static void AddAssemblyTypeArrayAttribute(ModuleDefinition module, MethodReference ctor, TypeReference[] types)
{
var attribute = new CustomAttribute(ctor);
var typeTypeRef = module.ImportReference(typeof(Type));
attribute.ConstructorArguments.Add(new CustomAttributeArgument(
module.ImportReference(typeof(Type[])),
types.Select(type => new CustomAttributeArgument(typeTypeRef, type)).ToArray()));
module.Assembly.CustomAttributes.Add(attribute);
}
private static TypeReference? FindType(ModuleDefinition module, string fullName, string assemblyName)
{
var resolved = Type.GetType($"{fullName}, {assemblyName}", false);
return resolved == null ? null : module.ImportReference(resolved);
}
private static MethodReference? FindTypeArrayConstructor(ModuleDefinition module, string fullName, string assemblyName)
{
var typeRef = FindType(module, fullName, assemblyName);
var typeDef = typeRef?.Resolve();
var ctor = typeDef?.Methods.FirstOrDefault(method =>
method.IsConstructor &&
method.Parameters.Count == 1 &&
method.Parameters[0].ParameterType.IsArray &&
method.Parameters[0].ParameterType.GetElementType().FullName == module.ImportReference(typeof(Type)).FullName);
return ctor == null ? null : module.ImportReference(ctor);
}
private static AssemblyDefinition AssemblyDefinitionFor(ICompiledAssembly compiledAssembly)
{
var assemblyResolver = new PostProcessorAssemblyResolver(compiledAssembly);
var readerParameters = new ReaderParameters
{
SymbolStream = new MemoryStream(compiledAssembly.InMemoryAssembly.PdbData.ToArray()),
SymbolReaderProvider = new PdbReaderProvider(),
AssemblyResolver = assemblyResolver,
ReflectionImporterProvider = new PostProcessorReflectionImporterProvider(),
ReadingMode = ReadingMode.Immediate
};
var assemblyDefinition = AssemblyDefinition.ReadAssembly(
new MemoryStream(compiledAssembly.InMemoryAssembly.PeData.ToArray()),
readerParameters);
assemblyResolver.AddAssemblyDefinitionBeingOperatedOn(assemblyDefinition);
return assemblyDefinition;
}
private static ILPostProcessResult GetResult(AssemblyDefinition assemblyDefinition, List<DiagnosticMessage> diagnostics)
{
var pe = new MemoryStream();
var pdb = new MemoryStream();
assemblyDefinition.Write(pe, new WriterParameters
{
SymbolWriterProvider = new PdbWriterProvider(),
SymbolStream = pdb,
WriteSymbols = true
});
return new ILPostProcessResult(new InMemoryAssembly(pe.ToArray(), pdb.ToArray()), diagnostics);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0f07f372d8ceeed47aa4e5702fd1adef
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+21
View File
@@ -0,0 +1,21 @@
{
"name": "Unity.ShrinkShared.CodeGen",
"rootNamespace": "ShrinkShared.CodeGen",
"references": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": true,
"overrideReferences": true,
"precompiledReferences": [
"Mono.Cecil.dll",
"Mono.Cecil.Mdb.dll",
"Mono.Cecil.Pdb.dll",
"Mono.Cecil.Rocks.dll"
],
"autoReferenced": false,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
+7
View File
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 89b1954231cba2541ab97b45f6a407fe
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+5
View File
@@ -0,0 +1,5 @@
# Shrink Shared CodeGen
Editor-only UPM 包,为引用 ShrinkCommand.Runtime、ShrinkNetwork.Runtime 或 ShrinkApp.Core.Runtime 的程序集生成程序集级注册表。
该包只通过 Cecil 按程序集名和类型全名读取元数据,不在 asmdef 或 UPM 层反向引用业务包。因此 App、Command、Network 可以依赖它而不形成循环依赖。运行时不包含此包代码。
+7
View File
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c9ae00f51ad2a3e4a82845953bf8bff9
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+20
View File
@@ -0,0 +1,20 @@
{
"name": "com.cneicy.shrink-shared-codegen",
"version": "0.1.0",
"displayName": "Shrink Shared CodeGen",
"description": "ShrinkApp、ShrinkCommand 与 ShrinkNetwork 共用的 Unity IL 后处理注册表生成器。",
"unity": "2022.3",
"dependencies": {
"com.unity.nuget.mono-cecil": "1.11.4"
},
"keywords": [
"codegen",
"ilpp",
"registry"
],
"author": {
"name": "cneicy",
"url": "https://git.crash.work/ShrinkSDK"
},
"documentationUrl": "https://git.crash.work/ShrinkSDK/ShrinkShared.CodeGen"
}
+7
View File
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 12ee30d453322c346b13f068125681d5
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: