feat: add shared runtime abstractions packages

This commit is contained in:
2026-09-05 03:18:06 +08:00
commit 0d8ef2904d
14 changed files with 332 additions and 0 deletions
+50
View File
@@ -0,0 +1,50 @@
name: Publish NuGet packages
on:
push:
tags:
- 'v*'
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
env:
NUGET_AUTH_TOKEN: ${{ secrets.SHRINKSDK_PACKAGE_TOKEN }}
steps:
- name: Checkout tagged source
uses: actions/checkout@v4
- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Validate tag and pack projects
shell: bash
run: |
set -euo pipefail
tag="${GITEA_REF#refs/tags/}"
version="$(node -p "require('./package.json').version")"
test "$tag" = "v$version"
mkdir -p packages
mapfile -d '' projects < <(find DotNet~ Godot~ -type f -name '*.csproj' -print0 2>/dev/null || true)
test "${#projects[@]}" -gt 0
for project in "${projects[@]}"; do
dotnet restore "$project" --configfile NuGet.Config
dotnet pack "$project" --configuration Release --no-restore --output "$PWD/packages" --include-symbols --include-source
done
find packages -maxdepth 1 -name '*.nupkg' -type f | grep -q .
- name: Publish packages
shell: bash
run: |
set -euo pipefail
: "${NUGET_AUTH_TOKEN:?SHRINKSDK_PACKAGE_TOKEN is required}"
dotnet nuget push 'packages/*.nupkg' --api-key "$NUGET_AUTH_TOKEN" --source https://git.crash.work/api/packages/ShrinkSDK/nuget/index.json --skip-duplicate
if compgen -G 'packages/*.snupkg' > /dev/null; then
dotnet nuget push 'packages/*.snupkg' --api-key "$NUGET_AUTH_TOKEN" --source https://git.crash.work/api/packages/ShrinkSDK/nuget/index.json --skip-duplicate
fi
+67
View File
@@ -0,0 +1,67 @@
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 exact tagged release archive
env:
GITEA_REF: ${{ gitea.ref }}
shell: bash
run: |
set -eu
tag="${GITEA_REF#refs/tags/}"
case "$tag" in
v[0-9]*) ;;
*) echo "Expected a version tag ref, got: $GITEA_REF" >&2; exit 1 ;;
esac
export SHRINKSDK_ARCHIVE_URL="https://git.crash.work/ShrinkSDK/ShrinkRuntime.Abstractions/archive/${tag}.tar.gz"
node --input-type=module <<'NODE'
import { writeFile } from 'node:fs/promises';
const response = await fetch(process.env.SHRINKSDK_ARCHIVE_URL);
if (!response.ok) {
throw new Error(`Release archive download failed: ${response.status} ${response.statusText}`);
}
await writeFile('release.tar.gz', new Uint8Array(await response.arrayBuffer()));
NODE
mkdir release
tar -xzf release.tar.gz --strip-components=1 -C release
rm -f release.tar.gz
printf '%s' "$tag" > release/.shrink-sdk-release-tag
- name: Validate immutable release version
shell: bash
run: |
set -eu
cd release
tag="$(cat .shrink-sdk-release-tag)"
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}"
cd release
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/
+3
View File
@@ -0,0 +1,3 @@
**/bin/
**/obj/
artifacts/
+11
View File
@@ -0,0 +1,11 @@
.git/
.gitea/
Development~/
Tools~/
DotNet~/
Godot~/
NuGet.Config
*.csproj
*.sln
*.user
*.DotSettings.user
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<AssemblyName>ShrinkRuntime.Abstractions</AssemblyName>
<RootNamespace>ShrinkSDK.Runtime</RootNamespace>
<PackageId>ShrinkSDK.Runtime.Abstractions</PackageId>
<Version>0.1.0</Version>
<Description>Engine-neutral ShrinkSDK runtime contracts.</Description>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Runtime\ShrinkRuntimeServices.cs" Link="Runtime\ShrinkRuntimeServices.cs" />
</ItemGroup>
</Project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="ShrinkSDK" value="https://git.crash.work/api/packages/ShrinkSDK/nuget/index.json" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
</packageSources>
</configuration>
+7
View File
@@ -0,0 +1,7 @@
# ShrinkSDK Runtime Abstractions
Unity 和普通 .NET/Godot 宿主共用的平台服务合同,包含日志、主线程派发、时钟、持久化路径、截图和应用生命周期。
- Unity:安装 `com.cneicy.shrink-runtime-abstractions`
- .NET/Godot:安装 `ShrinkSDK.Runtime.Abstractions`
- NuGet 打包工程位于 `DotNet~/ShrinkSDK.Runtime.Abstractions.csproj`
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fdcff332146fc1d439fc0c82285637da
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,5 @@
{
"name": "ShrinkRuntime.Abstractions",
"rootNamespace": "ShrinkSDK.Runtime",
"autoReferenced": true
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9285a23e48a9fd04ea5d3a7507010d2b
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+127
View File
@@ -0,0 +1,127 @@
#nullable enable
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace ShrinkSDK.Runtime
{
public enum ShrinkLogLevel { Trace, Debug, Information, Warning, Error }
public interface IShrinkLogger
{
void Log(ShrinkLogLevel level, string message, Exception? exception = null);
}
public interface IShrinkMainThreadDispatcher
{
bool IsMainThread { get; }
bool TryPost(Action action);
}
public interface IShrinkClock
{
DateTimeOffset UtcNow { get; }
double UnscaledTimeSeconds { get; }
}
public interface IShrinkPathProvider
{
string PersistentDataPath { get; }
string TemporaryDataPath { get; }
}
public interface IShrinkScreenshotProvider
{
ValueTask<byte[]> CapturePngAsync(CancellationToken cancellationToken = default);
}
public interface IShrinkApplicationLifecycle
{
event Action? Paused;
event Action? Resumed;
event Action? Exiting;
}
public static class ShrinkLoggerExtensions
{
public static void Error(this IShrinkLogger logger, string message, Exception? exception = null) =>
logger.Log(ShrinkLogLevel.Error, message, exception);
}
public static class ShrinkRuntimeServices
{
private static IShrinkLogger _logger = new ConsoleLogger();
private static IShrinkMainThreadDispatcher _dispatcher = new InlineDispatcher();
private static IShrinkClock _clock = new SystemClock();
private static IShrinkPathProvider _paths = new SystemPaths();
public static IShrinkLogger Logger => _logger;
public static IShrinkMainThreadDispatcher Dispatcher => _dispatcher;
public static IShrinkClock Clock => _clock;
public static IShrinkPathProvider Paths => _paths;
public static IShrinkScreenshotProvider? Screenshots { get; private set; }
public static IShrinkApplicationLifecycle? Lifecycle { get; private set; }
public static void Configure(IShrinkLogger logger, IShrinkMainThreadDispatcher dispatcher,
IShrinkClock clock, IShrinkPathProvider paths,
IShrinkScreenshotProvider? screenshots = null, IShrinkApplicationLifecycle? lifecycle = null)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
_clock = clock ?? throw new ArgumentNullException(nameof(clock));
_paths = paths ?? throw new ArgumentNullException(nameof(paths));
Screenshots = screenshots;
Lifecycle = lifecycle;
}
private sealed class ConsoleLogger : IShrinkLogger
{
public void Log(ShrinkLogLevel level, string message, Exception? exception = null)
{
Console.WriteLine($"[{level}] {message}");
if (exception != null) Console.WriteLine(exception);
}
}
private sealed class InlineDispatcher : IShrinkMainThreadDispatcher
{
public bool IsMainThread => true;
public bool TryPost(Action action)
{
if (action == null) return false;
action();
return true;
}
}
private sealed class SystemClock : IShrinkClock
{
private readonly Stopwatch _stopwatch = Stopwatch.StartNew();
public DateTimeOffset UtcNow => DateTimeOffset.UtcNow;
public double UnscaledTimeSeconds => _stopwatch.Elapsed.TotalSeconds;
}
private sealed class SystemPaths : IShrinkPathProvider
{
public string PersistentDataPath => Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "ShrinkSDK");
public string TemporaryDataPath => Path.GetTempPath();
}
}
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
public sealed class ShrinkCodeGenWovenAttribute : Attribute
{
public ShrinkCodeGenWovenAttribute(string weaverVersion, string inputMvid)
{
WeaverVersion = weaverVersion;
InputMvid = inputMvid;
}
public string WeaverVersion { get; }
public string InputMvid { get; }
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9f9b07df5ab1dc345be31f33e94077d2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+7
View File
@@ -0,0 +1,7 @@
{
"name": "com.cneicy.shrink-runtime-abstractions",
"version": "0.1.0",
"displayName": "ShrinkSDK Runtime Abstractions",
"description": "Engine-neutral runtime services and CodeGen marker contracts.",
"unity": "2022.3"
}
+7
View File
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 2f07481a8e08f454fa1d85c5afe4c92d
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: