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

This commit is contained in:
2026-08-26 02:49:29 +08:00
commit 4930099af7
30 changed files with 1115 additions and 0 deletions
@@ -0,0 +1,29 @@
{
"name": "ShrinkApp.Starter.Basic.Runtime",
"rootNamespace": "ShrinkApp.Starter.Basic",
"references": [
"ShrinkApp.Core.Runtime",
"ShrinkContext.AppAdapter.Runtime",
"ShrinkContext.Core.Runtime",
"ShrinkCommand.Runtime",
"ShrinkCommand.Integration.App",
"ShrinkDataSaver.Integration.App",
"ShrinkDataSaver.Runtime",
"ShrinkNetwork.Runtime",
"ShrinkNetwork.Integration.App",
"ShrinkCommand.Integration.EventBus",
"ShrinkDataSaver.Integration.EventBus",
"ShrinkNetwork.Integration.EventBus",
"ShrinkCommand.Integration.Network",
"UnityEngine.UI",
"UniTask"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 10b7cf71574bd904594339a0824e028b
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,78 @@
#nullable enable
using System.Collections.Generic;
using System.Linq;
using ShrinkCommand.Integration.App;
using ShrinkCommand.Integration;
using ShrinkContext.AppAdapter;
using ShrinkDataSaver.Integration.App;
using ShrinkDataSaver.Integration;
using ShrinkNetwork.Integration.App;
using ShrinkNetwork.Integration;
using UnityEngine;
namespace ShrinkApp.Starter.Basic
{
/// <summary>
/// Basic Starter 的组合根:ContextLoader 模式下默认使用原生 Cordis 组件,
/// 不再把三个功能模块交给 IShrinkAppModuleInstaller 包装器执行。
/// </summary>
public static class ShrinkAppBasicContextComposition
{
private static readonly string[] DefaultModuleIdValues =
{
"shrink.network",
"shrink.command",
"shrink.datasaver",
"shrink.integration.command-network",
"shrink.integration.command-eventbus",
"shrink.integration.datasaver-eventbus",
"shrink.integration.network-eventbus"
};
public static IReadOnlyList<string> DefaultModuleIds => DefaultModuleIdValues;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void RegisterDefaultComposition()
{
ShrinkAppLoaderBootstrapper.DefaultComposition = Configure;
}
public static void Configure(ShrinkAppLoaderHost host)
{
if (host == null)
throw new System.ArgumentNullException(nameof(host));
RegisterOrReplace(host, "shrink.network", static () => new ShrinkNetworkAppComponent());
RegisterOrReplace(host, "shrink.command", static () => new ShrinkCommandAppComponent());
RegisterOrReplace(host, "shrink.datasaver", static () => new ShrinkDataSaverAppComponent());
host.AddModuleComponent("shrink.integration.command-network",
static () => new ShrinkCommandNetworkIntegrationComponent());
host.AddModuleComponent("shrink.integration.command-eventbus",
static () => new ShrinkCommandEventBusComponent());
host.AddModuleComponent("shrink.integration.datasaver-eventbus",
static () => new ShrinkDataSaverEventBusComponent());
host.AddModuleComponent("shrink.integration.network-eventbus",
static () => new ShrinkNetworkEventBusComponent());
}
private static void RegisterOrReplace(
ShrinkAppLoaderHost host,
string moduleId,
System.Func<ShrinkContext.IShrinkComponent> componentFactory)
{
if (host.ModuleIds.Any(id => string.Equals(id, moduleId, System.StringComparison.OrdinalIgnoreCase)))
host.OverrideModuleComponent(moduleId, componentFactory);
else
host.AddModuleComponent(moduleId, componentFactory);
}
public static ShrinkAppCompositionDocument CreateDefaultDocument()
{
var entries = new List<ShrinkAppCompositionEntry>(DefaultModuleIdValues.Length);
foreach (var moduleId in DefaultModuleIdValues)
entries.Add(new ShrinkAppCompositionEntry(moduleId));
return new ShrinkAppCompositionDocument(includeUnlistedEntries: false, entries);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5b07e8ba4e0ea394d929c688f6f4fcc4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+214
View File
@@ -0,0 +1,214 @@
#nullable enable
using System;
using System.Linq;
using Cysharp.Threading.Tasks;
using ShrinkCommand;
using ShrinkCommand.Integration.App;
using ShrinkContext.AppAdapter;
using ShrinkNetwork;
using ShrinkNetwork.Integration.App;
using UnityEngine;
namespace ShrinkApp.Starter.Basic
{
public sealed class ShrinkAppBasicCommandSource : IShrinkCommandSource
{
private readonly Action<string>? _sink;
private readonly bool _logToConsole;
public ShrinkAppBasicCommandSource(Action<string>? sink = null, bool logToConsole = true)
{
_sink = sink;
_logToConsole = logToConsole;
}
public string SourceId => "starter.basic.console";
public string DisplayName => "StarterBasicConsole";
public bool IsConsole => true;
public bool HasPermission(string permission) => true;
public UniTask WriteLineAsync(string message, System.Threading.CancellationToken cancellationToken = default)
{
_sink?.Invoke(message);
if (_logToConsole)
Debug.Log("[ShrinkApp.Basic.Command] " + message);
return UniTask.CompletedTask;
}
}
[ShrinkCommandSubscriber]
public static class ShrinkAppBasicDemoCommands
{
[ShrinkCommand("starter status", Description = "显示 Starter.Basic 当前状态")]
private static string StarterStatus()
{
var appRunning = ShrinkApp.IsRunning;
var loadedSlot = ShrinkDataSaver.ShrinkSave.LoadedSlot;
return $"appRunning={appRunning}, loadedSlot={loadedSlot}";
}
}
public static class ShrinkAppBasicDemoRuntime
{
private const string SettingsResourceName = "ShrinkAppBasicStarterSettings";
private static ShrinkLoopbackTransport? _loopbackClientTransport;
private static ShrinkLoopbackTransport? _loopbackServerTransport;
private static long _activeLoopbackSessionId = -1;
public static ShrinkAppBasicStarterSettings GetOrCreateSettings()
{
var asset = Resources.Load<ShrinkAppBasicStarterSettings>(SettingsResourceName);
if (asset != null)
return asset;
var fallback = ScriptableObject.CreateInstance<ShrinkAppBasicStarterSettings>();
fallback.defaultCommandText = "starter status";
fallback.defaultLoopbackSessionId = 1;
fallback.logCommandOutputToConsole = true;
return fallback;
}
public static string BuildStatusSummary()
{
var commandReady = ShrinkApp.Context?.Services.TryGet<ShrinkCommandAppService>(out _) == true;
var networkReady = ShrinkApp.Context?.Services.TryGet<ShrinkNetworkAppService>(out _) == true;
var dataSaverReady = ShrinkApp.Context?.Services.TryGet<ShrinkDataSaver.Integration.App.ShrinkDataSaverService>(out _) == true;
var appRunning = ShrinkApp.IsRunning || ShrinkAppLoaderBootstrapper.Instance?.Host.IsRunning == true;
return $"app={appRunning}, save={dataSaverReady}, cmd={commandReady}, net={networkReady}, loopbackSession={_activeLoopbackSessionId}";
}
public static string BuildDetailedStatus()
{
var settings = GetOrCreateSettings();
var recentSlot = ShrinkDataSaver.ShrinkSave.GetRecentSlotIndex();
var commandService = ShrinkApp.Context?.Services.TryGet<ShrinkCommandAppService>(out var command) == true ? command : null;
var networkService = ShrinkApp.Context?.Services.TryGet<ShrinkNetworkAppService>(out var network) == true ? network : null;
var diagnostics = networkService?.GetDiagnosticsSnapshot();
var moduleCount = ShrinkAppLoaderBootstrapper.Instance?.Host.ActiveModuleIds.Count
?? ShrinkApp.Host?.StartedModules.Count
?? 0;
var serviceCount = ShrinkApp.Context?.Services.GetRegisteredServiceTypeNames().Count ?? 0;
return
$"defaultCommand={settings.defaultCommandText}\n" +
$"loopbackAutoBind={settings.autoBindLoopbackTransport}, sessionId={settings.defaultLoopbackSessionId}\n" +
$"recentSlot={recentSlot}, loadedSlot={ShrinkDataSaver.ShrinkSave.LoadedSlot}\n" +
$"modules={moduleCount}, services={serviceCount}, commandCount={commandService?.Commands.Count ?? 0}, currentSessions={diagnostics?.CurrentSessions ?? 0}\n" +
$"{BuildStatusSummary()}";
}
public static string BuildModuleSummary()
{
var loaderHost = ShrinkAppLoaderBootstrapper.Instance?.Host;
if (loaderHost != null && loaderHost.ActiveModuleIds.Count > 0)
return string.Join("\n", loaderHost.ActiveModuleIds);
if (ShrinkApp.Host?.StartedModules == null || ShrinkApp.Host.StartedModules.Count == 0)
return "No started modules.";
return string.Join("\n", ShrinkApp.Host.StartedModules);
}
public static string BuildServiceSummary()
{
if (ShrinkApp.Context == null)
return "No registered services.";
return string.Join("\n", ShrinkApp.Context.Services.GetRegisteredServiceTypeNames());
}
public static string BuildSaveMetaSummary(ShrinkDataSaver.SaveMeta[]? metas)
{
if (metas == null || metas.Length == 0)
return "No save slots found.";
return string.Join("\n", metas
.OrderBy(meta => meta.SlotIndex)
.Select(meta =>
$"slot={meta.SlotIndex}, name={meta.SlotName}, playtime={meta.PlaytimeSeconds:F0}s, modified={meta.LastModifiedTime:g}"));
}
public static string BuildCommandListSummary()
{
if (ShrinkApp.Context?.Services.TryGet<ShrinkCommandAppService>(out var commandService) != true || commandService == null)
return "Command service not ready.";
return string.Join("\n", commandService.Commands
.OrderBy(command => command.Path, StringComparer.OrdinalIgnoreCase)
.Take(10)
.Select(command => command.Path));
}
public static string BuildNetworkSummary()
{
if (ShrinkApp.Context?.Services.TryGet<ShrinkNetworkAppService>(out var networkService) != true || networkService == null)
return "Network service not ready.";
var diagnostics = networkService.GetDiagnosticsSnapshot();
var sessions = networkService.GetSessionSummaries();
return
$"sessions={diagnostics.CurrentSessions}, connected={diagnostics.SessionsConnected}, disconnected={diagnostics.SessionsDisconnected}\n" +
$"packetsSent={diagnostics.PacketsSent}, packetsReceived={diagnostics.PacketsReceived}\n" +
$"rpcStarted={diagnostics.RpcStarted}, rpcCompleted={diagnostics.RpcCompleted}\n" +
string.Join("\n", sessions);
}
public static async UniTask<string> ExecuteCommandAsync(string? commandText, Action<string>? outputSink = null)
{
var command = ShrinkApp.Services.GetRequired<ShrinkCommandAppService>();
var settings = GetOrCreateSettings();
var source = new ShrinkAppBasicCommandSource(outputSink, settings.logCommandOutputToConsole);
var effectiveCommand = string.IsNullOrWhiteSpace(commandText)
? settings.defaultCommandText
: commandText.Trim();
var result = await command.ExecuteAsync(source, effectiveCommand);
if (!string.IsNullOrWhiteSpace(result.Message))
outputSink?.Invoke(result.Message);
return result.Message;
}
public static string EnsureLoopbackReady()
{
var network = ShrinkApp.Services.GetRequired<ShrinkNetworkAppService>().Service;
var settings = GetOrCreateSettings();
if (_loopbackClientTransport == null || _loopbackServerTransport == null)
{
_loopbackClientTransport = new ShrinkLoopbackTransport();
_loopbackServerTransport = new ShrinkLoopbackTransport();
_loopbackClientTransport.LinkPeer(_loopbackServerTransport);
}
network.BindTransport(_loopbackClientTransport);
if (_activeLoopbackSessionId != settings.defaultLoopbackSessionId)
{
if (_activeLoopbackSessionId >= 0)
_loopbackClientTransport.CloseSession(_activeLoopbackSessionId);
_activeLoopbackSessionId = settings.defaultLoopbackSessionId;
_loopbackClientTransport.OpenSession(_activeLoopbackSessionId);
}
return $"loopbackBound={network.Sessions.Count}, session={_activeLoopbackSessionId}";
}
public static string AutoBindLoopbackIfEnabled()
{
var settings = GetOrCreateSettings();
if (!settings.autoBindLoopbackTransport)
return string.Empty;
return EnsureLoopbackReady();
}
public static string DisconnectLoopback()
{
if (_loopbackClientTransport == null || _activeLoopbackSessionId < 0)
return "loopbackNotBound";
_loopbackClientTransport.CloseSession(_activeLoopbackSessionId);
_activeLoopbackSessionId = -1;
return "loopbackDisconnected";
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 21ca7aa1ab7f9c64e9b4d050458df3d4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+173
View File
@@ -0,0 +1,173 @@
#nullable enable
using Cysharp.Threading.Tasks;
using ShrinkDataSaver;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace ShrinkApp.Starter.Basic
{
public sealed class ShrinkAppBasicSampleController : MonoBehaviour
{
[SerializeField] private Text? statusText;
[SerializeField] private Text? detailText;
[SerializeField] private Text? outputText;
[SerializeField] private Text? moduleText;
[SerializeField] private Text? serviceText;
[SerializeField] private Text? saveMetaText;
[SerializeField] private Text? commandListText;
[SerializeField] private Text? networkText;
[SerializeField] private Button? saveButton;
[SerializeField] private Button? loadButton;
[SerializeField] private Button? commandButton;
[SerializeField] private Button? loopbackButton;
[SerializeField] private Button? refreshButton;
[SerializeField] private Button? clearOutputButton;
[SerializeField] private Button? disconnectLoopbackButton;
[SerializeField] private InputField? commandInputField;
private int _counter;
private readonly List<string> _outputLines = new();
private void Awake()
{
if (saveButton != null)
saveButton.onClick.AddListener(() => SaveAsync().Forget());
if (loadButton != null)
loadButton.onClick.AddListener(() => LoadAsync().Forget());
if (commandButton != null)
commandButton.onClick.AddListener(() => RunCommandAsync().Forget());
if (loopbackButton != null)
loopbackButton.onClick.AddListener(BindLoopback);
if (refreshButton != null)
refreshButton.onClick.AddListener(RefreshPanels);
if (clearOutputButton != null)
clearOutputButton.onClick.AddListener(ClearOutput);
if (disconnectLoopbackButton != null)
disconnectLoopbackButton.onClick.AddListener(DisconnectLoopback);
}
private void Start()
{
var settings = ShrinkAppBasicDemoRuntime.GetOrCreateSettings();
if (commandInputField != null)
commandInputField.text = settings.defaultCommandText;
var autoLoopbackMessage = ShrinkAppBasicDemoRuntime.AutoBindLoopbackIfEnabled();
RefreshStatus("ShrinkApp Basic starter ready.");
if (!string.IsNullOrWhiteSpace(autoLoopbackMessage))
AppendOutput(autoLoopbackMessage);
RefreshPanels();
if (settings.autoRunDefaultCommandOnStart)
RunCommandAsync().Forget();
}
private async UniTaskVoid SaveAsync()
{
_counter++;
ShrinkSettings.Set("ShrinkApp.Basic.Counter", _counter);
await ShrinkSave.SaveSlotAsync(0);
RefreshStatus($"Saved counter={_counter}, recentSlot={ShrinkSave.GetRecentSlotIndex()}");
AppendOutput("save: slot 0");
RefreshPanels();
}
private async UniTaskVoid LoadAsync()
{
if (await ShrinkSave.SlotExistsAsync(0))
await ShrinkSave.LoadSlotAsync(0);
_counter = ShrinkSettings.Get("ShrinkApp.Basic.Counter", 0);
RefreshStatus($"Loaded counter={_counter}, loadedSlot={ShrinkSave.LoadedSlot}");
AppendOutput("load: slot 0");
RefreshPanels();
}
private async UniTaskVoid RunCommandAsync()
{
var message = await ShrinkAppBasicDemoRuntime.ExecuteCommandAsync(commandInputField?.text, AppendOutput);
RefreshStatus(message);
RefreshPanels();
}
private void BindLoopback()
{
var message = ShrinkAppBasicDemoRuntime.EnsureLoopbackReady();
AppendOutput(message);
RefreshStatus(message);
RefreshPanels();
}
private void DisconnectLoopback()
{
var message = ShrinkAppBasicDemoRuntime.DisconnectLoopback();
AppendOutput(message);
RefreshStatus(message);
RefreshPanels();
}
private void RefreshPanels()
{
RefreshDetail(ShrinkAppBasicDemoRuntime.BuildDetailedStatus());
RefreshInspectorText().Forget();
}
private void RefreshStatus(string text)
{
if (statusText != null)
statusText.text = text;
Debug.Log("[ShrinkApp.Starter.Basic] " + text);
}
private void RefreshDetail(string text)
{
if (detailText != null)
detailText.text = text;
}
private void AppendOutput(string text)
{
if (string.IsNullOrWhiteSpace(text))
return;
var settings = ShrinkAppBasicDemoRuntime.GetOrCreateSettings();
_outputLines.Add(text.Trim());
while (_outputLines.Count > settings.maxCommandOutputLines)
_outputLines.RemoveAt(0);
if (outputText != null)
outputText.text = string.Join("\n", _outputLines);
}
private void ClearOutput()
{
_outputLines.Clear();
if (outputText != null)
outputText.text = string.Empty;
}
private async UniTaskVoid RefreshInspectorText()
{
if (saveMetaText != null)
{
var metas = await ShrinkSave.GetAllMetaAsync();
saveMetaText.text = ShrinkAppBasicDemoRuntime.BuildSaveMetaSummary(metas);
}
if (moduleText != null)
moduleText.text = ShrinkAppBasicDemoRuntime.BuildModuleSummary();
if (serviceText != null)
serviceText.text = ShrinkAppBasicDemoRuntime.BuildServiceSummary();
if (commandListText != null)
commandListText.text = ShrinkAppBasicDemoRuntime.BuildCommandListSummary();
if (networkText != null)
networkText.text = ShrinkAppBasicDemoRuntime.BuildNetworkSummary();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2bc64b7d684d71f469b2335a8c4269ce
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+17
View File
@@ -0,0 +1,17 @@
#nullable enable
using UnityEngine;
namespace ShrinkApp.Starter.Basic
{
[CreateAssetMenu(fileName = "ShrinkAppBasicStarterSettings", menuName = "ShrinkApp/Starter/Basic Settings")]
public class ShrinkAppBasicStarterSettings : ScriptableObject
{
public bool autoBindLoopbackTransport;
public long defaultLoopbackSessionId = 1;
public string defaultCommandText = "starter status";
public bool logCommandOutputToConsole = true;
public bool autoRunDefaultCommandOnStart;
public int maxCommandOutputLines = 12;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2a4a0f6f7946adc45a3437ca04698c65
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: