From a013da4cbe3213a762ff8b092b7d787aedb8a0e4 Mon Sep 17 00:00:00 2001 From: Mohamad Iraji <4851913+Enzx@users.noreply.github.com> Date: Fri, 7 Aug 2026 23:29:53 +0200 Subject: [PATCH] Multi-target the serialization libraries to netstandard2.1 and ship them to Unity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NxGraph.Serialization and NxGraph.Serialization.Abstraction were net8.0-only on the recorded grounds that no netstandard2.1 consumer existed. One does now: the Unity graph editor loads and saves graph payloads in-editor, so both libraries join the core in targeting net8.0 + netstandard2.1, and a second UPM package ships them. The netstandard2.1 leg costs three small shims per assembly (init-only marker, caller argument attribute, argument-null guard), compiled in only on that TFM because the core's copies are internal. NxGraph.Serialization adds Compat.cs for the text-IO overloads the platform lacks — the conditional lives in the helper so ~30 call sites compile unchanged — plus an explicit System.Text.Json reference pinned to the 8.0.x line, so both TFMs serialize identically, and CopyLocalLockFileAssemblies so the dependency closure lands beside the assembly for staging. No public surface differs between the two TFMs. The public API test grows a netstandard2.1 baseline per shipped assembly, walked through a MetadataLoadContext over the netstandard2.1 build output; a baseline that stops matching its net8.0 twin means a member went TFM-conditional, which is a design change rather than a baseline update. com.enzx.nxgraph.serialization bundles its own third-party closure (MessagePack, System.Text.Json, BCL facades) rather than asking consumers to resolve it — duplicate assembly risk traded for zero setup. Its .meta sidecars are the reviewed allowlist of what staging may write, so adding a dependency breaks stage-binary until the new closure is reviewed. stage-source still refuses to stage it: source mode compiles the core as NxGraph.Unity.Runtime, which a prebuilt NxGraph.Serialization.dll cannot bind to. unity/NxGraphDev is the development harness that verifies this end to end — a batch-mode round-trip through the staged plugins. It references both packages by relative path, so Unity works against the tree directly, and its generated projects are ignored so they never collide with NxGraph.sln. --- .github/workflows/upm-build.yml | 12 +- .github/workflows/upm-release.yml | 89 ++- .gitignore | 29 +- Directory.Build.props | 20 +- NxGraph.Build/BuildHelpers.cs | 113 ++- NxGraph.Build/Program.cs | 213 +++++- NxGraph.Build/README.md | 32 +- .../NxGraph.Serialization.Abstraction.csproj | 12 +- .../Shims/ArgumentNullExceptionShim.cs | 30 + .../CallerArgumentExpressionAttribute.cs | 18 + .../Shims/IsExternalInit.cs | 14 + NxGraph.Serialization/BehaviorRegistry.cs | 2 +- NxGraph.Serialization/BlackboardSerializer.cs | 4 +- NxGraph.Serialization/Compat.cs | 56 ++ NxGraph.Serialization/ConditionRegistry.cs | 2 +- NxGraph.Serialization/GraphSerializer.cs | 4 +- .../NxGraph.Serialization.csproj | 26 +- .../RegionSelectorRegistry.cs | 2 +- .../Shims/ArgumentNullExceptionShim.cs | 29 + NxGraph.Serialization/Shims/IsExternalInit.cs | 14 + ...on.Abstraction.netstandard2.1.approved.txt | 100 +++ ....Serialization.netstandard2.1.approved.txt | 42 ++ .../PublicApi/PublicApiSurfaceTests.cs | 46 +- unity/NxGraphDev/Assets/Scratch.meta | 8 + unity/NxGraphDev/Assets/Scratch/.gitkeep | 0 unity/NxGraphDev/Assets/Scratch/Editor.meta | 8 + .../Scratch/Editor/SerializationSmokeTest.cs | 127 ++++ .../Editor/SerializationSmokeTest.cs.meta | 2 + .../Assets/Scratch/RuntimeUsageProbe.cs | 54 ++ .../Assets/Scratch/RuntimeUsageProbe.cs.meta | 2 + unity/NxGraphDev/Packages/manifest.json | 42 ++ unity/NxGraphDev/Packages/packages-lock.json | 316 ++++++++ .../ProjectSettings/AudioManager.asset | 23 + .../ProjectSettings/ClusterInputManager.asset | 6 + .../ProjectSettings/DynamicsManager.asset | 45 ++ .../ProjectSettings/EditorBuildSettings.asset | 8 + .../ProjectSettings/EditorSettings.asset | 52 ++ .../ProjectSettings/GraphicsSettings.asset | 68 ++ .../ProjectSettings/InputManager.asset | 296 ++++++++ .../ProjectSettings/MemorySettings.asset | 35 + .../ProjectSettings/MultiplayerManager.asset | 9 + .../ProjectSettings/NavMeshAreas.asset | 93 +++ .../PackageManagerSettings.asset | 42 ++ .../ProjectSettings/Physics2DSettings.asset | 57 ++ .../ProjectSettings/PresetManager.asset | 7 + .../ProjectSettings/ProjectSettings.asset | 694 ++++++++++++++++++ .../ProjectSettings/ProjectVersion.txt | 2 + .../ProjectSettings/QualitySettings.asset | 347 +++++++++ .../SceneTemplateSettings.json | 121 +++ .../ProjectSettings/TagManager.asset | 46 ++ .../ProjectSettings/TimeManager.asset | 14 + .../UnityConnectSettings.asset | 40 + .../ProjectSettings/VFXManager.asset | 20 + .../VersionControlSettings.asset | 7 + unity/README.md | 55 ++ .../CHANGELOG.md | 12 + .../CHANGELOG.md.meta | 7 + .../Documentation~/index.md | 37 + upm/com.enzx.nxgraph.serialization/LICENSE.md | 22 + .../LICENSE.md.meta | 7 + upm/com.enzx.nxgraph.serialization/README.md | 41 ++ .../README.md.meta | 7 + .../Runtime.meta | 8 + .../Runtime/Plugins.meta | 8 + .../Runtime/Plugins/.gitkeep | 0 .../Plugins/MessagePack.Annotations.dll.meta | 2 + .../Runtime/Plugins/MessagePack.dll.meta | 2 + .../Microsoft.Bcl.AsyncInterfaces.dll.meta | 2 + .../Microsoft.NET.StringTools.dll.meta | 2 + .../Plugins/NxGraph.Serialization.dll.meta | 2 + .../Plugins/NxGraph.Serialization.pdb.meta | 7 + .../Plugins/NxGraph.Serialization.xml.meta | 7 + .../Runtime/Plugins/System.Buffers.dll.meta | 2 + .../System.Collections.Immutable.dll.meta | 2 + .../Runtime/Plugins/System.Memory.dll.meta | 2 + .../Plugins/System.Numerics.Vectors.dll.meta | 2 + ...m.Runtime.CompilerServices.Unsafe.dll.meta | 2 + .../System.Text.Encodings.Web.dll.meta | 2 + .../Runtime/Plugins/System.Text.Json.dll.meta | 2 + ...System.Threading.Tasks.Extensions.dll.meta | 2 + .../package.json | 27 + .../package.json.meta | 7 + .../Documentation~/build-and-release.md | 29 +- ...NxGraph.Serialization.Abstraction.dll.meta | 2 + ...NxGraph.Serialization.Abstraction.pdb.meta | 7 + ...NxGraph.Serialization.Abstraction.xml.meta | 7 + .../Runtime/Plugins/NxGraph.xml.meta | 7 + 87 files changed, 3713 insertions(+), 117 deletions(-) create mode 100644 NxGraph.Serialization.Abstraction/Shims/ArgumentNullExceptionShim.cs create mode 100644 NxGraph.Serialization.Abstraction/Shims/CallerArgumentExpressionAttribute.cs create mode 100644 NxGraph.Serialization.Abstraction/Shims/IsExternalInit.cs create mode 100644 NxGraph.Serialization/Compat.cs create mode 100644 NxGraph.Serialization/Shims/ArgumentNullExceptionShim.cs create mode 100644 NxGraph.Serialization/Shims/IsExternalInit.cs create mode 100644 NxGraph.Tests/PublicApi/NxGraph.Serialization.Abstraction.netstandard2.1.approved.txt create mode 100644 NxGraph.Tests/PublicApi/NxGraph.Serialization.netstandard2.1.approved.txt create mode 100644 unity/NxGraphDev/Assets/Scratch.meta create mode 100644 unity/NxGraphDev/Assets/Scratch/.gitkeep create mode 100644 unity/NxGraphDev/Assets/Scratch/Editor.meta create mode 100644 unity/NxGraphDev/Assets/Scratch/Editor/SerializationSmokeTest.cs create mode 100644 unity/NxGraphDev/Assets/Scratch/Editor/SerializationSmokeTest.cs.meta create mode 100644 unity/NxGraphDev/Assets/Scratch/RuntimeUsageProbe.cs create mode 100644 unity/NxGraphDev/Assets/Scratch/RuntimeUsageProbe.cs.meta create mode 100644 unity/NxGraphDev/Packages/manifest.json create mode 100644 unity/NxGraphDev/Packages/packages-lock.json create mode 100644 unity/NxGraphDev/ProjectSettings/AudioManager.asset create mode 100644 unity/NxGraphDev/ProjectSettings/ClusterInputManager.asset create mode 100644 unity/NxGraphDev/ProjectSettings/DynamicsManager.asset create mode 100644 unity/NxGraphDev/ProjectSettings/EditorBuildSettings.asset create mode 100644 unity/NxGraphDev/ProjectSettings/EditorSettings.asset create mode 100644 unity/NxGraphDev/ProjectSettings/GraphicsSettings.asset create mode 100644 unity/NxGraphDev/ProjectSettings/InputManager.asset create mode 100644 unity/NxGraphDev/ProjectSettings/MemorySettings.asset create mode 100644 unity/NxGraphDev/ProjectSettings/MultiplayerManager.asset create mode 100644 unity/NxGraphDev/ProjectSettings/NavMeshAreas.asset create mode 100644 unity/NxGraphDev/ProjectSettings/PackageManagerSettings.asset create mode 100644 unity/NxGraphDev/ProjectSettings/Physics2DSettings.asset create mode 100644 unity/NxGraphDev/ProjectSettings/PresetManager.asset create mode 100644 unity/NxGraphDev/ProjectSettings/ProjectSettings.asset create mode 100644 unity/NxGraphDev/ProjectSettings/ProjectVersion.txt create mode 100644 unity/NxGraphDev/ProjectSettings/QualitySettings.asset create mode 100644 unity/NxGraphDev/ProjectSettings/SceneTemplateSettings.json create mode 100644 unity/NxGraphDev/ProjectSettings/TagManager.asset create mode 100644 unity/NxGraphDev/ProjectSettings/TimeManager.asset create mode 100644 unity/NxGraphDev/ProjectSettings/UnityConnectSettings.asset create mode 100644 unity/NxGraphDev/ProjectSettings/VFXManager.asset create mode 100644 unity/NxGraphDev/ProjectSettings/VersionControlSettings.asset create mode 100644 unity/README.md create mode 100644 upm/com.enzx.nxgraph.serialization/CHANGELOG.md create mode 100644 upm/com.enzx.nxgraph.serialization/CHANGELOG.md.meta create mode 100644 upm/com.enzx.nxgraph.serialization/Documentation~/index.md create mode 100644 upm/com.enzx.nxgraph.serialization/LICENSE.md create mode 100644 upm/com.enzx.nxgraph.serialization/LICENSE.md.meta create mode 100644 upm/com.enzx.nxgraph.serialization/README.md create mode 100644 upm/com.enzx.nxgraph.serialization/README.md.meta create mode 100644 upm/com.enzx.nxgraph.serialization/Runtime.meta create mode 100644 upm/com.enzx.nxgraph.serialization/Runtime/Plugins.meta create mode 100644 upm/com.enzx.nxgraph.serialization/Runtime/Plugins/.gitkeep create mode 100644 upm/com.enzx.nxgraph.serialization/Runtime/Plugins/MessagePack.Annotations.dll.meta create mode 100644 upm/com.enzx.nxgraph.serialization/Runtime/Plugins/MessagePack.dll.meta create mode 100644 upm/com.enzx.nxgraph.serialization/Runtime/Plugins/Microsoft.Bcl.AsyncInterfaces.dll.meta create mode 100644 upm/com.enzx.nxgraph.serialization/Runtime/Plugins/Microsoft.NET.StringTools.dll.meta create mode 100644 upm/com.enzx.nxgraph.serialization/Runtime/Plugins/NxGraph.Serialization.dll.meta create mode 100644 upm/com.enzx.nxgraph.serialization/Runtime/Plugins/NxGraph.Serialization.pdb.meta create mode 100644 upm/com.enzx.nxgraph.serialization/Runtime/Plugins/NxGraph.Serialization.xml.meta create mode 100644 upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Buffers.dll.meta create mode 100644 upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Collections.Immutable.dll.meta create mode 100644 upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Memory.dll.meta create mode 100644 upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Numerics.Vectors.dll.meta create mode 100644 upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Runtime.CompilerServices.Unsafe.dll.meta create mode 100644 upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Text.Encodings.Web.dll.meta create mode 100644 upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Text.Json.dll.meta create mode 100644 upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Threading.Tasks.Extensions.dll.meta create mode 100644 upm/com.enzx.nxgraph.serialization/package.json create mode 100644 upm/com.enzx.nxgraph.serialization/package.json.meta create mode 100644 upm/com.enzx.nxgraph/Runtime/Plugins/NxGraph.Serialization.Abstraction.dll.meta create mode 100644 upm/com.enzx.nxgraph/Runtime/Plugins/NxGraph.Serialization.Abstraction.pdb.meta create mode 100644 upm/com.enzx.nxgraph/Runtime/Plugins/NxGraph.Serialization.Abstraction.xml.meta create mode 100644 upm/com.enzx.nxgraph/Runtime/Plugins/NxGraph.xml.meta diff --git a/.github/workflows/upm-build.yml b/.github/workflows/upm-build.yml index 0cfe523..1fa8ecb 100644 --- a/.github/workflows/upm-build.yml +++ b/.github/workflows/upm-build.yml @@ -27,7 +27,7 @@ jobs: with: dotnet-version: 8.0.x - - name: Stage UPM package (${{ matrix.mode }}) + - name: Stage UPM packages (${{ matrix.mode }}) run: dotnet run --project NxGraph.Build -- stage-${{ matrix.mode }} - name: Upload staged UPM package @@ -36,3 +36,13 @@ jobs: name: upm-${{ matrix.mode }} path: upm/com.enzx.nxgraph/ + # Only binary mode produces this package: a prebuilt NxGraph.Serialization.dll + # references the assembly named NxGraph and cannot bind to a source-compiled core, + # which Unity would surface as an unresolved reference. + - name: Upload staged serialization UPM package + if: matrix.mode == 'binary' + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: upm-serialization + path: upm/com.enzx.nxgraph.serialization/ + diff --git a/.github/workflows/upm-release.yml b/.github/workflows/upm-release.yml index 404aaeb..b8c8d33 100644 --- a/.github/workflows/upm-release.yml +++ b/.github/workflows/upm-release.yml @@ -60,6 +60,21 @@ jobs: fi echo "version=$VER" >> "$GITHUB_OUTPUT" echo "mode=$MODE" >> "$GITHUB_OUTPUT" + + # Only binary mode ships the serialization package: a prebuilt + # NxGraph.Serialization.dll references the assembly named NxGraph and cannot bind + # to a source-compiled core, so source-mode releases publish the core alone. + if [[ "$MODE" == "binary" ]]; then + { + echo "assets<> "$GITHUB_OUTPUT" + else + echo "assets=com.enzx.nxgraph-${VER}.tgz" >> "$GITHUB_OUTPUT" + fi + echo "Resolved: version=$VER, mode=$MODE" - name: Build, test, stage, and package UPM @@ -74,41 +89,59 @@ jobs: upm-patch-version upm-tarball - - name: Push to upm branch + - name: Push package branches shell: bash run: | set -euo pipefail VER="${{ steps.meta.outputs.version }}" - - # Park the tarball outside the worktree: `git clean -fdx` below would delete it - # (it is untracked and not covered by the package-dir exclusion), and the release - # step needs it as an asset. - mv "com.enzx.nxgraph-${VER}.tgz" /tmp/ + MODE="${{ steps.meta.outputs.mode }}" + + # Park everything the release still needs outside the worktree. Publishing rewrites + # the tree to each package's layout in turn, and `git clean -fdx` deletes anything + # untracked — which covers both the tarballs and the staged binaries. + STASH=/tmp/upm-release + rm -rf "$STASH" && mkdir -p "$STASH" + mv "com.enzx.nxgraph-${VER}.tgz" "$STASH/" + cp -r upm/com.enzx.nxgraph "$STASH/core" + if [[ "$MODE" == "binary" ]]; then + mv "com.enzx.nxgraph.serialization-${VER}.tgz" "$STASH/" + cp -r upm/com.enzx.nxgraph.serialization "$STASH/serialization" + fi git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - # Create an orphan branch with just the UPM package contents - git checkout --orphan upm-staging - git rm -rf . > /dev/null 2>&1 || true - git clean -fdx -e "${UPM_PACKAGE_DIR}" > /dev/null 2>&1 || true + # Publish one package layout at the root of its own orphan branch. Each package gets + # its own branch so both stay installable by plain git URL, and so the existing + # '#upm' URL keeps meaning exactly what it meant before the split. + publish() { + local src="$1" branch="$2" - # Move UPM package contents to root - cp -r ${UPM_PACKAGE_DIR}/* . - cp -r ${UPM_PACKAGE_DIR}/.* . 2>/dev/null || true + git checkout --orphan upm-staging + git rm -rf . > /dev/null 2>&1 || true + git clean -fdx > /dev/null 2>&1 || true - # Drop the nested copy so the published branch is only the package layout. - rm -rf upm + # `/.` copies dotfiles (.gitkeep) along with everything else. + cp -r "${src}/." . - git add -A - git commit -m "Release UPM v${VER}" + git add -A + git commit -m "Release UPM v${VER}" + git push origin "upm-staging:${branch}" --force - git push origin upm-staging:upm --force + # Return to the released commit so the next publish starts from a known tree. + git checkout --force --detach "${GITHUB_SHA}" > /dev/null 2>&1 + git branch -D upm-staging > /dev/null 2>&1 || true - # Restore the tarball for the release step. - mv "/tmp/com.enzx.nxgraph-${VER}.tgz" . + echo "Pushed ${branch} @ v${VER}." + } - echo "Pushed UPM package v${VER} to 'upm' branch." + publish "$STASH/core" upm + if [[ "$MODE" == "binary" ]]; then + publish "$STASH/serialization" upm-serialization + fi + + # Restore the tarballs for the release step. + mv "$STASH"/*.tgz . - name: Create GitHub Release uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2 @@ -134,8 +167,18 @@ jobs: "com.enzx.nxgraph": "https://github.com/${{ github.repository }}.git#upm/v${{ steps.meta.outputs.version }}" ``` + ### Optional: serialization + + JSON and MessagePack payloads live in a separate package, released from the same + version and published to its own branch. It bundles its own dependencies — see its + README for the duplicate-assembly caveat. Binary-mode releases only. + + ```json + "com.enzx.nxgraph.serialization": "https://github.com/${{ github.repository }}.git#upm-serialization" + ``` + ### Install from tarball - Download the `.tgz` file below and install via Unity Package Manager → "Add package from tarball". - files: com.enzx.nxgraph-${{ steps.meta.outputs.version }}.tgz + Download a `.tgz` file below and install via Unity Package Manager → "Add package from tarball". + files: ${{ steps.meta.outputs.assets }} draft: false prerelease: ${{ contains(steps.meta.outputs.version, '-') }} diff --git a/.gitignore b/.gitignore index f1bb99f..fff41e5 100644 --- a/.gitignore +++ b/.gitignore @@ -12,8 +12,31 @@ TestResults/ coverage.info coverage.json /BenchmarkDotNet.Artifacts/ -upm/com.enzx.nxgraph/Runtime/**/*.dll -upm/com.enzx.nxgraph/Runtime/**/*.pdb -upm/com.enzx.nxgraph/Runtime/**/*.xml +# Staged UPM binaries: produced on demand by `NxGraph.Build -- stage-binary`, never +# committed. The `.meta` sidecars beside them ARE committed — they carry the plugin GUIDs +# and define which assemblies staging is allowed to write. +upm/*/Runtime/**/*.dll +upm/*/Runtime/**/*.pdb +upm/*/Runtime/**/*.xml +# Staged UPM sources: `stage-source` copies the core library here. The folder is a staging +# artifact and only exists in source mode, so Unity's generated .meta for it goes too. +upm/com.enzx.nxgraph/Runtime/NxGraph/ +upm/com.enzx.nxgraph/Runtime/NxGraph.meta *.log *.tgz + +# Unity development project. Everything here is regenerated from the packages and the +# assets that are tracked; Unity rewrites the C# projects on every import, so they must +# not sit next to NxGraph.sln in source control. +unity/*/Library/ +unity/*/Temp/ +unity/*/Obj/ +unity/*/Build/ +unity/*/Builds/ +unity/*/Logs/ +unity/*/UserSettings/ +unity/*/MemoryCaptures/ +unity/*/Recordings/ +unity/*/*.csproj +unity/*/*.sln +unity/*/*.user diff --git a/Directory.Build.props b/Directory.Build.props index a330c22..48dd6ec 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -3,12 +3,20 @@ these. Per-project files keep only what genuinely differs: TargetFramework(s), package Title/Description/Tags/readme, and IsPackable/IsTestProject flags. - TFM decision (recorded): TargetFrameworks stay per-project. The core library - multi-targets net8.0 + netstandard2.1 because the Unity (UPM) package stages the - netstandard2.1 build of NxGraph.dll; the serialization packages stay net8.0-only — - no netstandard2.1 consumer story exists for them (the UPM package ships only the - core), so widening them would cost polyfills for nothing. Revisit only if a - netstandard consumer of the serialization surface appears. --> + TFM decision (recorded, superseding the earlier net8.0-only serialization rule): + TargetFrameworks stay per-project, and all three shipped libraries — NxGraph, + NxGraph.Serialization.Abstraction, NxGraph.Serialization — multi-target + net8.0 + netstandard2.1. The netstandard2.1 leg exists for Unity: the core package + (com.enzx.nxgraph) stages NxGraph.dll and the abstraction, and the serialization + package (com.enzx.nxgraph.serialization) stages NxGraph.Serialization.dll together + with its dependencies. The netstandard2.1 consumer the previous note was waiting for + is the Unity graph editor, which loads and saves graph payloads in-editor. + + Cost of the widening, so it is not re-litigated: three small shim files per + serialization assembly (init-only marker, caller-argument attribute, argument-null + guard), an explicit System.Text.Json reference on the netstandard2.1 leg only, and + the Compat.cs helpers for the text-IO overloads netstandard2.1 lacks. No public + surface differs between the two TFMs. --> diff --git a/NxGraph.Build/BuildHelpers.cs b/NxGraph.Build/BuildHelpers.cs index 9134a02..baaac96 100644 --- a/NxGraph.Build/BuildHelpers.cs +++ b/NxGraph.Build/BuildHelpers.cs @@ -68,8 +68,17 @@ public static string FindRepoRoot() public static string SourceRoot(string repoRoot) => Path.Combine(repoRoot, "NxGraph"); + /// Directory name of the core UPM package. + public const string CorePackageDir = "com.enzx.nxgraph"; + + /// Directory name of the optional serialization UPM package. + public const string SerializationPackageDir = "com.enzx.nxgraph.serialization"; + public static string PackageRoot(string repoRoot) => - Path.Combine(repoRoot, "upm", "com.enzx.nxgraph"); + Path.Combine(repoRoot, "upm", CorePackageDir); + + public static string SerializationPackageRoot(string repoRoot) => + Path.Combine(repoRoot, "upm", SerializationPackageDir); public static string StagedSourceRoot(string repoRoot) => Path.Combine(PackageRoot(repoRoot), "Runtime", "NxGraph"); @@ -77,18 +86,41 @@ public static string StagedSourceRoot(string repoRoot) => public static string PluginsRoot(string repoRoot) => Path.Combine(PackageRoot(repoRoot), "Runtime", "Plugins"); + public static string SerializationPluginsRoot(string repoRoot) => + Path.Combine(SerializationPackageRoot(repoRoot), "Runtime", "Plugins"); + public static string BuildOutput(string repoRoot) => Path.Combine(repoRoot, "NxGraph", "bin", "Release", "netstandard2.1"); + /// + /// The serialization project's netstandard2.1 output. Because that project sets + /// CopyLocalLockFileAssemblies on this TFM, the directory holds the whole + /// dependency closure — which is exactly what the Unity package bundles. + /// + public static string SerializationBuildOutput(string repoRoot) => + Path.Combine(repoRoot, "NxGraph.Serialization", "bin", "Release", "netstandard2.1"); + public static string ArtifactsDir(string repoRoot) => Path.Combine(repoRoot, OptionalEnv("ARTIFACTS_DIR") ?? "artifacts"); + /// + /// The core package's package.json. UPM_PACKAGE_DIR still overrides it, which is how + /// the release workflow points at a relocated layout. + /// public static string PackageJsonPath(string repoRoot) { - var upmDir = OptionalEnv("UPM_PACKAGE_DIR") ?? Path.Combine("upm", "com.enzx.nxgraph"); + var upmDir = OptionalEnv("UPM_PACKAGE_DIR") ?? Path.Combine("upm", CorePackageDir); return Path.Combine(repoRoot, upmDir, "package.json"); } + /// + /// The serialization package's package.json. Deliberately not overridable by + /// UPM_PACKAGE_DIR — that variable names one directory, and the two packages are + /// versioned and released together. + /// + public static string SerializationPackageJsonPath(string repoRoot) => + Path.Combine(SerializationPackageRoot(repoRoot), "package.json"); + // ── Pack helper (replaces the 3× duplicated dotnet pack blocks) ─── public static IReadOnlyList PackArgs( @@ -137,7 +169,13 @@ public static IReadOnlyList PackArgs( // ── package.json version patching ────────────────────────────────── - public static void PatchPackageJsonVersion(string packageJsonPath, string version) + /// + /// When set, the named entry under dependencies is pinned to the same version. The + /// two UPM packages ship as a unit, so the serialization package always depends on the + /// exact core version released alongside it. + /// + public static void PatchPackageJsonVersion(string packageJsonPath, string version, + string? pinDependency = null) { if (!File.Exists(packageJsonPath)) throw new FileNotFoundException($"package.json not found at {packageJsonPath}"); @@ -148,25 +186,44 @@ public static void PatchPackageJsonVersion(string packageJsonPath, string versio node["version"] = version; + if (pinDependency is not null) + { + if (node["dependencies"] is not JsonObject dependencies) + throw new InvalidOperationException( + $"{packageJsonPath} has no 'dependencies' object to pin '{pinDependency}' in."); + + if (!dependencies.ContainsKey(pinDependency)) + throw new InvalidOperationException( + $"{packageJsonPath} declares no dependency on '{pinDependency}'."); + + dependencies[pinDependency] = version; + Console.WriteLine($"Pinned dependency {pinDependency} to {version}"); + } + var options = new JsonSerializerOptions { WriteIndented = true }; File.WriteAllText(packageJsonPath, node.ToJsonString(options) + Environment.NewLine); - Console.WriteLine($"Updated package.json version to {version}"); + Console.WriteLine($"Updated {Path.GetFileName(Path.GetDirectoryName(packageJsonPath))} version to {version}"); } // ── Tarball creation ─────────────────────────────────────────────── public static string CreateTarball(string repoRoot, string version) { - var upmRelDir = OptionalEnv("UPM_PACKAGE_DIR") ?? Path.Combine("upm", "com.enzx.nxgraph"); - var upmAbsDir = Path.Combine(repoRoot, upmRelDir); - var tarballName = $"com.enzx.nxgraph-{version}.tgz"; + var upmRelDir = OptionalEnv("UPM_PACKAGE_DIR") ?? Path.Combine("upm", CorePackageDir); + return CreateTarball(repoRoot, version, Path.Combine(repoRoot, upmRelDir), CorePackageDir); + } + + /// Tarballs one package directory as {packageName}-{version}.tgz. + public static string CreateTarball(string repoRoot, string version, string upmAbsDir, string packageName) + { + var tarballName = $"{packageName}-{version}.tgz"; var tarballPath = Path.Combine(repoRoot, tarballName); if (!Directory.Exists(upmAbsDir)) throw new DirectoryNotFoundException($"UPM package directory not found: {upmAbsDir}"); - // We need to create a .tar.gz with entries rooted at "com.enzx.nxgraph/" + // We need to create a .tar.gz with entries rooted at "{packageName}/" using var fileStream = File.Create(tarballPath); using var gzipStream = new GZipStream(fileStream, CompressionLevel.Optimal); TarFile.CreateFromDirectory( @@ -213,18 +270,48 @@ public static void ClearStagedSource(string repoRoot) } } - public static void ClearStagedPlugins(string repoRoot) + public static void ClearStagedPlugins(string repoRoot) => ClearPlugins(PluginsRoot(repoRoot)); + + /// + /// Removes staged binaries from a Plugins folder while preserving the tracked sidecars. + /// + /// The .meta files must survive: they carry the plugin GUIDs Unity uses as reference + /// identity, they are committed (the binaries themselves are gitignored and staged on + /// demand), and regenerating them would hand every consumer project a new GUID for the same + /// assembly. They double as the reviewed allowlist of what may be staged — see + /// . + /// + /// + public static void ClearPlugins(string pluginsDir) { - var dir = PluginsRoot(repoRoot); - Directory.CreateDirectory(dir); + Directory.CreateDirectory(pluginsDir); - foreach (var file in Directory.GetFiles(dir)) + foreach (var file in Directory.GetFiles(pluginsDir)) { - if (Path.GetFileName(file) == ".gitkeep") continue; + var name = Path.GetFileName(file); + if (name == ".gitkeep" || name.EndsWith(".meta", StringComparison.OrdinalIgnoreCase)) + continue; + File.Delete(file); } } + /// + /// The file names a Plugins folder is allowed to contain, derived from the committed + /// .meta sidecars. Staging compares against this so that a new transitive dependency + /// can neither be silently bundled (unreviewed binary in a shipped package) nor silently + /// dropped (a TypeLoadException at the consumer) — it fails the build until someone adds + /// the matching .meta. + /// + public static HashSet StagedPluginNames(string pluginsDir) + { + Directory.CreateDirectory(pluginsDir); + + return Directory.GetFiles(pluginsDir, "*.meta") + .Select(f => Path.GetFileNameWithoutExtension(f)!) + .ToHashSet(StringComparer.OrdinalIgnoreCase); + } + // ── Target resolution (tag-based) ────────────────────────────────── public static (string target, string version) ResolvePublishTarget() diff --git a/NxGraph.Build/Program.cs b/NxGraph.Build/Program.cs index 9f20c05..6038251 100644 --- a/NxGraph.Build/Program.cs +++ b/NxGraph.Build/Program.cs @@ -1,4 +1,5 @@ -using static Bullseye.Targets; +using System.Text; +using static Bullseye.Targets; using static SimpleExec.Command; using static NxGraph.Build.BuildHelpers; @@ -44,6 +45,18 @@ public static class Program Path.Combine("Fsm", "TracingObserver.cs"), ]; + // Assemblies the core package owns. They are present in the serialization project's + // netstandard2.1 output too (it references them), and staging them into both packages + // would give Unity two copies of the same types. + private static readonly string[] CoreAssemblies = + [ + "NxGraph", + "NxGraph.Serialization.Abstraction", + ]; + + // Sidecars worth shipping next to a staged assembly, in staging order. + private static readonly string[] AssemblySidecars = [".dll", ".pdb", ".xml"]; + public static async Task Main(string[] args) { var repoRoot = FindRepoRoot(); @@ -217,15 +230,36 @@ await RunDotNet(repoRoot, PushArgs("*.snupkg", apiKey), { var version = OptionalEnv("VERSION"); version = ValidateSemVer(version); - var path = PackageJsonPath(repoRoot); - PatchPackageJsonVersion(path, version); + + PatchPackageJsonVersion(PackageJsonPath(repoRoot), version); + + // The serialization package rides the same version and pins the core it was built + // against — the two are staged from one build and are not independently versioned. + PatchPackageJsonVersion(SerializationPackageJsonPath(repoRoot), version, + pinDependency: CorePackageDir); }); Target("upm-tarball", DependsOn("upm-patch-version"), () => { var version = OptionalEnv("VERSION"); version = ValidateSemVer(version); + CreateTarball(repoRoot, version); + + // Source mode leaves the serialization package unstaged (see StageSource); there is + // nothing to ship, so no second tarball is produced. + if (Directory.GetFiles(SerializationPluginsRoot(repoRoot), "*.dll").Length > 0) + { + CreateTarball(repoRoot, version, SerializationPackageRoot(repoRoot), SerializationPackageDir); + } + else + { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine( + $"Skipping {SerializationPackageDir} tarball: no staged assemblies " + + "(expected when staging in source mode)."); + Console.ResetColor(); + } }); await RunTargetsAndExitAsync(args); @@ -413,6 +447,13 @@ private static void StageSource(string repoRoot) ClearStagedSource(repoRoot); ClearStagedPlugins(repoRoot); + // Source mode compiles the core into the package's own asmdef, so the resulting Unity + // assembly is named NxGraph.Unity.Runtime — not NxGraph. A prebuilt + // NxGraph.Serialization.dll carries an assembly reference to "NxGraph" and cannot bind + // to it, so the serialization package is only ever staged in binary mode. Clearing it + // here keeps the two package layouts consistent with each other. + ClearPlugins(SerializationPluginsRoot(repoRoot)); + // Copy directories foreach (var relDir in DirectoriesToCopy) { @@ -452,6 +493,12 @@ private static void StageSource(string repoRoot) Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("Unity package source staged successfully."); Console.ResetColor(); + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine( + $"Note: {SerializationPackageDir} is not staged in source mode — a prebuilt " + + "NxGraph.Serialization.dll cannot bind to a source-compiled core. Use stage-binary " + + "to produce both packages."); + Console.ResetColor(); foreach (var file in Directory.GetFiles(stagedRoot, "*", SearchOption.AllDirectories)) { @@ -461,47 +508,133 @@ private static void StageSource(string repoRoot) private static async Task StageBinary(string repoRoot) { - var projectPath = Path.Combine(repoRoot, "NxGraph", "NxGraph.csproj"); + // Building the serialization project also builds the core it references, and its + // netstandard2.1 output carries the full dependency closure + // (CopyLocalLockFileAssemblies) that the serialization package bundles. + var serializationProject = Path.Combine(repoRoot, "NxGraph.Serialization", "NxGraph.Serialization.csproj"); Console.ForegroundColor = ConsoleColor.Cyan; - Console.WriteLine("Building NxGraph binary for Unity package staging..."); + Console.WriteLine("Building netstandard2.1 binaries for Unity package staging..."); Console.ResetColor(); - Console.WriteLine($"Project: {projectPath}"); - Console.WriteLine($"Package: {PackageRoot(repoRoot)}"); + Console.WriteLine($"Project: {serializationProject}"); + Console.WriteLine($"Packages: {PackageRoot(repoRoot)}"); + Console.WriteLine($" {SerializationPackageRoot(repoRoot)}"); - if (!File.Exists(projectPath)) - throw new InvalidOperationException($"Project not found: {projectPath}"); + if (!File.Exists(serializationProject)) + throw new InvalidOperationException($"Project not found: {serializationProject}"); ClearStagedSource(repoRoot); ClearStagedPlugins(repoRoot); + ClearPlugins(SerializationPluginsRoot(repoRoot)); - await RunDotNet(repoRoot, $"build \"{projectPath}\" -c Release -f netstandard2.1"); - - // Copy outputs - var buildDir = BuildOutput(repoRoot); - var pluginsDir = PluginsRoot(repoRoot); + await RunDotNet(repoRoot, $"build \"{serializationProject}\" -c Release -f netstandard2.1"); - var dllPath = Path.Combine(buildDir, "NxGraph.dll"); - if (!File.Exists(dllPath)) - throw new InvalidOperationException($"Build completed but NxGraph.dll was not found at {dllPath}"); + var serializationBuildDir = SerializationBuildOutput(repoRoot); - File.Copy(dllPath, Path.Combine(pluginsDir, "NxGraph.dll"), overwrite: true); + // The core package takes NxGraph plus the dependency-free serialization abstraction; + // both come out of the same build directory. + StagePlugins(repoRoot, serializationBuildDir, PluginsRoot(repoRoot), CorePackageDir, + name => CoreAssemblies.Contains(name, StringComparer.OrdinalIgnoreCase)); - var pdbPath = Path.Combine(buildDir, "NxGraph.pdb"); - if (File.Exists(pdbPath)) - File.Copy(pdbPath, Path.Combine(pluginsDir, "NxGraph.pdb"), overwrite: true); - - var xmlPath = Path.Combine(buildDir, "NxGraph.xml"); - if (File.Exists(xmlPath)) - File.Copy(xmlPath, Path.Combine(pluginsDir, "NxGraph.xml"), overwrite: true); + // The serialization package takes everything else: the serializer itself and its + // bundled third-party dependencies. + StagePlugins(repoRoot, serializationBuildDir, SerializationPluginsRoot(repoRoot), + SerializationPackageDir, + name => !CoreAssemblies.Contains(name, StringComparer.OrdinalIgnoreCase)); Console.WriteLine(); Console.ForegroundColor = ConsoleColor.Green; - Console.WriteLine("Binary staged successfully."); + Console.WriteLine("Binaries staged successfully."); Console.ResetColor(); + } + + /// + /// Copies the assemblies selected by from a build directory into + /// a package's Plugins folder, and reconciles the result against the committed + /// .meta sidecars: an assembly with no sidecar, or a sidecar with no assembly, fails + /// the target. That keeps a shipped package's binary contents a reviewed, tracked decision + /// rather than whatever NuGet happened to resolve. + /// + private static void StagePlugins(string repoRoot, string buildDir, string pluginsDir, + string packageName, Func include) + { + if (!Directory.Exists(buildDir)) + throw new InvalidOperationException($"Build output not found: {buildDir}"); - foreach (var file in Directory.GetFiles(pluginsDir)) + var expected = StagedPluginNames(pluginsDir); + var staged = new List(); + + foreach (var dll in Directory.GetFiles(buildDir, "*.dll").Order(StringComparer.Ordinal)) { + var assemblyName = Path.GetFileNameWithoutExtension(dll); + if (!include(assemblyName)) + continue; + + foreach (var extension in AssemblySidecars) + { + var source = Path.Combine(buildDir, assemblyName + extension); + if (!File.Exists(source)) + continue; + + var fileName = assemblyName + extension; + + // Only files with a committed .meta are staged; the reconciliation below turns + // anything missing into an actionable error rather than a silent omission. + if (!expected.Contains(fileName)) + { + if (extension == ".dll") + staged.Add(fileName); + + continue; + } + + File.Copy(source, Path.Combine(pluginsDir, fileName), overwrite: true); + if (extension == ".dll") + staged.Add(fileName); + } + } + + var unexpected = staged.Where(f => !expected.Contains(f)).Order(StringComparer.Ordinal).ToList(); + var missing = expected + .Where(f => f.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) + .Where(f => !staged.Contains(f, StringComparer.OrdinalIgnoreCase)) + .Order(StringComparer.Ordinal) + .ToList(); + + if (unexpected.Count > 0 || missing.Count > 0) + { + var message = new StringBuilder(); + message.Append("The staged assemblies for ").Append(packageName) + .AppendLine(" do not match the package's committed .meta sidecars."); + + if (unexpected.Count > 0) + { + message.AppendLine().AppendLine( + "Built but not allowed (a dependency was added — review it, then commit a " + + ".meta with a fresh GUID for each):"); + foreach (var file in unexpected) + message.Append(" + ").AppendLine(file); + } + + if (missing.Count > 0) + { + message.AppendLine().AppendLine( + "Allowed but not built (a dependency was dropped — delete the stale .meta):"); + foreach (var file in missing) + message.Append(" - ").AppendLine(file); + } + + message.AppendLine().Append("Plugins folder: ").Append(pluginsDir); + throw new InvalidOperationException(message.ToString()); + } + + Console.WriteLine(); + Console.WriteLine($"{packageName}:"); + foreach (var file in Directory.GetFiles(pluginsDir).Order(StringComparer.Ordinal)) + { + if (Path.GetExtension(file).Equals(".meta", StringComparison.OrdinalIgnoreCase)) + continue; + var info = new FileInfo(file); Console.WriteLine($" {info.Name} ({info.Length:N0} bytes)"); } @@ -510,7 +643,6 @@ private static async Task StageBinary(string repoRoot) private static void CleanStaged(string repoRoot) { var stagedRoot = StagedSourceRoot(repoRoot); - var pluginsDir = PluginsRoot(repoRoot); if (Directory.Exists(stagedRoot)) { @@ -526,18 +658,21 @@ private static void CleanStaged(string repoRoot) Console.ResetColor(); } - if (Directory.Exists(pluginsDir)) + foreach (var pluginsDir in new[] { PluginsRoot(repoRoot), SerializationPluginsRoot(repoRoot) }) { - ClearStagedPlugins(repoRoot); - Console.ForegroundColor = ConsoleColor.Green; - Console.WriteLine($"Cleaned staged Unity package binaries in {pluginsDir}"); - Console.ResetColor(); - } - else - { - Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine($"Nothing to clean: {pluginsDir} does not exist."); - Console.ResetColor(); + if (Directory.Exists(pluginsDir)) + { + ClearPlugins(pluginsDir); + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine($"Cleaned staged Unity package binaries in {pluginsDir}"); + Console.ResetColor(); + } + else + { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine($"Nothing to clean: {pluginsDir} does not exist."); + Console.ResetColor(); + } } } } diff --git a/NxGraph.Build/README.md b/NxGraph.Build/README.md index 723f659..b3ff45d 100644 --- a/NxGraph.Build/README.md +++ b/NxGraph.Build/README.md @@ -25,7 +25,7 @@ Bullseye supports passing **multiple targets** in a single invocation. Shared de | Target | Depends on | Description | |---|---|---| | `info` | — | Diagnostic preflight: print repo root, resolved `dotnet` (and why), candidates, `dotnet --info` | -| `clean` | — | Remove all staged UPM files (source & binary) | +| `clean` | — | Remove staged UPM files (source & binary) from both packages | | `restore` | — | `dotnet restore` the solution | | `build` | `restore` | `dotnet build` the solution | | `test` | `build` | `dotnet test` with code coverage + threshold gate (see [Coverage](#coverage)) | @@ -33,10 +33,10 @@ Bullseye supports passing **multiple targets** in a single invocation. Shared de | `pack` | `build` | Pack one or more NuGet packages | | `push` | `pack` | Push `.nupkg` + `.snupkg` to nuget.org (API key never echoed — see below) | | **`publish`** | `ci`, `push` | **Full release pipeline** (ci + pack + push) | -| `stage-source` | — | Copy NxGraph source files into the UPM package | -| `stage-binary` | — | Build NxGraph DLL and copy into the UPM package | -| `upm-patch-version` | — | Patch `version` field in UPM `package.json` | -| `upm-tarball` | `upm-patch-version` | Create a `.tgz` archive of the UPM package | +| `stage-source` | — | Copy NxGraph source files into the core UPM package (the serialization package is binary-only and is cleared) | +| `stage-binary` | — | Build the netstandard2.1 assemblies and distribute them across both UPM packages | +| `upm-patch-version` | — | Patch `version` in both UPM `package.json` files, pinning the serialization package's dependency on the core | +| `upm-tarball` | `upm-patch-version` | Create a `.tgz` archive per staged UPM package | ### Dependency tree @@ -155,11 +155,19 @@ Bullseye runs all four targets (and their transitive dependencies) in a single p This is what the `upm-release.yml` workflow runs — the remaining git-push and GitHub Release steps stay in YAML because they need authenticated git operations. -**UPM release checklist:** the committed `upm/com.enzx.nxgraph/package.json` carries the -**last released** version by policy (CI's `upm-patch-version` stamps the same value at -release time). When cutting a UPM release, bump the manifest `version`, the CHANGELOG top -entry, and the package README's install pin to the new version in the release-prep commit — -three artifacts, one version. +**UPM release checklist:** both committed `package.json` files carry the **last released** +version by policy (CI's `upm-patch-version` stamps the same value at release time, and pins +the serialization package's `com.enzx.nxgraph` dependency to it). When cutting a UPM release, +bump both manifest `version` fields, the serialization manifest's dependency pin, both +CHANGELOG top entries, and the core package README's install pin — one version everywhere. + +**Staged plugin allowlist:** `stage-binary` copies only assemblies that already have a +committed `.meta` sidecar in the target `Runtime/Plugins` folder, and fails when the built +set and the sidecar set disagree in either direction. The sidecars are the reviewed record of +what each package ships (the binaries themselves are gitignored), and they hold the plugin +GUIDs Unity treats as reference identity — which is why staging preserves them rather than +clearing the folder wholesale. If a transitive dependency appears or disappears, the target +fails with the file names; review the change, then add or delete sidecars. ### Clean staged UPM files @@ -196,7 +204,7 @@ sensible defaults for local development. | `REPO_URL` | `pack` | _(optional)_ | Repository URL embedded in NuGet package (SourceLink) | | `REPO_BRANCH` | `pack` | _(optional)_ | Branch name embedded in NuGet package | | `REPO_COMMIT` | `pack` | _(optional)_ | Commit SHA embedded in NuGet package | -| `UPM_PACKAGE_DIR` | `upm-patch-version`, `upm-tarball` | `upm/com.enzx.nxgraph` | Relative path to the UPM package directory | +| `UPM_PACKAGE_DIR` | `upm-patch-version`, `upm-tarball` | `upm/com.enzx.nxgraph` | Relative path to the **core** UPM package directory. The serialization package is not relocatable — it is versioned and released with the core. | In CI, these are set automatically by the GitHub Actions workflows. For local use, only `TARGET` and `VERSION` are needed for pack/UPM commands; everything else has defaults. @@ -208,7 +216,7 @@ In CI, these are set automatically by the GitHub Actions workflows. For local us | **`dotnet.yml`** | checkout, setup .NET, upload coverage artifact | `ci` (restore → build → test) | | **`publish-nuget.yml`** | checkout, setup .NET, preflight API key mask, validate `.nupkg` contents, upload artifact | `publish` (ci + pack + push) | | **`upm-build.yml`** | checkout, setup .NET, upload artifact | `stage-source` or `stage-binary` | -| **`upm-release.yml`** | checkout, setup .NET, resolve version, git push to `upm` branch, create GitHub Release | `ci` + `stage-{mode}` + `upm-patch-version` + `upm-tarball` | +| **`upm-release.yml`** | checkout, setup .NET, resolve version, git push to the `upm` and `upm-serialization` branches, create GitHub Release | `ci` + `stage-{mode}` + `upm-patch-version` + `upm-tarball` | The YAML files only contain what **must** stay in GitHub Actions: triggers, permissions, concurrency groups, checkout, SDK setup, secret masking, artifact upload, git push, and diff --git a/NxGraph.Serialization.Abstraction/NxGraph.Serialization.Abstraction.csproj b/NxGraph.Serialization.Abstraction/NxGraph.Serialization.Abstraction.csproj index 616d802..1b29eab 100644 --- a/NxGraph.Serialization.Abstraction/NxGraph.Serialization.Abstraction.csproj +++ b/NxGraph.Serialization.Abstraction/NxGraph.Serialization.Abstraction.csproj @@ -3,7 +3,7 @@ - net8.0 + net8.0;netstandard2.1 true + + + + + + + diff --git a/NxGraph.Serialization.Abstraction/Shims/ArgumentNullExceptionShim.cs b/NxGraph.Serialization.Abstraction/Shims/ArgumentNullExceptionShim.cs new file mode 100644 index 0000000..8a468fd --- /dev/null +++ b/NxGraph.Serialization.Abstraction/Shims/ArgumentNullExceptionShim.cs @@ -0,0 +1,30 @@ +#if NETSTANDARD2_1 +// The alias makes the netstandard2.1 build resolve the simple name +// `ArgumentNullException` to the shim below, so the ~30 `ArgumentNullException.ThrowIfNull` +// call sites across the serialization assemblies compile unchanged on both TFMs. +// Safe because these assemblies never write `new ArgumentNullException(...)`, never catch it, +// and never cref it — verified before the alias was introduced. Qualified `System.` uses are +// unaffected by a simple-name alias, which is how the shim still throws the real exception. +global using ArgumentNullException = NxGraph.Serialization.Abstraction.Shims.ArgumentNullExceptionShim; + +using System.Runtime.CompilerServices; + +namespace NxGraph.Serialization.Abstraction.Shims +{ + /// + /// netstandard2.1 stand-in for System.ArgumentNullException.ThrowIfNull (net6.0+). + /// + internal static class ArgumentNullExceptionShim + { + public static void ThrowIfNull( + object? argument, + [CallerArgumentExpression("argument")] string? paramName = null) + { + if (argument is null) + { + throw new System.ArgumentNullException(paramName); + } + } + } +} +#endif diff --git a/NxGraph.Serialization.Abstraction/Shims/CallerArgumentExpressionAttribute.cs b/NxGraph.Serialization.Abstraction/Shims/CallerArgumentExpressionAttribute.cs new file mode 100644 index 0000000..c5a5128 --- /dev/null +++ b/NxGraph.Serialization.Abstraction/Shims/CallerArgumentExpressionAttribute.cs @@ -0,0 +1,18 @@ +#if NETSTANDARD2_1 +// ReSharper disable once CheckNamespace +namespace System.Runtime.CompilerServices +{ + /// + /// Lets the argument-null shim capture the caller's expression text the way + /// ArgumentNullException.ThrowIfNull does on net8.0. Added in net5.0; absent + /// from netstandard2.1. + /// + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] + internal sealed class CallerArgumentExpressionAttribute : Attribute + { + public CallerArgumentExpressionAttribute(string parameterName) => ParameterName = parameterName; + + public string ParameterName { get; } + } +} +#endif diff --git a/NxGraph.Serialization.Abstraction/Shims/IsExternalInit.cs b/NxGraph.Serialization.Abstraction/Shims/IsExternalInit.cs new file mode 100644 index 0000000..d9530b8 --- /dev/null +++ b/NxGraph.Serialization.Abstraction/Shims/IsExternalInit.cs @@ -0,0 +1,14 @@ +#if NETSTANDARD2_1 +// ReSharper disable once CheckNamespace +namespace System.Runtime.CompilerServices +{ + /// + /// Marker the compiler requires to emit init-only setters (records, init + /// properties). Present in net5.0+; absent from netstandard2.1, so this assembly + /// carries its own copy. The core library's copy is internal and cannot be shared. + /// + internal static class IsExternalInit + { + } +} +#endif diff --git a/NxGraph.Serialization/BehaviorRegistry.cs b/NxGraph.Serialization/BehaviorRegistry.cs index 0994ec6..73616b7 100644 --- a/NxGraph.Serialization/BehaviorRegistry.cs +++ b/NxGraph.Serialization/BehaviorRegistry.cs @@ -37,7 +37,7 @@ public sealed class BehaviorRegistry : IBehaviorRegistry /// public void Register(string behaviorTypeName, Func factory) { - ArgumentException.ThrowIfNullOrEmpty(behaviorTypeName); + Guard.NotNullOrEmpty(behaviorTypeName); ArgumentNullException.ThrowIfNull(factory); if (!_factories.TryAdd(behaviorTypeName, factory)) { diff --git a/NxGraph.Serialization/BlackboardSerializer.cs b/NxGraph.Serialization/BlackboardSerializer.cs index 8c9b189..c439fd4 100644 --- a/NxGraph.Serialization/BlackboardSerializer.cs +++ b/NxGraph.Serialization/BlackboardSerializer.cs @@ -64,7 +64,9 @@ public async ValueTask ToJsonAsync(Blackboard blackboard, Stream destination, Ca BlackboardDto dto = new(entries, blackboard.Schema.Name, (int)blackboard.Schema.Scope); - await using StreamWriter writer = new(destination, new UTF8Encoding(false), leaveOpen: true); + // bufferSize is spelled out because netstandard2.1 has no (Stream, Encoding, bool) + // overload; 1024 is the value the omitted-argument overload uses on net8.0. + await using StreamWriter writer = new(destination, new UTF8Encoding(false), bufferSize: 1024, leaveOpen: true); string json = JsonSerializer.Serialize(dto, _jsonOptions); await writer.WriteAsync(json.AsMemory(), ct).ConfigureAwait(false); await writer.FlushAsync(ct).ConfigureAwait(false); diff --git a/NxGraph.Serialization/Compat.cs b/NxGraph.Serialization/Compat.cs new file mode 100644 index 0000000..d7fcaeb --- /dev/null +++ b/NxGraph.Serialization/Compat.cs @@ -0,0 +1,56 @@ +using System.Runtime.CompilerServices; + +namespace NxGraph.Serialization; + +/// +/// Argument guards whose BCL equivalents postdate netstandard2.1. Unlike the files under +/// Shims/ this compiles into both target frameworks: the call sites are shared, so the +/// helper — not the caller — carries the conditional. +/// +internal static class Guard +{ + /// + /// netstandard2.1 stand-in for ArgumentException.ThrowIfNullOrEmpty (net7.0+), + /// throwing the same two exception types for the same two cases. + /// + public static void NotNullOrEmpty( + string? value, + [CallerArgumentExpression("value")] string? paramName = null) + { +#if NET8_0_OR_GREATER + ArgumentException.ThrowIfNullOrEmpty(value, paramName); +#else + if (value is null) + { + throw new System.ArgumentNullException(paramName); + } + + if (value.Length == 0) + { + throw new ArgumentException("The value cannot be an empty string.", paramName); + } +#endif + } +} + +#if NETSTANDARD2_1 +/// +/// Cancellable text-IO overloads that net8.0 has as instance methods and netstandard2.1 does +/// not. Declared in the serializers' own namespace so the call sites bind to them without an +/// import, and compiled only for netstandard2.1 so they can never shadow the real instance +/// methods on net8.0. +/// +/// The token cannot interrupt an in-flight read or flush on this framework, so it is honored +/// at entry only — the observable difference is that a cancellation requested mid-operation +/// surfaces after it completes rather than during. +/// +/// +internal static class TextIoPolyfills +{ + public static Task FlushAsync(this StreamWriter writer, CancellationToken ct) => + ct.IsCancellationRequested ? Task.FromCanceled(ct) : writer.FlushAsync(); + + public static Task ReadToEndAsync(this StreamReader reader, CancellationToken ct) => + ct.IsCancellationRequested ? Task.FromCanceled(ct) : reader.ReadToEndAsync(); +} +#endif diff --git a/NxGraph.Serialization/ConditionRegistry.cs b/NxGraph.Serialization/ConditionRegistry.cs index 4404a0f..a405dab 100644 --- a/NxGraph.Serialization/ConditionRegistry.cs +++ b/NxGraph.Serialization/ConditionRegistry.cs @@ -34,7 +34,7 @@ public sealed class ConditionRegistry : IConditionRegistry /// public void Register(string conditionTypeName, Func factory) { - ArgumentException.ThrowIfNullOrEmpty(conditionTypeName); + Guard.NotNullOrEmpty(conditionTypeName); ArgumentNullException.ThrowIfNull(factory); if (!_factories.TryAdd(conditionTypeName, factory)) { diff --git a/NxGraph.Serialization/GraphSerializer.cs b/NxGraph.Serialization/GraphSerializer.cs index 2733c72..ea0c51c 100644 --- a/NxGraph.Serialization/GraphSerializer.cs +++ b/NxGraph.Serialization/GraphSerializer.cs @@ -122,7 +122,9 @@ public async ValueTask ToJsonAsync(Graph graph, Stream destination, Cancellation GraphDto dto = ToDto(graph); - await using StreamWriter writer = new(destination, new UTF8Encoding(false), leaveOpen: true); + // bufferSize is spelled out because netstandard2.1 has no (Stream, Encoding, bool) + // overload; 1024 is the value the omitted-argument overload uses on net8.0. + await using StreamWriter writer = new(destination, new UTF8Encoding(false), bufferSize: 1024, leaveOpen: true); string json = JsonSerializer.Serialize(dto, _jsonOptions); await writer.WriteAsync(json.AsMemory(), ct).ConfigureAwait(false); diff --git a/NxGraph.Serialization/NxGraph.Serialization.csproj b/NxGraph.Serialization/NxGraph.Serialization.csproj index daa58d6..8f3995a 100644 --- a/NxGraph.Serialization/NxGraph.Serialization.csproj +++ b/NxGraph.Serialization/NxGraph.Serialization.csproj @@ -3,7 +3,7 @@ - net8.0 + net8.0;netstandard2.1 true @@ -19,6 +19,30 @@ + + + + + + + + true + + + + + + + + + + diff --git a/NxGraph.Serialization/RegionSelectorRegistry.cs b/NxGraph.Serialization/RegionSelectorRegistry.cs index 1d1c12c..e3df3a1 100644 --- a/NxGraph.Serialization/RegionSelectorRegistry.cs +++ b/NxGraph.Serialization/RegionSelectorRegistry.cs @@ -27,7 +27,7 @@ public sealed class RegionSelectorRegistry : IRegionSelectorRegistry /// public Func Register(string key, Func selector) { - ArgumentException.ThrowIfNullOrEmpty(key); + Guard.NotNullOrEmpty(key); ArgumentNullException.ThrowIfNull(selector); if (_byKey.ContainsKey(key)) { diff --git a/NxGraph.Serialization/Shims/ArgumentNullExceptionShim.cs b/NxGraph.Serialization/Shims/ArgumentNullExceptionShim.cs new file mode 100644 index 0000000..081e736 --- /dev/null +++ b/NxGraph.Serialization/Shims/ArgumentNullExceptionShim.cs @@ -0,0 +1,29 @@ +#if NETSTANDARD2_1 +// See the sibling file in NxGraph.Serialization.Abstraction for why this alias is safe. +global using ArgumentNullException = NxGraph.Serialization.Shims.ArgumentNullExceptionShim; + +// CallerArgumentExpressionAttribute is deliberately NOT redefined here: the Abstraction +// assembly's copy is already visible through the InternalsVisibleTo this project relies on +// for the entry-codec hooks, and a second source-level definition makes every use ambiguous +// (CS0436, an error under TreatWarningsAsErrors). +using System.Runtime.CompilerServices; + +namespace NxGraph.Serialization.Shims +{ + /// + /// netstandard2.1 stand-in for System.ArgumentNullException.ThrowIfNull (net6.0+). + /// + internal static class ArgumentNullExceptionShim + { + public static void ThrowIfNull( + object? argument, + [CallerArgumentExpression("argument")] string? paramName = null) + { + if (argument is null) + { + throw new System.ArgumentNullException(paramName); + } + } + } +} +#endif diff --git a/NxGraph.Serialization/Shims/IsExternalInit.cs b/NxGraph.Serialization/Shims/IsExternalInit.cs new file mode 100644 index 0000000..9f2a280 --- /dev/null +++ b/NxGraph.Serialization/Shims/IsExternalInit.cs @@ -0,0 +1,14 @@ +#if NETSTANDARD2_1 +// ReSharper disable once CheckNamespace +namespace System.Runtime.CompilerServices +{ + /// + /// Marker the compiler requires to emit init-only setters (records, init + /// properties). Present in net5.0+; absent from netstandard2.1, so this assembly + /// carries its own copy — the sibling assemblies' copies are internal. + /// + internal static class IsExternalInit + { + } +} +#endif diff --git a/NxGraph.Tests/PublicApi/NxGraph.Serialization.Abstraction.netstandard2.1.approved.txt b/NxGraph.Tests/PublicApi/NxGraph.Serialization.Abstraction.netstandard2.1.approved.txt new file mode 100644 index 0000000..9a36383 --- /dev/null +++ b/NxGraph.Tests/PublicApi/NxGraph.Serialization.Abstraction.netstandard2.1.approved.txt @@ -0,0 +1,100 @@ +sealed class NxGraph.Serialization.Abstraction.BehaviorBinding + ctor System.Void .ctor(System.String, NxGraph.Serialization.Abstraction.BehaviorFieldValue) + property NxGraph.Serialization.Abstraction.BehaviorFieldValue Literal { get; } + property System.String KeyName { get; } +sealed class NxGraph.Serialization.Abstraction.BehaviorEntry + ctor System.Void .ctor(System.String, NxGraph.Serialization.Abstraction.BehaviorField[]) + property NxGraph.Serialization.Abstraction.BehaviorField[] Fields { get; } + property System.String BehaviorTypeName { get; } +sealed class NxGraph.Serialization.Abstraction.BehaviorField + ctor System.Void .ctor(System.String, NxGraph.Serialization.Abstraction.BehaviorFieldValue) + property NxGraph.Serialization.Abstraction.BehaviorFieldValue Value { get; } + property System.String Name { get; } +enum NxGraph.Serialization.Abstraction.BehaviorFieldKind : System.IComparable, System.IConvertible, System.IFormattable + Behaviors = 8 + Binding = 7 + Bool = 1 + Conditions = 9 + Double = 5 + Enum = 6 + Int32 = 2 + Int64 = 3 + Single = 4 + String = 0 +sealed class NxGraph.Serialization.Abstraction.BehaviorFieldReader + ctor System.Void .ctor(System.Collections.Generic.IReadOnlyList`1[NxGraph.Serialization.Abstraction.BehaviorField]) + method NxGraph.Behaviors.BlackboardValue`1[T] ReadBinding[T](System.String) + method System.Boolean Has(System.String) + method System.Boolean ReadBool(System.String) + method System.Double ReadDouble(System.String) + method System.Int32 ReadInt32(System.String) + method System.Int64 ReadInt64(System.String) + method System.Object[] ReadBehaviors(System.String) + method System.Object[] ReadConditions(System.String) + method System.Single ReadSingle(System.String) + method System.String ReadString(System.String) + method TEnum ReadEnum[TEnum](System.String) +sealed class NxGraph.Serialization.Abstraction.BehaviorFieldValue + ctor System.Void .ctor(NxGraph.Serialization.Abstraction.BehaviorFieldKind, System.String, System.Boolean, System.Int64, System.Double, NxGraph.Serialization.Abstraction.BehaviorBinding, NxGraph.Serialization.Abstraction.BehaviorEntry[], NxGraph.Serialization.Abstraction.ConditionEntry[]) + property NxGraph.Serialization.Abstraction.BehaviorBinding Binding { get; } + property NxGraph.Serialization.Abstraction.BehaviorEntry[] Entries { get; } + property NxGraph.Serialization.Abstraction.BehaviorFieldKind Kind { get; } + property NxGraph.Serialization.Abstraction.ConditionEntry[] Conditions { get; } + property System.Boolean Flag { get; } + property System.Double Number { get; } + property System.Int64 Integer { get; } + property System.String Text { get; } +sealed class NxGraph.Serialization.Abstraction.BehaviorFieldWriter + ctor System.Void .ctor() + method NxGraph.Serialization.Abstraction.BehaviorField[] ToFields() + method System.Void WriteBehaviors(System.String, System.Collections.Generic.IReadOnlyList`1[System.Object]) + method System.Void WriteBinding[T](System.String, NxGraph.Behaviors.BlackboardValue`1[T]&) + method System.Void WriteBool(System.String, System.Boolean) + method System.Void WriteConditions(System.String, System.Collections.Generic.IReadOnlyList`1[System.Object]) + method System.Void WriteDouble(System.String, System.Double) + method System.Void WriteEnum[TEnum](System.String, TEnum) + method System.Void WriteInt32(System.String, System.Int32) + method System.Void WriteInt64(System.String, System.Int64) + method System.Void WriteSingle(System.String, System.Single) + method System.Void WriteString(System.String, System.String) +enum NxGraph.Serialization.Abstraction.BlackboardMismatchPolicy : System.IComparable, System.IConvertible, System.IFormattable + Skip = 1 + Strict = 0 +sealed class NxGraph.Serialization.Abstraction.ConditionEntry + ctor System.Void .ctor(System.String, NxGraph.Serialization.Abstraction.BehaviorField[]) + property NxGraph.Serialization.Abstraction.BehaviorField[] Fields { get; } + property System.String ConditionTypeName { get; } +interface NxGraph.Serialization.Abstraction.IBehaviorRegistry + method System.Boolean TryRead(System.String, NxGraph.Serialization.Abstraction.BehaviorFieldReader, System.Object&) + method System.Boolean TryWrite(System.Object, NxGraph.Serialization.Abstraction.BehaviorFieldWriter) +interface NxGraph.Serialization.Abstraction.IBlackboardBinarySerializer + method System.Threading.Tasks.ValueTask RestoreFromBinaryAsync(NxGraph.Blackboards.Blackboard, System.IO.Stream, NxGraph.Serialization.Abstraction.BlackboardMismatchPolicy, System.Threading.CancellationToken) + method System.Threading.Tasks.ValueTask ToBinaryAsync(NxGraph.Blackboards.Blackboard, System.IO.Stream, System.Threading.CancellationToken) +interface NxGraph.Serialization.Abstraction.IBlackboardJsonSerializer + method System.Threading.Tasks.ValueTask RestoreFromJsonAsync(NxGraph.Blackboards.Blackboard, System.IO.Stream, NxGraph.Serialization.Abstraction.BlackboardMismatchPolicy, System.Threading.CancellationToken) + method System.Threading.Tasks.ValueTask ToJsonAsync(NxGraph.Blackboards.Blackboard, System.IO.Stream, System.Threading.CancellationToken) +interface NxGraph.Serialization.Abstraction.IConditionRegistry + method System.Boolean TryRead(System.String, NxGraph.Serialization.Abstraction.BehaviorFieldReader, System.Object&) + method System.Boolean TryWrite(System.Object, NxGraph.Serialization.Abstraction.BehaviorFieldWriter) +interface NxGraph.Serialization.Abstraction.IContainerCodec +interface NxGraph.Serialization.Abstraction.IContainerCodec`1 : NxGraph.Serialization.Abstraction.IContainerCodec + method NxGraph.Graphs.IAsyncLogic Deserialize(TWire, System.Collections.Generic.IReadOnlyList`1[NxGraph.Graphs.Graph]) + method TWire Serialize(NxGraph.Graphs.ISubGraphProvider) +interface NxGraph.Serialization.Abstraction.IGraphBinarySerializer : NxGraph.Serialization.Abstraction.IGraphSerializer + method System.Threading.Tasks.ValueTask ToBinaryAsync(NxGraph.Graphs.Graph, System.IO.Stream, System.Threading.CancellationToken) + method System.Threading.Tasks.ValueTask`1[NxGraph.Graphs.Graph] FromBinaryAsync(System.IO.Stream, System.Threading.CancellationToken) +interface NxGraph.Serialization.Abstraction.IGraphJsonSerializer : NxGraph.Serialization.Abstraction.IGraphSerializer + method System.Threading.Tasks.ValueTask ToJsonAsync(NxGraph.Graphs.Graph, System.IO.Stream, System.Threading.CancellationToken) + method System.Threading.Tasks.ValueTask`1[NxGraph.Graphs.Graph] FromJsonAsync(System.IO.Stream, System.Threading.CancellationToken) +interface NxGraph.Serialization.Abstraction.IGraphSerializer +interface NxGraph.Serialization.Abstraction.ILogicCodec +interface NxGraph.Serialization.Abstraction.ILogicCodec`1 : NxGraph.Serialization.Abstraction.ILogicCodec + method NxGraph.Graphs.IAsyncLogic Deserialize(TWire) + method TWire Serialize(NxGraph.Graphs.IAsyncLogic) +interface NxGraph.Serialization.Abstraction.IRegionSelectorRegistry + method System.Boolean TryGetKey(System.Func`2[NxGraph.Blackboards.BlackboardContext,NxGraph.Fsm.RegionMask], System.String&) + method System.Boolean TryGetSelector(System.String, System.Func`2[NxGraph.Blackboards.BlackboardContext,NxGraph.Fsm.RegionMask]&) +interface NxGraph.Serialization.Abstraction.ISerializableBehavior + method System.Void Write(NxGraph.Serialization.Abstraction.BehaviorFieldWriter) +interface NxGraph.Serialization.Abstraction.ISerializableCondition + method System.Void Write(NxGraph.Serialization.Abstraction.BehaviorFieldWriter) diff --git a/NxGraph.Tests/PublicApi/NxGraph.Serialization.netstandard2.1.approved.txt b/NxGraph.Tests/PublicApi/NxGraph.Serialization.netstandard2.1.approved.txt new file mode 100644 index 0000000..436b936 --- /dev/null +++ b/NxGraph.Tests/PublicApi/NxGraph.Serialization.netstandard2.1.approved.txt @@ -0,0 +1,42 @@ +sealed class NxGraph.Serialization.BehaviorRegistry : NxGraph.Serialization.Abstraction.IBehaviorRegistry + ctor System.Void .ctor() + method System.Boolean TryRead(System.String, NxGraph.Serialization.Abstraction.BehaviorFieldReader, System.Object&) + method System.Boolean TryWrite(System.Object, NxGraph.Serialization.Abstraction.BehaviorFieldWriter) + method System.Void Register(System.String, System.Func`2[NxGraph.Serialization.Abstraction.BehaviorFieldReader,System.Object]) +sealed class NxGraph.Serialization.BlackboardSerializer : NxGraph.Serialization.Abstraction.IBlackboardBinarySerializer, NxGraph.Serialization.Abstraction.IBlackboardJsonSerializer + ctor System.Void .ctor(System.Text.Json.JsonSerializerOptions, MessagePack.MessagePackSerializerOptions) + method System.Threading.Tasks.ValueTask RestoreFromBinaryAsync(NxGraph.Blackboards.Blackboard, System.IO.Stream, NxGraph.Serialization.Abstraction.BlackboardMismatchPolicy, System.Threading.CancellationToken) + method System.Threading.Tasks.ValueTask RestoreFromJsonAsync(NxGraph.Blackboards.Blackboard, System.IO.Stream, NxGraph.Serialization.Abstraction.BlackboardMismatchPolicy, System.Threading.CancellationToken) + method System.Threading.Tasks.ValueTask ToBinaryAsync(NxGraph.Blackboards.Blackboard, System.IO.Stream, System.Threading.CancellationToken) + method System.Threading.Tasks.ValueTask ToJsonAsync(NxGraph.Blackboards.Blackboard, System.IO.Stream, System.Threading.CancellationToken) +sealed class NxGraph.Serialization.ConditionRegistry : NxGraph.Serialization.Abstraction.IConditionRegistry + ctor System.Void .ctor() + method System.Boolean TryRead(System.String, NxGraph.Serialization.Abstraction.BehaviorFieldReader, System.Object&) + method System.Boolean TryWrite(System.Object, NxGraph.Serialization.Abstraction.BehaviorFieldWriter) + method System.Void Register(System.String, System.Func`2[NxGraph.Serialization.Abstraction.BehaviorFieldReader,System.Object]) +sealed class NxGraph.Serialization.GraphSerializer : NxGraph.Serialization.Abstraction.IGraphBinarySerializer, NxGraph.Serialization.Abstraction.IGraphJsonSerializer, NxGraph.Serialization.Abstraction.IGraphSerializer + ctor System.Void .ctor(NxGraph.Serialization.Abstraction.ILogicCodec) + ctor System.Void .ctor(NxGraph.Serialization.Abstraction.ILogicCodec, NxGraph.Serialization.GraphSerializerOptions) + method NxGraph.Serialization.Abstraction.IGraphBinarySerializer AsBinarySerializer() + method NxGraph.Serialization.Abstraction.IGraphJsonSerializer AsJsonSerializer() + method System.Threading.Tasks.ValueTask ToBinaryAsync(NxGraph.Graphs.Graph, System.IO.Stream, System.Threading.CancellationToken) + method System.Threading.Tasks.ValueTask ToJsonAsync(NxGraph.Graphs.Graph, System.IO.Stream, System.Threading.CancellationToken) + method System.Threading.Tasks.ValueTask`1[NxGraph.Graphs.Graph] FromBinaryAsync(System.IO.Stream, System.Threading.CancellationToken) + method System.Threading.Tasks.ValueTask`1[NxGraph.Graphs.Graph] FromJsonAsync(System.IO.Stream, System.Threading.CancellationToken) +sealed class NxGraph.Serialization.GraphSerializerOptions + ctor System.Void .ctor() + property NxGraph.Serialization.Abstraction.IBehaviorRegistry BehaviorRegistry { get; set; } + property NxGraph.Serialization.Abstraction.IConditionRegistry ConditionRegistry { get; set; } + property NxGraph.Serialization.Abstraction.IContainerCodec ContainerCodec { get; set; } + property NxGraph.Serialization.Abstraction.IRegionSelectorRegistry SelectorRegistry { get; set; } +interface NxGraph.Serialization.IContainerBinaryCodec : NxGraph.Serialization.Abstraction.IContainerCodec, NxGraph.Serialization.Abstraction.IContainerCodec`1[[System.ReadOnlyMemory`1[[System.Byte]]]] +interface NxGraph.Serialization.IContainerTextCodec : NxGraph.Serialization.Abstraction.IContainerCodec, NxGraph.Serialization.Abstraction.IContainerCodec`1[[System.String]] +interface NxGraph.Serialization.ILogicBinaryCodec : NxGraph.Serialization.Abstraction.ILogicCodec, NxGraph.Serialization.Abstraction.ILogicCodec`1[[System.ReadOnlyMemory`1[[System.Byte]]]] +interface NxGraph.Serialization.ILogicTextCodec : NxGraph.Serialization.Abstraction.ILogicCodec, NxGraph.Serialization.Abstraction.ILogicCodec`1[[System.String]] +sealed class NxGraph.Serialization.RegionSelectorRegistry : NxGraph.Serialization.Abstraction.IRegionSelectorRegistry + ctor System.Void .ctor() + method System.Boolean TryGetKey(System.Func`2[NxGraph.Blackboards.BlackboardContext,NxGraph.Fsm.RegionMask], System.String&) + method System.Boolean TryGetSelector(System.String, System.Func`2[NxGraph.Blackboards.BlackboardContext,NxGraph.Fsm.RegionMask]&) + method System.Func`2[NxGraph.Blackboards.BlackboardContext,NxGraph.Fsm.RegionMask] Register(System.String, System.Func`2[NxGraph.Blackboards.BlackboardContext,NxGraph.Fsm.RegionMask]) +static class NxGraph.Serialization.SerializationVersion + field static System.Int32 Version diff --git a/NxGraph.Tests/PublicApi/PublicApiSurfaceTests.cs b/NxGraph.Tests/PublicApi/PublicApiSurfaceTests.cs index 8077ae1..1541469 100644 --- a/NxGraph.Tests/PublicApi/PublicApiSurfaceTests.cs +++ b/NxGraph.Tests/PublicApi/PublicApiSurfaceTests.cs @@ -20,10 +20,11 @@ namespace NxGraph.Tests.PublicApi; /// /// /// Two flavors of capture: the loaded net8.0 assemblies are described via runtime -/// reflection; the netstandard2.1 build of NxGraph (the Unity-facing surface, compiled -/// with the Shims/** re-includes) is described via a -/// walk over NxGraph/bin/{Configuration}/netstandard2.1/NxGraph.dll resolved against -/// the NETStandard.Library.Ref facades, and lands in NxGraph.netstandard2.1.approved.txt. +/// reflection; the netstandard2.1 builds (the Unity-facing surfaces, compiled with the +/// Shims/** re-includes) are described via a walk +/// over {Project}/bin/{Configuration}/netstandard2.1/ resolved against the +/// NETStandard.Library.Ref facades, and land in *.netstandard2.1.approved.txt. +/// All three shipped assemblies multi-target, so all three are captured both ways. /// /// /// Known limitation (both flavors, unchanged from the original fixture): the walk captures @@ -44,6 +45,20 @@ private static readonly (string BaselineFile, Assembly Assembly)[] Assemblies = ("NxGraph.Serialization.Abstraction.approved.txt", typeof(ILogicCodec).Assembly), ]; + /// + /// The netstandard2.1 flavor of each shipped assembly: the project directory holding the + /// build output, and the baseline the walk is compared against. All three multi-target, so + /// all three have a Unity-facing surface worth guarding. + /// + private static readonly (string ProjectDirectory, string AssemblyFileName, string BaselineFile)[] NetStandardAssemblies = + [ + ("NxGraph", "NxGraph.dll", "NxGraph.netstandard2.1.approved.txt"), + ("NxGraph.Serialization", "NxGraph.Serialization.dll", + "NxGraph.Serialization.netstandard2.1.approved.txt"), + ("NxGraph.Serialization.Abstraction", "NxGraph.Serialization.Abstraction.dll", + "NxGraph.Serialization.Abstraction.netstandard2.1.approved.txt"), + ]; + [Test] public void Public_api_matches_approved_baseline( [Range(0, 2)] int assemblyIndex) @@ -53,9 +68,13 @@ public void Public_api_matches_approved_baseline( } [Test] - public void Public_api_matches_approved_baseline_for_netstandard21() + public void Public_api_matches_approved_baseline_for_netstandard21( + [Range(0, 2)] int assemblyIndex) { - string targetDll = NetStandardAssemblyPath(); + (string projectDirectory, string assemblyFileName, string baselineFile) = + NetStandardAssemblies[assemblyIndex]; + + string targetDll = NetStandardAssemblyPath(projectDirectory, assemblyFileName); if (!File.Exists(targetDll)) { Assert.Ignore( @@ -63,13 +82,18 @@ public void Public_api_matches_approved_baseline_for_netstandard21() "Build the full solution (dotnet build) to produce it; the solution build always emits both TFMs."); } + // Everything sitting beside the target resolves too: the sibling NxGraph assemblies and + // — because the serialization project sets CopyLocalLockFileAssemblies on this TFM — + // MessagePack and System.Text.Json, whose types appear in the serializer's signatures. string facadeDir = NetStandardFacadeDirectory(); PathAssemblyResolver resolver = new( - Directory.EnumerateFiles(facadeDir, "*.dll").Append(targetDll)); + Directory.EnumerateFiles(facadeDir, "*.dll") + .Concat(Directory.EnumerateFiles(Path.GetDirectoryName(targetDll)!, "*.dll"))); using MetadataLoadContext mlc = new(resolver, coreAssemblyName: "netstandard"); string actual = DescribePublicApi(mlc.LoadFromAssemblyPath(targetDll)); - CompareOrUpdateBaseline("NxGraph.netstandard2.1.approved.txt", "NxGraph (netstandard2.1)", actual); + CompareOrUpdateBaseline(baselineFile, + $"{Path.GetFileNameWithoutExtension(assemblyFileName)} (netstandard2.1)", actual); } private static void CompareOrUpdateBaseline(string baselineFile, string assemblyDisplayName, string actual) @@ -101,8 +125,8 @@ private static void CompareOrUpdateBaseline(string baselineFile, string assembly "\nIf this change is intentional, re-run with NXGRAPH_UPDATE_PUBLIC_API=1 and commit the baseline diff."); } - /// NxGraph's netstandard2.1 build output for the configuration this test run was built as. - private static string NetStandardAssemblyPath() + /// A project's netstandard2.1 build output for the configuration this test run was built as. + private static string NetStandardAssemblyPath(string projectDirectory, string assemblyFileName) { // Test bin layout: /NxGraph.Tests/bin//net8.0/ — take the live // configuration from the test host's own path so a Debug test run checks the Debug @@ -112,7 +136,7 @@ private static string NetStandardAssemblyPath() string configuration = new DirectoryInfo(baseDir).Parent?.Name ?? "Release"; string repoRoot = Path.GetFullPath(Path.Combine(BaselineDirectory(), "..", "..")); - return Path.Combine(repoRoot, "NxGraph", "bin", configuration, "netstandard2.1", "NxGraph.dll"); + return Path.Combine(repoRoot, projectDirectory, "bin", configuration, "netstandard2.1", assemblyFileName); } /// Reference-facade directory of the restored NETStandard.Library.Ref pack. diff --git a/unity/NxGraphDev/Assets/Scratch.meta b/unity/NxGraphDev/Assets/Scratch.meta new file mode 100644 index 0000000..a476b01 --- /dev/null +++ b/unity/NxGraphDev/Assets/Scratch.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: aee504f8484bf2344ac5bc060da737e5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/NxGraphDev/Assets/Scratch/.gitkeep b/unity/NxGraphDev/Assets/Scratch/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/unity/NxGraphDev/Assets/Scratch/Editor.meta b/unity/NxGraphDev/Assets/Scratch/Editor.meta new file mode 100644 index 0000000..50ed8ca --- /dev/null +++ b/unity/NxGraphDev/Assets/Scratch/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4c5f202686bd061498bb5eb7a45bcaf4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/NxGraphDev/Assets/Scratch/Editor/SerializationSmokeTest.cs b/unity/NxGraphDev/Assets/Scratch/Editor/SerializationSmokeTest.cs new file mode 100644 index 0000000..14b60bb --- /dev/null +++ b/unity/NxGraphDev/Assets/Scratch/Editor/SerializationSmokeTest.cs @@ -0,0 +1,127 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using NxGraph; +using NxGraph.Authoring; +using NxGraph.Graphs; +using NxGraph.Serialization; +using NxGraph.Serialization.Abstraction; +using UnityEditor; +using UnityEngine; + +namespace NxGraphDev.Editor +{ + /// + /// Proves the bundled serialization package works inside Unity's runtime, not merely that it + /// compiles. Both formats are exercised because they fail differently: System.Text.Json is + /// reflection-heavy, and MessagePack resolves formatters dynamically — a missing or + /// conflicting BCL facade shows up here as a TypeLoadException, which is exactly the failure + /// mode that bundling dependencies risks. + /// + /// This lives in the dev project rather than the package on purpose: the core package must + /// not depend on the optional serialization package. + /// + /// + public static class SerializationSmokeTest + { + [MenuItem("Window/NxGraph/Run Serialization Smoke Test")] + public static void Run() + { + try + { + RunAsync().GetAwaiter().GetResult(); + Debug.Log($"[NxGraph] Serialization smoke test PASSED (payload v{SerializationVersion.Version})."); + } + catch (Exception e) + { + Debug.LogError($"[NxGraph] Serialization smoke test FAILED: {e}"); + throw; + } + } + + /// Batch-mode entry point: -executeMethod NxGraphDev.Editor.SerializationSmokeTest.RunBatch. + public static void RunBatch() + { + try + { + RunAsync().GetAwaiter().GetResult(); + Debug.Log($"[NxGraph] Serialization smoke test PASSED (payload v{SerializationVersion.Version})."); + EditorApplication.Exit(0); + } + catch (Exception e) + { + Debug.LogError($"[NxGraph] Serialization smoke test FAILED: {e}"); + EditorApplication.Exit(1); + } + } + + private static async Task RunAsync() + { + Graph graph = BuildGraph(); + GraphSerializer serializer = new(new NoopCodec()); + + using (MemoryStream json = new()) + { + await serializer.ToJsonAsync(graph, json); + json.Position = 0; + Graph restored = await serializer.FromJsonAsync(json); + Expect(restored.NodeCount == graph.NodeCount, + $"JSON round-trip changed the node count: {graph.NodeCount} -> {restored.NodeCount}"); + } + + using (MemoryStream binary = new()) + { + await serializer.ToBinaryAsync(graph, binary); + binary.Position = 0; + Graph restored = await serializer.FromBinaryAsync(binary); + Expect(restored.NodeCount == graph.NodeCount, + $"MessagePack round-trip changed the node count: {graph.NodeCount} -> {restored.NodeCount}"); + } + } + + private static Graph BuildGraph() + { + GraphBuilder builder = new(); + + NodeId first = builder.AddNode(new NxGraph.Fsm.RelayState(() => Result.Success), true); + NodeId second = builder.AddNode(new NxGraph.Fsm.RelayState(() => Result.Success), false); + NodeId handler = builder.AddNode(new NxGraph.Fsm.RelayState(() => Result.Success), false); + + builder.SetName(first, "First"); + builder.SetName(second, "Second"); + builder.SetName(handler, "Handler"); + + builder.AddTransition(first, second); + builder.AddFailureTransition(first, handler); + + return builder.Build(); + } + + private static void Expect(bool condition, string message) + { + if (!condition) + { + throw new InvalidOperationException(message); + } + } + + /// + /// Node logic rides the wire through a codec. This one is deliberately trivial: the test + /// is about the serializer and its dependencies loading and running, not about any + /// particular logic representation. + /// + private sealed class NoopCodec : ILogicTextCodec + { + public string Serialize(IAsyncLogic data) => "noop"; + + public IAsyncLogic Deserialize(string s) => new NoopLogic(); + } + + private sealed class NoopLogic : IAsyncLogic + { + public ValueTask ExecuteAsync(CancellationToken ct = default) => + new(Result.Success); + } + } +} diff --git a/unity/NxGraphDev/Assets/Scratch/Editor/SerializationSmokeTest.cs.meta b/unity/NxGraphDev/Assets/Scratch/Editor/SerializationSmokeTest.cs.meta new file mode 100644 index 0000000..dc7c18b --- /dev/null +++ b/unity/NxGraphDev/Assets/Scratch/Editor/SerializationSmokeTest.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c40cd68f5531b3f4aa9ee17aaec2f43e \ No newline at end of file diff --git a/unity/NxGraphDev/Assets/Scratch/RuntimeUsageProbe.cs b/unity/NxGraphDev/Assets/Scratch/RuntimeUsageProbe.cs new file mode 100644 index 0000000..031830d --- /dev/null +++ b/unity/NxGraphDev/Assets/Scratch/RuntimeUsageProbe.cs @@ -0,0 +1,54 @@ +using NxGraph; +using NxGraph.Authoring; +using NxGraph.Fsm; +using NxGraph.Graphs; +using UnityEngine; + +namespace NxGraphDev +{ + /// + /// A plain MonoBehaviour in Assets/ with no asmdef, proving the ordinary Unity workflow + /// works: the package's plugins are auto-referenced into Assembly-CSharp, so gameplay code + /// can just using NxGraph.Authoring; and build a machine. + /// + public sealed class RuntimeUsageProbe : MonoBehaviour + { + private StateMachine _machine; + + private void Start() + { + Graph graph = GraphBuilder + .StartWith(() => + { + Debug.Log("[NxGraph] first step"); + return Result.Success; + }) + .SetName("First") + .To(() => + { + Debug.Log("[NxGraph] second step"); + return Result.Success; + }) + .SetName("Second") + .Build(); + + _machine = graph.ToStateMachine(); + _machine.SetStepMode(ParallelStepMode.RunToJoin); + } + + private void Update() + { + if (_machine is null) + { + return; + } + + Result result = _machine.Execute(); + if (result != Result.InProgress) + { + Debug.Log($"[NxGraph] machine finished: {result}"); + _machine = null; + } + } + } +} diff --git a/unity/NxGraphDev/Assets/Scratch/RuntimeUsageProbe.cs.meta b/unity/NxGraphDev/Assets/Scratch/RuntimeUsageProbe.cs.meta new file mode 100644 index 0000000..c35e1d4 --- /dev/null +++ b/unity/NxGraphDev/Assets/Scratch/RuntimeUsageProbe.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 061bf656578c91b4a81a088a4d2d6a39 \ No newline at end of file diff --git a/unity/NxGraphDev/Packages/manifest.json b/unity/NxGraphDev/Packages/manifest.json new file mode 100644 index 0000000..1d2a5d5 --- /dev/null +++ b/unity/NxGraphDev/Packages/manifest.json @@ -0,0 +1,42 @@ +{ + "dependencies": { + "com.enzx.nxgraph": "file:../../../upm/com.enzx.nxgraph", + "com.enzx.nxgraph.serialization": "file:../../../upm/com.enzx.nxgraph.serialization", + "com.unity.ide.rider": "3.0.40", + "com.unity.multiplayer.center": "1.0.1", + "com.unity.modules.accessibility": "1.0.0", + "com.unity.modules.adaptiveperformance": "1.0.0", + "com.unity.modules.ai": "1.0.0", + "com.unity.modules.androidjni": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.cloth": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.physics2d": "1.0.0", + "com.unity.modules.screencapture": "1.0.0", + "com.unity.modules.terrain": "1.0.0", + "com.unity.modules.terrainphysics": "1.0.0", + "com.unity.modules.tilemap": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.umbra": "1.0.0", + "com.unity.modules.unityanalytics": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.unitywebrequesttexture": "1.0.0", + "com.unity.modules.unitywebrequestwww": "1.0.0", + "com.unity.modules.vectorgraphics": "1.0.0", + "com.unity.modules.vehicles": "1.0.0", + "com.unity.modules.video": "1.0.0", + "com.unity.modules.vr": "1.0.0", + "com.unity.modules.wind": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } +} diff --git a/unity/NxGraphDev/Packages/packages-lock.json b/unity/NxGraphDev/Packages/packages-lock.json new file mode 100644 index 0000000..cda3c04 --- /dev/null +++ b/unity/NxGraphDev/Packages/packages-lock.json @@ -0,0 +1,316 @@ +{ + "dependencies": { + "com.enzx.nxgraph": { + "version": "file:../../../upm/com.enzx.nxgraph", + "depth": 0, + "source": "local", + "dependencies": {} + }, + "com.enzx.nxgraph.serialization": { + "version": "file:../../../upm/com.enzx.nxgraph.serialization", + "depth": 0, + "source": "local", + "dependencies": { + "com.enzx.nxgraph": "2.2.0-alpha" + } + }, + "com.unity.ext.nunit": { + "version": "2.0.5", + "depth": 1, + "source": "builtin", + "dependencies": {} + }, + "com.unity.ide.rider": { + "version": "3.0.40", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ext.nunit": "1.0.6" + }, + "url": "https://packages.unity.com" + }, + "com.unity.multiplayer.center": { + "version": "1.0.1", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.uielements": "1.0.0" + } + }, + "com.unity.modules.accessibility": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.adaptiveperformance": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.subsystems": "1.0.0" + } + }, + "com.unity.modules.ai": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.androidjni": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.animation": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.assetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.audio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.cloth": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.director": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.animation": "1.0.0" + } + }, + "com.unity.modules.hierarchycore": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.imageconversion": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.imgui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.jsonserialize": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.particlesystem": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics2d": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.screencapture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.subsystems": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.terrain": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.terrainphysics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.terrain": "1.0.0" + } + }, + "com.unity.modules.tilemap": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics2d": "1.0.0" + } + }, + "com.unity.modules.ui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.uielements": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.hierarchycore": "1.0.0", + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.umbra": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unityanalytics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.unitywebrequest": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unitywebrequestassetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestaudio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.audio": "1.0.0" + } + }, + "com.unity.modules.unitywebrequesttexture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestwww": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.vectorgraphics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.imgui": "1.0.0" + } + }, + "com.unity.modules.vehicles": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.video": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.vr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } + }, + "com.unity.modules.wind": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.xr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.subsystems": "1.0.0" + } + } + } +} diff --git a/unity/NxGraphDev/ProjectSettings/AudioManager.asset b/unity/NxGraphDev/ProjectSettings/AudioManager.asset new file mode 100644 index 0000000..50b4625 --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/AudioManager.asset @@ -0,0 +1,23 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!11 &1 +AudioManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Volume: 1 + Rolloff Scale: 1 + Doppler Factor: 1 + Default Speaker Mode: 2 + m_SampleRate: 0 + m_DSPBufferSize: 1024 + m_VirtualVoiceCount: 512 + m_RealVoiceCount: 32 + m_EnableOutputSuspension: 1 + m_SpatializerPlugin: + m_AmbisonicDecoderPlugin: + m_DisableAudio: 0 + m_VirtualizeEffects: 1 + m_RequestedDSPBufferSize: 0 + m_AudioFoundation: 0 + m_OutputChannelLayout: 2 + m_OutputSamplingRate: 48000 diff --git a/unity/NxGraphDev/ProjectSettings/ClusterInputManager.asset b/unity/NxGraphDev/ProjectSettings/ClusterInputManager.asset new file mode 100644 index 0000000..e7886b2 --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/ClusterInputManager.asset @@ -0,0 +1,6 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!236 &1 +ClusterInputManager: + m_ObjectHideFlags: 0 + m_Inputs: [] diff --git a/unity/NxGraphDev/ProjectSettings/DynamicsManager.asset b/unity/NxGraphDev/ProjectSettings/DynamicsManager.asset new file mode 100644 index 0000000..3c102d1 --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/DynamicsManager.asset @@ -0,0 +1,45 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!55 &1 +PhysicsManager: + m_ObjectHideFlags: 0 + serializedVersion: 23 + m_Gravity: {x: 0, y: -9.81, z: 0} + m_DefaultMaterial: {fileID: 0} + m_BounceThreshold: 2 + m_DefaultMaxDepenetrationVelocity: 10 + m_SleepThreshold: 0.005 + m_DefaultContactOffset: 0.01 + m_DefaultSolverIterations: 6 + m_DefaultSolverVelocityIterations: 1 + m_QueriesHitBackfaces: 0 + m_QueriesHitTriggers: 1 + m_EnableAdaptiveForce: 0 + m_ClothInterCollisionDistance: 0.1 + m_ClothInterCollisionStiffness: 0.2 + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + m_SimulationMode: 0 + m_AutoSyncTransforms: 0 + m_ReuseCollisionCallbacks: 1 + m_InvokeCollisionCallbacks: 1 + m_ClothInterCollisionSettingsToggle: 0 + m_ClothGravity: {x: 0, y: -9.81, z: 0} + m_ContactPairsMode: 0 + m_BroadphaseType: 2 + m_WorldBounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 256, y: 256, z: 256} + m_WorldSubdivisions: 8 + m_FrictionType: 0 + m_EnableEnhancedDeterminism: 0 + m_ImprovedPatchFriction: 0 + m_GenerateOnTriggerStayEvents: 1 + m_SolverType: 0 + m_DefaultMaxAngularSpeed: 50 + m_ScratchBufferChunkCount: 4 + m_CurrentBackendId: 4072204805 + m_FastMotionThreshold: 3.4028235e+38 + m_SceneBuffersReleaseInterval: 0 + m_ReleaseSceneBuffers: 0 + m_LogVerbosity: 3 + m_IncrementalStaticBroadphase: 1 diff --git a/unity/NxGraphDev/ProjectSettings/EditorBuildSettings.asset b/unity/NxGraphDev/ProjectSettings/EditorBuildSettings.asset new file mode 100644 index 0000000..0147887 --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/EditorBuildSettings.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1045 &1 +EditorBuildSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Scenes: [] + m_configObjects: {} diff --git a/unity/NxGraphDev/ProjectSettings/EditorSettings.asset b/unity/NxGraphDev/ProjectSettings/EditorSettings.asset new file mode 100644 index 0000000..f5b380f --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/EditorSettings.asset @@ -0,0 +1,52 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!159 &1 +EditorSettings: + m_ObjectHideFlags: 0 + serializedVersion: 15 + m_SerializationMode: 2 + m_LineEndingsForNewScripts: 2 + m_DefaultBehaviorMode: 0 + m_PrefabRegularEnvironment: {fileID: 0} + m_PrefabUIEnvironment: {fileID: 0} + m_SpritePackerMode: 0 + m_SpritePackerCacheSize: 10 + m_SpritePackerPaddingPower: 1 + m_Bc7TextureCompressor: 0 + m_EtcTextureCompressorBehavior: 1 + m_EtcTextureFastCompressor: 1 + m_EtcTextureNormalCompressor: 2 + m_EtcTextureBestCompressor: 4 + m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;asmref;rsp;java;cpp;c;mm;m;h + m_ProjectGenerationRootNamespace: + m_EnableTextureStreamingInEditMode: 1 + m_EnableTextureStreamingInPlayMode: 1 + m_EnableEditorAsyncCPUTextureLoading: 0 + m_AsyncShaderCompilation: 1 + m_BlockShaders: 0 + m_UnlockBlockShaders: 0 + m_PrefabModeAllowAutoSave: 1 + m_EnterPlayModeOptionsEnabled: 1 + m_EnterPlayModeOptions: 0 + m_GameObjectNamingDigits: 1 + m_GameObjectNamingScheme: 0 + m_AssetNamingUsesSpace: 1 + m_InspectorUseIMGUIDefaultInspector: 0 + m_UseLegacyProbeSampleCount: 0 + m_SerializeInlineMappingsOnOneLine: 1 + m_DisableCookiesInLightmapper: 0 + m_ShadowmaskStitching: 1 + m_AssetPipelineMode: 1 + m_RefreshImportMode: 0 + m_CacheServerMode: 0 + m_CacheServerEndpoint: + m_CacheServerNamespacePrefix: default + m_CacheServerEnableDownload: 1 + m_CacheServerEnableUpload: 1 + m_CacheServerEnableTls: 0 + m_CacheServerValidationMode: 2 + m_CacheServerDownloadBatchSize: 128 + m_EnableEnlightenBakedGI: 0 + m_ReferencedClipsExactNaming: 1 + m_ForceAssetUnloadAndGCOnSceneLoad: 1 + m_HideBuildProfileClassicPlatforms: 0 diff --git a/unity/NxGraphDev/ProjectSettings/GraphicsSettings.asset b/unity/NxGraphDev/ProjectSettings/GraphicsSettings.asset new file mode 100644 index 0000000..4b152c0 --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/GraphicsSettings.asset @@ -0,0 +1,68 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!30 &1 +GraphicsSettings: + m_ObjectHideFlags: 0 + serializedVersion: 16 + m_Deferred: + m_Mode: 1 + m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} + m_DeferredReflections: + m_Mode: 1 + m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} + m_ScreenSpaceShadows: + m_Mode: 1 + m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} + m_DepthNormals: + m_Mode: 1 + m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} + m_MotionVectors: + m_Mode: 1 + m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} + m_LightHalo: + m_Mode: 1 + m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} + m_LensFlare: + m_Mode: 1 + m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} + m_VideoShadersIncludeMode: 2 + m_AlwaysIncludedShaders: + - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10783, guid: 0000000000000000f000000000000000, type: 0} + m_PreloadedShaders: [] + m_PreloadShadersBatchTimeLimit: -1 + m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0} + m_CustomRenderPipeline: {fileID: 0} + m_TransparencySortMode: 0 + m_TransparencySortAxis: {x: 0, y: 0, z: 1} + m_DefaultRenderingPath: 1 + m_DefaultMobileRenderingPath: 1 + m_TierSettings: [] + m_LightmapStripping: 0 + m_FogStripping: 0 + m_InstancingStripping: 0 + m_BrgStripping: 0 + m_LightmapKeepPlain: 1 + m_LightmapKeepDirCombined: 1 + m_LightmapKeepDynamicPlain: 1 + m_LightmapKeepDynamicDirCombined: 1 + m_LightmapKeepShadowMask: 1 + m_LightmapKeepSubtractive: 1 + m_FogKeepLinear: 1 + m_FogKeepExp: 1 + m_FogKeepExp2: 1 + m_AlbedoSwatchInfos: [] + m_RenderPipelineGlobalSettingsMap: {} + m_ShaderBuildSettings: + keywordDeclarationOverrides: [] + m_LightsUseLinearIntensity: 0 + m_LightsUseColorTemperature: 0 + m_LogWhenShaderIsCompiled: 0 + m_LightProbeOutsideHullStrategy: 1 + m_CameraRelativeLightCulling: 0 + m_CameraRelativeShadowCulling: 0 diff --git a/unity/NxGraphDev/ProjectSettings/InputManager.asset b/unity/NxGraphDev/ProjectSettings/InputManager.asset new file mode 100644 index 0000000..8068b20 --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/InputManager.asset @@ -0,0 +1,296 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!13 &1 +InputManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Axes: + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: a + altPositiveButton: d + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: s + altPositiveButton: w + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: mouse 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: mouse 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left shift + altNegativeButton: + altPositiveButton: mouse 2 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: space + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse X + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse Y + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse ScrollWheel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 2 + joyNum: 0 + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 1 + type: 2 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 0 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 1 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 2 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 3 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: return + altNegativeButton: + altPositiveButton: joystick button 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: enter + altNegativeButton: + altPositiveButton: space + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Cancel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: escape + altNegativeButton: + altPositiveButton: joystick button 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + m_UsePhysicalKeys: 1 diff --git a/unity/NxGraphDev/ProjectSettings/MemorySettings.asset b/unity/NxGraphDev/ProjectSettings/MemorySettings.asset new file mode 100644 index 0000000..517e60e --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/MemorySettings.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!387306366 &1 +MemorySettings: + m_ObjectHideFlags: 0 + m_EditorMemorySettings: + m_MainAllocatorBlockSize: -1 + m_ThreadAllocatorBlockSize: -1 + m_MainGfxBlockSize: -1 + m_ThreadGfxBlockSize: -1 + m_CacheBlockSize: -1 + m_TypetreeBlockSize: -1 + m_ProfilerBlockSize: -1 + m_ProfilerEditorBlockSize: -1 + m_BucketAllocatorGranularity: -1 + m_BucketAllocatorBucketsCount: -1 + m_BucketAllocatorBlockSize: -1 + m_BucketAllocatorBlockCount: -1 + m_ProfilerBucketAllocatorGranularity: -1 + m_ProfilerBucketAllocatorBucketsCount: -1 + m_ProfilerBucketAllocatorBlockSize: -1 + m_ProfilerBucketAllocatorBlockCount: -1 + m_TempAllocatorSizeMain: -1 + m_JobTempAllocatorBlockSize: -1 + m_BackgroundJobTempAllocatorBlockSize: -1 + m_JobTempAllocatorReducedBlockSize: -1 + m_TempAllocatorSizeGIBakingWorker: -1 + m_TempAllocatorSizeNavMeshWorker: -1 + m_TempAllocatorSizeAudioWorker: -1 + m_TempAllocatorSizeCloudWorker: -1 + m_TempAllocatorSizeGfx: -1 + m_TempAllocatorSizeJobWorker: -1 + m_TempAllocatorSizeBackgroundWorker: -1 + m_TempAllocatorSizePreloadManager: -1 + m_PlatformMemorySettings: [] diff --git a/unity/NxGraphDev/ProjectSettings/MultiplayerManager.asset b/unity/NxGraphDev/ProjectSettings/MultiplayerManager.asset new file mode 100644 index 0000000..c19bcd7 --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/MultiplayerManager.asset @@ -0,0 +1,9 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!655991488 &1 +MultiplayerManager: + m_ObjectHideFlags: 0 + m_EnableMultiplayerRoles: 0 + m_EnablePlayModeLocalDeployment: 0 + m_EnablePlayModeRemoteDeployment: 0 + m_StrippingTypes: {} diff --git a/unity/NxGraphDev/ProjectSettings/NavMeshAreas.asset b/unity/NxGraphDev/ProjectSettings/NavMeshAreas.asset new file mode 100644 index 0000000..2e2e369 --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/NavMeshAreas.asset @@ -0,0 +1,93 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!126 &1 +NavMeshProjectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + areas: + - name: Walkable + cost: 1 + - name: Not Walkable + cost: 1 + - name: Jump + cost: 2 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + m_LastAgentTypeID: -887442657 + m_Settings: + - serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.75 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_SettingNames: + - Humanoid diff --git a/unity/NxGraphDev/ProjectSettings/PackageManagerSettings.asset b/unity/NxGraphDev/ProjectSettings/PackageManagerSettings.asset new file mode 100644 index 0000000..8e6edc3 --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/PackageManagerSettings.asset @@ -0,0 +1,42 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 53 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: UnityEditor.dll::UnityEditor.PackageManager.UI.Internal.PackageManagerProjectSettings + m_EnablePreReleasePackages: 0 + m_AdvancedSettingsExpanded: 1 + m_ScopedRegistriesSettingsExpanded: 1 + m_SeeAllPackageVersions: 0 + m_DismissPreviewPackagesInUse: 0 + oneTimeWarningShown: 0 + oneTimePackageErrorsPopUpShown: 0 + m_Registries: + - m_Id: main + m_Name: + m_Url: https://packages.unity.com + m_Scopes: [] + m_IsDefault: 1 + m_Capabilities: 7 + m_ConfigSource: 0 + m_Compliance: + m_Status: 0 + m_Violations: [] + m_UserSelectedRegistryName: + m_UserAddingNewScopedRegistry: 0 + m_RegistryInfoDraft: + m_Modified: 0 + m_ErrorMessage: + m_UserModificationsEntityId: + m_Data: -920 + m_OriginalEntityId: + m_Data: -922 + m_LoadAssets: 0 diff --git a/unity/NxGraphDev/ProjectSettings/Physics2DSettings.asset b/unity/NxGraphDev/ProjectSettings/Physics2DSettings.asset new file mode 100644 index 0000000..14f419f --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/Physics2DSettings.asset @@ -0,0 +1,57 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!19 &1 +Physics2DSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_Gravity: {x: 0, y: -9.81} + m_DefaultMaterial: {fileID: 0} + m_VelocityIterations: 8 + m_PositionIterations: 3 + m_BounceThreshold: 1 + m_MaxLinearCorrection: 0.2 + m_MaxAngularCorrection: 8 + m_MaxTranslationSpeed: 100 + m_MaxRotationSpeed: 360 + m_BaumgarteScale: 0.2 + m_BaumgarteTimeOfImpactScale: 0.75 + m_TimeToSleep: 0.5 + m_LinearSleepTolerance: 0.01 + m_AngularSleepTolerance: 2 + m_DefaultContactOffset: 0.01 + m_ContactThreshold: 0 + m_JobOptions: + serializedVersion: 2 + useMultithreading: 0 + useConsistencySorting: 0 + m_InterpolationPosesPerJob: 100 + m_NewContactsPerJob: 30 + m_CollideContactsPerJob: 100 + m_ClearFlagsPerJob: 200 + m_ClearBodyForcesPerJob: 200 + m_SyncDiscreteFixturesPerJob: 50 + m_SyncContinuousFixturesPerJob: 50 + m_FindNearestContactsPerJob: 100 + m_UpdateTriggerContactsPerJob: 100 + m_IslandSolverCostThreshold: 100 + m_IslandSolverBodyCostScale: 1 + m_IslandSolverContactCostScale: 10 + m_IslandSolverJointCostScale: 10 + m_IslandSolverBodiesPerJob: 50 + m_IslandSolverContactsPerJob: 50 + m_SimulationMode: 0 + m_SimulationLayers: + serializedVersion: 2 + m_Bits: 4294967295 + m_MaxSubStepCount: 4 + m_MinSubStepFPS: 30 + m_UseSubStepping: 0 + m_UseSubStepContacts: 0 + m_QueriesHitTriggers: 1 + m_QueriesStartInColliders: 1 + m_CallbacksOnDisable: 1 + m_ReuseCollisionCallbacks: 1 + m_AutoSyncTransforms: 0 + m_GizmoOptions: 10 + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + m_PhysicsLowLevelSettings: {fileID: 0} diff --git a/unity/NxGraphDev/ProjectSettings/PresetManager.asset b/unity/NxGraphDev/ProjectSettings/PresetManager.asset new file mode 100644 index 0000000..67a94da --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/PresetManager.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1386491679 &1 +PresetManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_DefaultPresets: {} diff --git a/unity/NxGraphDev/ProjectSettings/ProjectSettings.asset b/unity/NxGraphDev/ProjectSettings/ProjectSettings.asset new file mode 100644 index 0000000..587c97e --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/ProjectSettings.asset @@ -0,0 +1,694 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!129 &1 +PlayerSettings: + m_ObjectHideFlags: 0 + serializedVersion: 28 + productGUID: 655105db1dc2a8544abb6886bf8bb56e + AndroidProfiler: 0 + AndroidFilterTouchesWhenObscured: 0 + AndroidEnableSustainedPerformanceMode: 0 + defaultScreenOrientation: 4 + targetDevice: 2 + useOnDemandResources: 0 + accelerometerFrequency: 60 + companyName: DefaultCompany + productName: NxGraphDev + defaultCursor: {fileID: 0} + cursorHotspot: {x: 0, y: 0} + m_SplashScreenBackgroundColor: {r: 0.12156863, g: 0.12156863, b: 0.1254902, a: 1} + m_ShowUnitySplashScreen: 1 + m_ShowUnitySplashLogo: 1 + m_SplashScreenOverlayOpacity: 1 + m_SplashScreenAnimation: 1 + m_SplashScreenLogoStyle: 1 + m_SplashScreenDrawMode: 0 + m_SplashScreenBackgroundAnimationZoom: 1 + m_SplashScreenLogoAnimationZoom: 1 + m_SplashScreenBackgroundLandscapeAspect: 1 + m_SplashScreenBackgroundPortraitAspect: 1 + m_SplashScreenBackgroundLandscapeUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenBackgroundPortraitUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenLogos: [] + m_VirtualRealitySplashScreen: {fileID: 0} + defaultScreenWidth: 1920 + defaultScreenHeight: 1080 + defaultScreenWidthWeb: 960 + defaultScreenHeightWeb: 600 + m_StereoRenderingPath: 0 + m_ActiveColorSpace: 0 + unsupportedMSAAFallback: 0 + m_SpriteBatchMaxVertexCount: 65535 + m_SpriteBatchVertexThreshold: 300 + m_MTRendering: 1 + mipStripping: 0 + numberOfMipsStripped: 0 + numberOfMipsStrippedPerMipmapLimitGroup: {} + m_StackTraceTypes: 010000000100000001000000010000000100000001000000 + iosShowActivityIndicatorOnLoading: -1 + androidShowActivityIndicatorOnLoading: -1 + iosUseCustomAppBackgroundBehavior: 0 + allowedAutorotateToPortrait: 1 + allowedAutorotateToPortraitUpsideDown: 1 + allowedAutorotateToLandscapeRight: 1 + allowedAutorotateToLandscapeLeft: 1 + useOSAutorotation: 1 + use32BitDisplayBuffer: 1 + preserveFramebufferAlpha: 0 + disableDepthAndStencilBuffers: 0 + androidStartInFullscreen: 1 + androidRenderOutsideSafeArea: 1 + androidUseSwappy: 1 + androidDisplayOptions: 1 + androidBlitType: 0 + androidResizeableActivity: 1 + androidDefaultWindowWidth: 1920 + androidDefaultWindowHeight: 1080 + androidMinimumWindowWidth: 400 + androidMinimumWindowHeight: 300 + androidFullscreenMode: 1 + androidAutoRotationBehavior: 1 + androidPredictiveBackSupport: 1 + androidApplicationEntry: 2 + defaultIsNativeResolution: 1 + macRetinaSupport: 1 + runInBackground: 0 + muteOtherAudioSources: 0 + Prepare IOS For Recording: 0 + Force IOS Speakers When Recording: 0 + audioSpatialExperience: 0 + deferSystemGesturesMode: 0 + hideHomeButton: 0 + submitAnalytics: 1 + usePlayerLog: 1 + dedicatedServerOptimizations: 1 + bakeCollisionMeshes: 0 + forceSingleInstance: 0 + useFlipModelSwapchain: 1 + resizableWindow: 0 + useMacAppStoreValidation: 0 + macAppStoreCategory: public.app-category.games + gpuSkinning: 0 + meshDeformation: 0 + xboxPIXTextureCapture: 0 + xboxEnableAvatar: 0 + xboxEnableKinect: 0 + xboxEnableKinectAutoTracking: 0 + xboxEnableFitness: 0 + visibleInBackground: 1 + allowFullscreenSwitch: 1 + fullscreenMode: 1 + xboxSpeechDB: 0 + xboxEnableHeadOrientation: 0 + xboxEnableGuest: 0 + xboxEnablePIXSampling: 0 + metalFramebufferOnly: 0 + metalUseMetalDisplayLink: 0 + xboxOneResolution: 0 + xboxOneSResolution: 0 + xboxOneXResolution: 3 + xboxOneMonoLoggingLevel: 0 + xboxOneLoggingLevel: 1 + xboxOneDisableEsram: 0 + xboxOneEnableTypeOptimization: 0 + xboxOnePresentImmediateThreshold: 0 + switchQueueCommandMemory: 1048576 + switchQueueControlMemory: 16384 + switchQueueComputeMemory: 262144 + switchNVNShaderPoolsGranularity: 33554432 + switchNVNDefaultPoolsGranularity: 16777216 + switchNVNOtherPoolsGranularity: 16777216 + switchGpuScratchPoolGranularity: 2097152 + switchAllowGpuScratchShrinking: 0 + switchNVNMaxPublicTextureIDCount: 0 + switchNVNMaxPublicSamplerIDCount: 0 + switchMaxWorkerMultiple: 8 + switchNVNGraphicsFirmwareMemory: 32 + switchGraphicsJobsSyncAfterKick: 1 + vulkanNumSwapchainBuffers: 3 + vulkanEnableSetSRGBWrite: 0 + vulkanEnablePreTransform: 0 + vulkanEnableLateAcquireNextImage: 0 + vulkanEnableCommandBufferRecycling: 1 + loadStoreDebugModeEnabled: 0 + visionOSBundleVersion: 1.0 + tvOSBundleVersion: 1.0 + bundleVersion: 1.0 + preloadedAssets: [] + metroInputSource: 0 + wsaTransparentSwapchain: 0 + xboxOneDisableKinectGpuReservation: 1 + xboxOneEnable7thCore: 1 + vrSettings: + enable360StereoCapture: 0 + enableFrameTimingStats: 0 + enableOpenGLProfilerGPURecorders: 1 + allowHDRDisplaySupport: 0 + useHDRDisplay: 0 + hdrBitDepth: 0 + m_ColorGamuts: 00000000 + targetPixelDensity: 0 + resolutionScalingMode: 0 + resetResolutionOnWindowResize: 0 + androidSupportedAspectRatio: 1 + androidMaxAspectRatio: 2.4 + androidMinAspectRatio: 1 + applicationIdentifier: {} + buildNumber: {} + overrideDefaultApplicationIdentifier: 0 + AndroidBundleVersionCode: 1 + AndroidMinSdkVersion: 25 + AndroidTargetSdkVersion: 0 + AndroidPreferredInstallLocation: 1 + AndroidPreferredDataLocation: 1 + aotOptions: + stripEngineCode: 1 + iPhoneStrippingLevel: 0 + iPhoneScriptCallOptimization: 0 + ForceInternetPermission: 0 + ForceSDCardPermission: 0 + CreateWallpaper: 0 + androidSplitApplicationBinary: 0 + keepLoadedShadersAlive: 0 + StripUnusedMeshComponents: 0 + strictShaderVariantMatching: 0 + VertexChannelCompressionMask: 4054 + iPhoneSdkVersion: 988 + iOSSimulatorArchitecture: 0 + iOSTargetOSVersionString: + tvOSSdkVersion: 0 + tvOSSimulatorArchitecture: 0 + tvOSRequireExtendedGameController: 0 + tvOSTargetOSVersionString: + VisionOSSdkVersion: 0 + VisionOSTargetOSVersionString: + uIPrerenderedIcon: 0 + uIRequiresPersistentWiFi: 0 + uIRequiresFullScreen: 1 + uIStatusBarHidden: 1 + uIExitOnSuspend: 0 + uIStatusBarStyle: 0 + appleTVSplashScreen: {fileID: 0} + appleTVSplashScreen2x: {fileID: 0} + tvOSSmallIconLayers: [] + tvOSSmallIconLayers2x: [] + tvOSLargeIconLayers: [] + tvOSLargeIconLayers2x: [] + tvOSTopShelfImageLayers: [] + tvOSTopShelfImageLayers2x: [] + tvOSTopShelfImageWideLayers: [] + tvOSTopShelfImageWideLayers2x: [] + iOSLaunchScreenType: 0 + iOSLaunchScreenPortrait: {fileID: 0} + iOSLaunchScreenLandscape: {fileID: 0} + iOSLaunchScreenBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreenFillPct: 100 + iOSLaunchScreenSize: 100 + iOSLaunchScreeniPadType: 0 + iOSLaunchScreeniPadImage: {fileID: 0} + iOSLaunchScreeniPadBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreeniPadFillPct: 100 + iOSLaunchScreeniPadSize: 100 + iOSLaunchScreenCustomStoryboardPath: + iOSLaunchScreeniPadCustomStoryboardPath: + iOSDeviceRequirements: [] + iOSURLSchemes: [] + macOSURLSchemes: [] + iOSBackgroundModes: 0 + iOSMetalForceHardShadows: 0 + metalEditorSupport: 1 + metalAPIValidation: 1 + metalCompileShaderBinary: 0 + iOSRenderExtraFrameOnPause: 0 + iosCopyPluginsCodeInsteadOfSymlink: 0 + appleDeveloperTeamID: + iOSManualSigningProvisioningProfileID: + tvOSManualSigningProvisioningProfileID: + VisionOSManualSigningProvisioningProfileID: + iOSManualSigningProvisioningProfileType: 0 + tvOSManualSigningProvisioningProfileType: 0 + VisionOSManualSigningProvisioningProfileType: 0 + appleEnableAutomaticSigning: 0 + iOSRequireARKit: 0 + iOSAutomaticallyDetectAndAddCapabilities: 1 + appleEnableProMotion: 0 + shaderPrecisionModel: 0 + clonedFromGUID: 00000000000000000000000000000000 + templatePackageId: + templateDefaultScene: + useCustomMainManifest: 0 + useCustomLauncherManifest: 0 + useCustomMainGradleTemplate: 0 + useCustomLauncherGradleManifest: 0 + useCustomBaseGradleTemplate: 0 + useCustomGradlePropertiesTemplate: 0 + useCustomGradleSettingsTemplate: 0 + useCustomProguardFile: 0 + AndroidTargetArchitectures: 2 + AndroidAllowedArchitectures: -1 + AndroidSplashScreenScale: 0 + androidSplashScreen: {fileID: 0} + AndroidKeystoreName: + AndroidKeyaliasName: + AndroidEnableArmv9SecurityFeatures: 0 + AndroidEnableArm64MTE: 0 + AndroidBuildApkPerCpuArchitecture: 0 + AndroidTVCompatibility: 0 + AndroidIsGame: 1 + androidAppCategory: 3 + useAndroidAppCategory: 1 + androidAppCategoryOther: + AndroidEnableTango: 0 + androidEnableBanner: 1 + androidUseLowAccuracyLocation: 0 + androidUseCustomKeystore: 0 + m_AndroidBanners: + - width: 320 + height: 180 + banner: {fileID: 0} + androidGamepadSupportLevel: 0 + AndroidMinifyRelease: 0 + AndroidMinifyDebug: 0 + AndroidValidateAppBundleSize: 1 + AndroidAppBundleSizeToValidate: 200 + AndroidReportGooglePlayAppDependencies: 1 + androidSymbolsSizeThreshold: 800 + m_BuildTargetIcons: [] + m_BuildTargetPlatformIcons: [] + m_BuildTargetBatching: [] + m_BuildTargetShaderSettings: [] + m_BuildTargetGraphicsJobs: [] + m_BuildTargetGraphicsJobMode: [] + m_BuildTargetGraphicsAPIs: [] + m_BuildTargetVRSettings: [] + m_DefaultShaderChunkSizeInMB: 16 + m_DefaultShaderChunkCount: 0 + openGLRequireES31: 0 + openGLRequireES31AEP: 0 + openGLRequireES32: 0 + m_TemplateCustomTags: {} + mobileMTRendering: + Android: 1 + VisionOS: 1 + iPhone: 1 + tvOS: 1 + m_BuildTargetGroupLightmapEncodingQuality: [] + m_BuildTargetGroupHDRCubemapEncodingQuality: [] + m_BuildTargetGroupLightmapSettings: [] + m_BuildTargetGroupLoadStoreDebugModeSettings: [] + m_BuildTargetNormalMapEncoding: [] + m_BuildTargetDefaultTextureCompressionFormat: [] + playModeTestRunnerEnabled: 0 + runPlayModeTestAsEditModeTest: 0 + actionOnDotNetUnhandledException: 1 + editorGfxJobOverride: 1 + enableInternalProfiler: 0 + logObjCUncaughtExceptions: 1 + enableCrashReportAPI: 0 + cameraUsageDescription: + locationUsageDescription: + microphoneUsageDescription: + bluetoothUsageDescription: + macOSTargetOSVersion: + switchNMETAOverride: + switchNetLibKey: + switchSocketMemoryPoolSize: 6144 + switchSocketAllocatorPoolSize: 128 + switchSocketConcurrencyLimit: 14 + switchScreenResolutionBehavior: 2 + switchUseCPUProfiler: 0 + switchEnableFileSystemTrace: 0 + switchLTOSetting: 0 + switchApplicationID: 0x01004b9000490000 + switchNSODependencies: + switchCompilerFlags: + switchTitleNames_0: + switchTitleNames_1: + switchTitleNames_2: + switchTitleNames_3: + switchTitleNames_4: + switchTitleNames_5: + switchTitleNames_6: + switchTitleNames_7: + switchTitleNames_8: + switchTitleNames_9: + switchTitleNames_10: + switchTitleNames_11: + switchTitleNames_12: + switchTitleNames_13: + switchTitleNames_14: + switchTitleNames_15: + switchPublisherNames_0: + switchPublisherNames_1: + switchPublisherNames_2: + switchPublisherNames_3: + switchPublisherNames_4: + switchPublisherNames_5: + switchPublisherNames_6: + switchPublisherNames_7: + switchPublisherNames_8: + switchPublisherNames_9: + switchPublisherNames_10: + switchPublisherNames_11: + switchPublisherNames_12: + switchPublisherNames_13: + switchPublisherNames_14: + switchPublisherNames_15: + switchIcons_0: {fileID: 0} + switchIcons_1: {fileID: 0} + switchIcons_2: {fileID: 0} + switchIcons_3: {fileID: 0} + switchIcons_4: {fileID: 0} + switchIcons_5: {fileID: 0} + switchIcons_6: {fileID: 0} + switchIcons_7: {fileID: 0} + switchIcons_8: {fileID: 0} + switchIcons_9: {fileID: 0} + switchIcons_10: {fileID: 0} + switchIcons_11: {fileID: 0} + switchIcons_12: {fileID: 0} + switchIcons_13: {fileID: 0} + switchIcons_14: {fileID: 0} + switchIcons_15: {fileID: 0} + switchSmallIcons_0: {fileID: 0} + switchSmallIcons_1: {fileID: 0} + switchSmallIcons_2: {fileID: 0} + switchSmallIcons_3: {fileID: 0} + switchSmallIcons_4: {fileID: 0} + switchSmallIcons_5: {fileID: 0} + switchSmallIcons_6: {fileID: 0} + switchSmallIcons_7: {fileID: 0} + switchSmallIcons_8: {fileID: 0} + switchSmallIcons_9: {fileID: 0} + switchSmallIcons_10: {fileID: 0} + switchSmallIcons_11: {fileID: 0} + switchSmallIcons_12: {fileID: 0} + switchSmallIcons_13: {fileID: 0} + switchSmallIcons_14: {fileID: 0} + switchSmallIcons_15: {fileID: 0} + switchManualHTML: + switchAccessibleURLs: + switchLegalInformation: + switchMainThreadStackSize: 1048576 + switchPresenceGroupId: + switchLogoHandling: 0 + switchReleaseVersion: 0 + switchDisplayVersion: 1.0.0 + switchStartupUserAccount: 0 + switchSupportedLanguagesMask: 0 + switchLogoType: 0 + switchApplicationErrorCodeCategory: + switchUserAccountSaveDataSize: 0 + switchUserAccountSaveDataJournalSize: 0 + switchApplicationAttribute: 0 + switchCardSpecSize: -1 + switchCardSpecClock: -1 + switchRatingsMask: 0 + switchRatingsInt_0: 0 + switchRatingsInt_1: 0 + switchRatingsInt_2: 0 + switchRatingsInt_3: 0 + switchRatingsInt_4: 0 + switchRatingsInt_5: 0 + switchRatingsInt_6: 0 + switchRatingsInt_7: 0 + switchRatingsInt_8: 0 + switchRatingsInt_9: 0 + switchRatingsInt_10: 0 + switchRatingsInt_11: 0 + switchRatingsInt_12: 0 + switchLocalCommunicationIds_0: + switchLocalCommunicationIds_1: + switchLocalCommunicationIds_2: + switchLocalCommunicationIds_3: + switchLocalCommunicationIds_4: + switchLocalCommunicationIds_5: + switchLocalCommunicationIds_6: + switchLocalCommunicationIds_7: + switchParentalControl: 0 + switchAllowsScreenshot: 1 + switchAllowsVideoCapturing: 1 + switchAllowsRuntimeAddOnContentInstall: 0 + switchDataLossConfirmation: 0 + switchUserAccountLockEnabled: 0 + switchSystemResourceMemory: 16777216 + switchSupportedNpadStyles: 22 + switchNativeFsCacheSize: 32 + switchIsHoldTypeHorizontal: 1 + switchSupportedNpadCount: 8 + switchEnableTouchScreen: 1 + switchSocketConfigEnabled: 0 + switchTcpInitialSendBufferSize: 32 + switchTcpInitialReceiveBufferSize: 64 + switchTcpAutoSendBufferSizeMax: 256 + switchTcpAutoReceiveBufferSizeMax: 256 + switchUdpSendBufferSize: 9 + switchUdpReceiveBufferSize: 42 + switchSocketBufferEfficiency: 4 + switchSocketInitializeEnabled: 1 + switchNetworkInterfaceManagerInitializeEnabled: 1 + switchDisableHTCSPlayerConnection: 0 + switchUseNewStyleFilepaths: 1 + switchUseLegacyFmodPriorities: 0 + switchUseMicroSleepForYield: 1 + switchEnableRamDiskSupport: 0 + switchMicroSleepForYieldTime: 25 + switchRamDiskSpaceSize: 12 + switchUpgradedPlayerSettingsToNMETA: 0 + ps4NPAgeRating: 12 + ps4NPTitleSecret: + ps4NPTrophyPackPath: + ps4ParentalLevel: 11 + ps4ContentID: ED1633-NPXX51362_00-0000000000000000 + ps4Category: 0 + ps4MasterVersion: 01.00 + ps4AppVersion: 01.00 + ps4AppType: 0 + ps4ParamSfxPath: + ps4VideoOutPixelFormat: 0 + ps4VideoOutInitialWidth: 1920 + ps4VideoOutBaseModeInitialWidth: 1920 + ps4VideoOutReprojectionRate: 60 + ps4PronunciationXMLPath: + ps4PronunciationSIGPath: + ps4BackgroundImagePath: + ps4StartupImagePath: + ps4StartupImagesFolder: + ps4IconImagesFolder: + ps4SaveDataImagePath: + ps4SdkOverride: + ps4BGMPath: + ps4ShareFilePath: + ps4ShareOverlayImagePath: + ps4PrivacyGuardImagePath: + ps4ExtraSceSysFile: + ps4NPtitleDatPath: + ps4RemotePlayKeyAssignment: -1 + ps4RemotePlayKeyMappingDir: + ps4PlayTogetherPlayerCount: 0 + ps4EnterButtonAssignment: 2 + ps4ApplicationParam1: 0 + ps4ApplicationParam2: 0 + ps4ApplicationParam3: 0 + ps4ApplicationParam4: 0 + ps4DownloadDataSize: 0 + ps4GarlicHeapSize: 2048 + ps4ProGarlicHeapSize: 2560 + playerPrefsMaxSize: 32768 + ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ + ps4pnSessions: 1 + ps4pnPresence: 1 + ps4pnFriends: 1 + ps4pnGameCustomData: 1 + playerPrefsSupport: 0 + enableApplicationExit: 0 + resetTempFolder: 1 + restrictedAudioUsageRights: 0 + ps4UseResolutionFallback: 0 + ps4ReprojectionSupport: 0 + ps4UseAudio3dBackend: 0 + ps4UseLowGarlicFragmentationMode: 1 + ps4SocialScreenEnabled: 0 + ps4ScriptOptimizationLevel: 2 + ps4Audio3dVirtualSpeakerCount: 14 + ps4attribCpuUsage: 0 + ps4PatchPkgPath: + ps4PatchLatestPkgPath: + ps4PatchChangeinfoPath: + ps4PatchDayOne: 0 + ps4attribUserManagement: 0 + ps4attribMoveSupport: 0 + ps4attrib3DSupport: 0 + ps4attribShareSupport: 0 + ps4attribExclusiveVR: 0 + ps4disableAutoHideSplash: 0 + ps4videoRecordingFeaturesUsed: 0 + ps4contentSearchFeaturesUsed: 0 + ps4CompatibilityPS5: 0 + ps4AllowPS5Detection: 0 + ps4GPU800MHz: 1 + ps4attribEyeToEyeDistanceSettingVR: 0 + ps4IncludedModules: [] + ps4attribVROutputEnabled: 0 + monoEnv: + splashScreenBackgroundSourceLandscape: {fileID: 0} + splashScreenBackgroundSourcePortrait: {fileID: 0} + blurSplashScreenBackground: 1 + spritePackerPolicy: + webGLMemorySize: 32 + webGLExceptionSupport: 1 + webGLNameFilesAsHashes: 0 + webGLShowDiagnostics: 0 + webGLDataCaching: 1 + webGLDebugSymbols: 0 + webGLEmscriptenArgs: + webGLModulesDirectory: + webGLTemplate: APPLICATION:Default + webGLAnalyzeBuildSize: 0 + webGLUseEmbeddedResources: 0 + webGLCompressionFormat: 1 + webGLWasmArithmeticExceptions: 0 + webGLLinkerTarget: 1 + webGLThreadsSupport: 0 + webGLDecompressionFallback: 0 + webGLInitialMemorySize: 32 + webGLMaximumMemorySize: 2048 + webGLMemoryGrowthMode: 2 + webGLMemoryLinearGrowthStep: 16 + webGLMemoryGeometricGrowthStep: 0.2 + webGLMemoryGeometricGrowthCap: 96 + webGLPowerPreference: 2 + webGLWebAssemblyTable: 0 + webGLWebAssemblyBigInt: 0 + webGLCloseOnQuit: 0 + webWasm2023: 0 + webEnableSubmoduleStrippingCompatibility: 0 + scriptingDefineSymbols: {} + additionalCompilerArguments: {} + platformArchitecture: {} + scriptingBackend: {} + il2cppCompilerConfiguration: {} + il2cppCodeGeneration: {} + il2cppStacktraceInformation: {} + managedStrippingLevel: {} + incrementalIl2cppBuild: {} + suppressCommonWarnings: 1 + allowUnsafeCode: 0 + useDeterministicCompilation: 1 + additionalIl2CppArgs: + scriptingRuntimeVersion: 1 + gcIncremental: 1 + gcWBarrierValidation: 0 + apiCompatibilityLevelPerPlatform: {} + editorAssembliesCompatibilityLevel: 1 + m_RenderingPath: 1 + m_MobileRenderingPath: 1 + metroPackageName: NxGraphDev + metroPackageVersion: + metroCertificatePath: + metroCertificatePassword: + metroCertificateSubject: + metroCertificateIssuer: + metroCertificateNotAfter: 0000000000000000 + metroApplicationDescription: NxGraphDev + wsaImages: {} + metroTileShortName: + metroTileShowName: 0 + metroMediumTileShowName: 0 + metroLargeTileShowName: 0 + metroWideTileShowName: 0 + metroSupportStreamingInstall: 0 + metroLastRequiredScene: 0 + metroDefaultTileSize: 1 + metroTileForegroundText: 2 + metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0} + metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, a: 1} + metroSplashScreenUseBackgroundColor: 0 + syncCapabilities: 0 + platformCapabilities: {} + metroTargetDeviceFamilies: {} + metroFTAName: + metroFTAFileTypes: [] + metroProtocolName: + vcxProjDefaultLanguage: + XboxOneProductId: + XboxOneUpdateKey: + XboxOneSandboxId: + XboxOneContentId: + XboxOneTitleId: + XboxOneSCId: + XboxOneGameOsOverridePath: + XboxOnePackagingOverridePath: + XboxOneAppManifestOverridePath: + XboxOneVersion: 1.0.0.0 + XboxOnePackageEncryption: 0 + XboxOnePackageUpdateGranularity: 2 + XboxOneDescription: + XboxOneLanguage: + - enus + XboxOneCapability: [] + XboxOneGameRating: {} + XboxOneIsContentPackage: 0 + XboxOneEnhancedXboxCompatibilityMode: 0 + XboxOneEnableGPUVariability: 1 + XboxOneSockets: {} + XboxOneSplashScreen: {fileID: 0} + XboxOneAllowedProductIds: [] + XboxOnePersistentLocalStorageSize: 0 + XboxOneXTitleMemory: 8 + XboxOneOverrideIdentityName: + XboxOneOverrideIdentityPublisher: + vrEditorSettings: {} + cloudServicesEnabled: {} + luminIcon: + m_Name: + m_ModelFolderPath: + m_PortalFolderPath: + luminCert: + m_CertPath: + m_SignPackage: 1 + luminIsChannelApp: 0 + luminVersion: + m_VersionCode: 1 + m_VersionName: + hmiPlayerDataPath: + hmiForceSRGBBlit: 0 + embeddedLinuxEnableGamepadInput: 0 + hmiCpuConfiguration: + hmiLogStartupTiming: 0 + qnxGraphicConfPath: + apiCompatibilityLevel: 6 + captureStartupLogs: {} + activeInputHandler: 0 + windowsGamepadBackendHint: 0 + enableDirectStorage: 0 + cloudProjectId: + framebufferDepthMemorylessMode: 0 + qualitySettingsNames: [] + projectName: + organizationId: + cloudEnabled: 0 + legacyClampBlendShapeWeights: 0 + hmiLoadingImage: {fileID: 0} + platformRequiresReadableAssets: 0 + virtualTexturingSupportEnabled: 0 + insecureHttpOption: 0 + androidVulkanDenyFilterList: [] + androidVulkanAllowFilterList: [] + androidVulkanDeviceFilterListAsset: {fileID: 0} + d3d12DeviceFilterListAsset: {fileID: 0} + allowedHttpConnections: 3 diff --git a/unity/NxGraphDev/ProjectSettings/ProjectVersion.txt b/unity/NxGraphDev/ProjectSettings/ProjectVersion.txt new file mode 100644 index 0000000..2c1b9d7 --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/ProjectVersion.txt @@ -0,0 +1,2 @@ +m_EditorVersion: 6000.4.8f1 +m_EditorVersionWithRevision: 6000.4.8f1 (f8b72d3d7343) diff --git a/unity/NxGraphDev/ProjectSettings/QualitySettings.asset b/unity/NxGraphDev/ProjectSettings/QualitySettings.asset new file mode 100644 index 0000000..64f8aba --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/QualitySettings.asset @@ -0,0 +1,347 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!47 &1 +QualitySettings: + m_ObjectHideFlags: 0 + serializedVersion: 5 + m_CurrentQuality: 5 + m_QualitySettings: + - serializedVersion: 5 + name: Very Low + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 15 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + skinWeights: 1 + globalTextureMipmapLimit: 1 + textureMipmapLimitSettings: [] + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + useLegacyDetailDistribution: 0 + adaptiveVsync: 0 + vSyncCount: 0 + realtimeGICPUUsage: 25 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 + lodBias: 0.3 + meshLodThreshold: 1 + maximumLODLevel: 0 + enableLODCrossFade: 1 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 4 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 + excludedTargetPlatforms: [] + - serializedVersion: 5 + name: Low + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + skinWeights: 2 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + useLegacyDetailDistribution: 0 + adaptiveVsync: 0 + vSyncCount: 0 + realtimeGICPUUsage: 25 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 + lodBias: 0.4 + meshLodThreshold: 1 + maximumLODLevel: 0 + enableLODCrossFade: 1 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 16 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 + excludedTargetPlatforms: [] + - serializedVersion: 5 + name: Medium + pixelLightCount: 1 + shadows: 1 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + skinWeights: 2 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + useLegacyDetailDistribution: 0 + adaptiveVsync: 0 + vSyncCount: 1 + realtimeGICPUUsage: 25 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 + lodBias: 0.7 + meshLodThreshold: 1 + maximumLODLevel: 0 + enableLODCrossFade: 1 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 64 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 + excludedTargetPlatforms: [] + - serializedVersion: 5 + name: High + pixelLightCount: 2 + shadows: 2 + shadowResolution: 1 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 40 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + skinWeights: 2 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + useLegacyDetailDistribution: 0 + adaptiveVsync: 0 + vSyncCount: 1 + realtimeGICPUUsage: 50 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 + lodBias: 1 + meshLodThreshold: 1 + maximumLODLevel: 0 + enableLODCrossFade: 1 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 256 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 + excludedTargetPlatforms: [] + - serializedVersion: 5 + name: Very High + pixelLightCount: 3 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 70 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + skinWeights: 4 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] + anisotropicTextures: 2 + antiAliasing: 2 + softParticles: 1 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + useLegacyDetailDistribution: 0 + adaptiveVsync: 0 + vSyncCount: 1 + realtimeGICPUUsage: 50 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 + lodBias: 1.5 + meshLodThreshold: 1 + maximumLODLevel: 0 + enableLODCrossFade: 1 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 1024 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 + excludedTargetPlatforms: [] + - serializedVersion: 5 + name: Ultra + pixelLightCount: 4 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 4 + shadowDistance: 150 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + skinWeights: 255 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] + anisotropicTextures: 2 + antiAliasing: 2 + softParticles: 1 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + useLegacyDetailDistribution: 0 + adaptiveVsync: 0 + vSyncCount: 1 + realtimeGICPUUsage: 100 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 + lodBias: 2 + meshLodThreshold: 1 + maximumLODLevel: 0 + enableLODCrossFade: 1 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 4096 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 + excludedTargetPlatforms: [] + m_TextureMipmapLimitGroupNames: [] + m_PerPlatformDefaultQuality: + Android: 2 + EmbeddedLinux: 5 + GameCoreScarlett: 5 + GameCoreXboxOne: 5 + Kepler: 5 + LinuxHeadlessSimulation: 5 + Nintendo Switch: 5 + Nintendo Switch 2: 5 + PS4: 5 + PS5: 5 + QNX: 5 + Server: 5 + Standalone: 5 + VisionOS: 5 + WebGL: 3 + Windows Store Apps: 5 + XboxOne: 5 + iPhone: 2 + tvOS: 2 diff --git a/unity/NxGraphDev/ProjectSettings/SceneTemplateSettings.json b/unity/NxGraphDev/ProjectSettings/SceneTemplateSettings.json new file mode 100644 index 0000000..ede5887 --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/SceneTemplateSettings.json @@ -0,0 +1,121 @@ +{ + "templatePinStates": [], + "dependencyTypeInfos": [ + { + "userAdded": false, + "type": "UnityEngine.AnimationClip", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.Animations.AnimatorController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.AnimatorOverrideController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.Audio.AudioMixerController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.ComputeShader", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Cubemap", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.GameObject", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.LightingDataAsset", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.LightingSettings", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Material", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.MonoScript", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicsMaterial", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicsMaterial2D", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessProfile", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessResources", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.VolumeProfile", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.SceneAsset", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Shader", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.ShaderVariantCollection", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Texture", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Texture2D", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Timeline.TimelineAsset", + "defaultInstantiationMode": 0 + } + ], + "defaultDependencyTypeInfo": { + "userAdded": false, + "type": "", + "defaultInstantiationMode": 1 + }, + "newSceneOverride": 0 +} \ No newline at end of file diff --git a/unity/NxGraphDev/ProjectSettings/TagManager.asset b/unity/NxGraphDev/ProjectSettings/TagManager.asset new file mode 100644 index 0000000..6abf33d --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/TagManager.asset @@ -0,0 +1,46 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!78 &1 +TagManager: + serializedVersion: 3 + tags: [] + layers: + - Default + - TransparentFX + - Ignore Raycast + - + - Water + - UI + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + m_SortingLayers: + - name: Default + uniqueID: 0 + locked: 0 + m_RenderingLayers: + - Default + m_MigratedRenderPipelines: [] diff --git a/unity/NxGraphDev/ProjectSettings/TimeManager.asset b/unity/NxGraphDev/ProjectSettings/TimeManager.asset new file mode 100644 index 0000000..2e23a1f --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/TimeManager.asset @@ -0,0 +1,14 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!5 &1 +TimeManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + Fixed Timestep: + m_Count: 2822399 + m_Rate: + m_Denominator: 1 + m_Numerator: 141120000 + Maximum Allowed Timestep: 0.33333334 + m_TimeScale: 1 + Maximum Particle Timestep: 0.03 diff --git a/unity/NxGraphDev/ProjectSettings/UnityConnectSettings.asset b/unity/NxGraphDev/ProjectSettings/UnityConnectSettings.asset new file mode 100644 index 0000000..5ef5698 --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/UnityConnectSettings.asset @@ -0,0 +1,40 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!310 &1 +UnityConnectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 1 + m_Enabled: 0 + m_TestMode: 0 + m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events + m_EventUrl: https://cdp.cloud.unity3d.com/v1/events + m_ConfigUrl: https://config.uca.cloud.unity3d.com + m_DashboardUrl: https://dashboard.unity3d.com + m_TestInitMode: 0 + InsightsSettings: + m_EngineDiagnosticsEnabled: 0 + m_Enabled: 0 + CrashReportingSettings: + serializedVersion: 2 + m_EventUrl: https://perf-events.cloud.unity3d.com + m_EnableCloudDiagnosticsReporting: 0 + m_LogBufferSize: 10 + m_CaptureEditorExceptions: 1 + UnityPurchasingSettings: + m_Enabled: 0 + m_TestMode: 0 + UnityAnalyticsSettings: + m_Enabled: 0 + m_TestMode: 0 + m_InitializeOnStartup: 1 + m_PackageRequiringCoreStatsPresent: 0 + UnityAdsSettings: + m_Enabled: 0 + m_InitializeOnStartup: 1 + m_TestMode: 0 + m_IosGameId: + m_AndroidGameId: + m_GameIds: {} + m_GameId: + PerformanceReportingSettings: + m_Enabled: 0 diff --git a/unity/NxGraphDev/ProjectSettings/VFXManager.asset b/unity/NxGraphDev/ProjectSettings/VFXManager.asset new file mode 100644 index 0000000..56783bb --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/VFXManager.asset @@ -0,0 +1,20 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!937362698 &1 +VFXManager: + m_ObjectHideFlags: 0 + m_IndirectShader: {fileID: 0} + m_CopyBufferShader: {fileID: 0} + m_PrefixSumShader: {fileID: 0} + m_SortShader: {fileID: 0} + m_StripUpdateShader: {fileID: 0} + m_EmptyShader: {fileID: 0} + m_RenderPipeSettingsPath: + m_FixedTimeStep: 0.016666668 + m_MaxDeltaTime: 0.05 + m_MaxScrubTime: 30 + m_MaxCapacity: 100000000 + m_CompiledVersion: 0 + m_RuntimeVersion: 0 + m_RuntimeResources: {fileID: 0} + m_BatchEmptyLifetime: 300 diff --git a/unity/NxGraphDev/ProjectSettings/VersionControlSettings.asset b/unity/NxGraphDev/ProjectSettings/VersionControlSettings.asset new file mode 100644 index 0000000..979fd8e --- /dev/null +++ b/unity/NxGraphDev/ProjectSettings/VersionControlSettings.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!890905787 &1 +VersionControlSettings: + m_ObjectHideFlags: 0 + m_Mode: Visible Meta Files + m_TrackPackagesOutsideProject: 0 diff --git a/unity/README.md b/unity/README.md new file mode 100644 index 0000000..7f4a204 --- /dev/null +++ b/unity/README.md @@ -0,0 +1,55 @@ +# Unity development project + +`NxGraphDev` is a harness for developing the NxGraph graph editor. It is **not** shipped and **not** a sample: it exists so the editor code — which lives in the UPM package, not here — can be run, debugged and screenshotted against a real Unity install. + +- Unity **6000.4.8f1**, API Compatibility Level **.NET Standard 2.1**. +- Both packages are referenced by relative `file:` path in `Packages/manifest.json`, so Unity uses the working tree directly. Edits to the package are live; there is no copy to keep in sync. + +## Opening it + +Unity Hub → **Add** → **Add project from disk** → pick `NxGraph_Code/unity/NxGraphDev`. Hub matches the version from `ProjectSettings/ProjectVersion.txt` (6000.4.8f1); if you later open it with a different Unity, expect an upgrade prompt. + +Do the staging step below **first**, or Unity opens to a package with no code in it. + +## Before opening it + +The packages ship prebuilt assemblies, and those are gitignored — a fresh clone has `.meta` files in `Runtime/Plugins` and nothing beside them. Stage them first: + +```bash +dotnet run --project NxGraph.Build -- stage-binary +``` + +Without this Unity opens to a package with no code in it. Re-run it after any change to the core or serialization libraries; Unity picks the new assemblies up on focus. + +Use `stage-binary`, not `stage-source`. Source mode compiles the core inside Unity as the `NxGraph.Unity.Runtime` assembly, which the prebuilt `NxGraph.Serialization.dll` cannot bind to. + +## Writing code in it + +This is an ordinary Unity project — nothing about NxGraph changes the workflow. + +The packages ship their assemblies as auto-referenced plugins, so a plain script in `Assets/` with no assembly definition can `using NxGraph.Authoring;` and build a machine. `Assets/Scratch/RuntimeUsageProbe.cs` is exactly that: a `MonoBehaviour`, no asmdef, compiled into `Assembly-CSharp`. If you add your own asmdef, leave `overrideReferences` off (the default) and the plugins stay visible. + +`com.unity.ide.rider` is installed, so Unity generates the C# projects and `NxGraphDev.sln`. Four projects show up: `Assembly-CSharp`, `Assembly-CSharp-Editor`, `NxGraph.Unity.Runtime`, and `NxGraph.Unity.Editor` — the last one is the package's editor code, and because the packages are referenced by `file:` path rather than copied, its sources point straight at the working tree. **Editing the graph editor from the IDE edits the package**; save, focus Unity, and it recompiles. There is no copy to keep in sync and no separate build step. + +The one thing that is *not* automatic: changes to the C# libraries under `NxGraph_Code/` (`NxGraph`, `NxGraph.Serialization`) are compiled by `dotnet`, not Unity. Re-run `stage-binary` after those, then focus Unity. + +## Where the code lives + +| What | Where | +| --- | --- | +| Editor code | `upm/com.enzx.nxgraph/Editor/` | +| Scratch scenes and test assets | `unity/NxGraphDev/Assets/Scratch/` | + +Editor code lives in the package on purpose: it ships to consumers with the package, the `Editor` platform constraint in its asmdef keeps it out of player builds, and developing it in place means there is never a migration from "project code" to "package code". + +`Assets/Scratch/` is for throwaway work. Nothing there is referenced by the package. + +## Using it + +`Window → NxGraph → Graph Editor`, or double-click an `NxGraphAsset` (`Assets → Create → NxGraph → Graph`). + +Right-click the canvas to add a step; drag from `success` or `failure` to wire it; right-click a node to make it the start. Every structural edit recompiles the asset into a real `Graph` and runs `graph.Validate()` — the panel at the bottom shows the library's own verdict, not a second opinion. + +## What this is not, yet + +The asset model covers plain steps and the two transition channels. Branch nodes, composites, fork/join, behaviors, retry policies and blackboard schemas are all authorable through the C# DSL and are **not** in the editor's model yet. `Copy Mermaid` runs the library's exporter over the compiled graph, so it renders more than the canvas draws. diff --git a/upm/com.enzx.nxgraph.serialization/CHANGELOG.md b/upm/com.enzx.nxgraph.serialization/CHANGELOG.md new file mode 100644 index 0000000..e6c61ac --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +All notable changes to this package are documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +- Initial package. Ships `NxGraph.Serialization.dll` built for netstandard2.1, together with its bundled dependencies (MessagePack, System.Text.Json, and the BCL facades they require). +- Depends on `com.enzx.nxgraph` at an exactly pinned version; the two packages are versioned and released as a unit. diff --git a/upm/com.enzx.nxgraph.serialization/CHANGELOG.md.meta b/upm/com.enzx.nxgraph.serialization/CHANGELOG.md.meta new file mode 100644 index 0000000..852d122 --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/CHANGELOG.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1db210d104da4513a75896d97a6a937f +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/upm/com.enzx.nxgraph.serialization/Documentation~/index.md b/upm/com.enzx.nxgraph.serialization/Documentation~/index.md new file mode 100644 index 0000000..3931803 --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/Documentation~/index.md @@ -0,0 +1,37 @@ +# NxGraph Serialization + +Optional serialization for NxGraph in Unity. See the package `README.md` for installation requirements and the duplicate-assembly caveat that comes with bundled dependencies. + +## What a durable flow consists of + +Three kinds of artifact, serialized independently: + +| Artifact | Produced by | Notes | +| --- | --- | --- | +| Graph payload | `GraphSerializer` | Structure: nodes, transitions, composites, fork/join, event entries, behaviors. | +| Machine snapshot | `StateMachine.Suspend()` / `SuspendDeep()` | Plain records (`StateMachineSnapshot`, `StateMachineDeepSnapshot`). Serialize with any serializer. | +| Blackboard payload | `BlackboardSerializer` | One per bound board. Node-scoped boards are transient and never serialize. | + +Machine-level configuration (step mode, restart policy) is not structure and does not ride the payload. + +## Node logic + +Node logic is serialized through pluggable `ILogicCodec` implementations, which live in `NxGraph.Serialization.Abstraction` — shipped in the **core** package, so a codec assembly can reference the abstraction without depending on this package. + +Delegate-carrying relay nodes (`.To(bb => ...)`, port relays, `Relay*` branch states) are not serializable by construction; a codec decides how the graphs you author are represented on the wire. + +## Payload version + +The wire format is versioned (`SerializationVersion`). Older payloads stay readable; a payload from a newer version than the running assembly is rejected. Because this package is pinned to an exact core version, the two always agree. + +## Build and release + +This package is staged by the repository's C# build system and only in binary mode: + +```bash +dotnet run --project NxGraph.Build -- stage-binary +``` + +Staging copies `NxGraph.Serialization.dll` and its dependency closure out of `NxGraph.Serialization/bin/Release/netstandard2.1/` into `Runtime/Plugins/`. The set of files allowed there is defined by the committed `.meta` sidecars: if a dependency appears or disappears, staging fails until the sidecars are updated, so nothing is silently bundled into or dropped from a shipped package. + +See the core package's `Documentation~/build-and-release.md` for the full pipeline. diff --git a/upm/com.enzx.nxgraph.serialization/LICENSE.md b/upm/com.enzx.nxgraph.serialization/LICENSE.md new file mode 100644 index 0000000..9bbbe8b --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/LICENSE.md @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2025 Mohamad Iraji + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/upm/com.enzx.nxgraph.serialization/LICENSE.md.meta b/upm/com.enzx.nxgraph.serialization/LICENSE.md.meta new file mode 100644 index 0000000..cdece0c --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/LICENSE.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 08535b955f414d7f85caeb541b6d50a7 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/upm/com.enzx.nxgraph.serialization/README.md b/upm/com.enzx.nxgraph.serialization/README.md new file mode 100644 index 0000000..75ee409 --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/README.md @@ -0,0 +1,41 @@ +# NxGraph Serialization + +Optional serialization for [NxGraph](https://github.com/Enzx/NxGraph) in Unity: durable graph payloads, state-machine snapshots, and blackboard payloads, in JSON or MessagePack. + +This package is separate from `com.enzx.nxgraph` because it is the only part of the library with third-party dependencies. The core package has none and stays that way. + +## Requirements + +- Unity 2021.3 or newer, with **API Compatibility Level set to .NET Standard 2.1** (Project Settings → Player → Other Settings). +- `com.enzx.nxgraph` at the same version. The dependency is pinned exactly; the two packages are built and released together. + +## What ships here + +`Runtime/Plugins/` carries `NxGraph.Serialization.dll` (netstandard2.1) together with its full dependency closure — MessagePack and System.Text.Json plus the BCL facades those need on netstandard2.1. Nothing else has to be installed. + +Bundling has a cost worth knowing about before you install: several of those facades (`System.Memory`, `System.Buffers`, `System.Runtime.CompilerServices.Unsafe`, `System.Text.Encodings.Web`, …) are commonly shipped by *other* Unity packages too. If your project already gets them from somewhere else — NuGetForUnity, another asset, a different SDK — Unity will report duplicate assemblies, and you must keep exactly one copy. Deleting the duplicate from this package's `Runtime/Plugins` folder is a valid fix as long as the surviving version is compatible. + +`NxGraph.Serialization.Abstraction.dll` is **not** here. It has no dependencies of its own, so it ships in the core package where custom codecs can reference it without pulling any of this in. + +## Usage + +```csharp +using NxGraph.Serialization; + +GraphSerializer serializer = new(new MyLogicCodec()); + +// JSON +await serializer.ToJsonAsync(graph, stream); +Graph restored = await serializer.FromJsonAsync(stream); + +// MessagePack +await serializer.ToMessagePackAsync(graph, stream); +``` + +A durable flow is more than one artifact: the graph payload, the machine snapshot (`StateMachineSnapshot` or `StateMachineDeepSnapshot` — plain records, serialize them with anything), and one `BlackboardSerializer` payload per bound board. Node-scoped boards are transient and never serialize. + +See the core package's documentation for the full model. + +## Source mode is not supported here + +The core package can be staged in *source* mode, where its C# compiles inside Unity as the `NxGraph.Unity.Runtime` assembly. A prebuilt `NxGraph.Serialization.dll` references the assembly named `NxGraph` and cannot bind to that, so this package requires the core package in **binary** mode. The release pipeline enforces it: source-mode releases do not publish this package at all. diff --git a/upm/com.enzx.nxgraph.serialization/README.md.meta b/upm/com.enzx.nxgraph.serialization/README.md.meta new file mode 100644 index 0000000..acf2149 --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2ffafa3c5a9b4186ab58fd812b084836 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/upm/com.enzx.nxgraph.serialization/Runtime.meta b/upm/com.enzx.nxgraph.serialization/Runtime.meta new file mode 100644 index 0000000..19d5492 --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0b7b4d3c113b4b13af4fbf985b047bae +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/upm/com.enzx.nxgraph.serialization/Runtime/Plugins.meta b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins.meta new file mode 100644 index 0000000..651e83c --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3d928c37d425489c88ced172944dcc04 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/.gitkeep b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/MessagePack.Annotations.dll.meta b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/MessagePack.Annotations.dll.meta new file mode 100644 index 0000000..ad9a0b3 --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/MessagePack.Annotations.dll.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 746f244078e2475abcedca69191d7da3 diff --git a/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/MessagePack.dll.meta b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/MessagePack.dll.meta new file mode 100644 index 0000000..bc9a20b --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/MessagePack.dll.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: eaeb536a2bcb448e8d4b73c45bd47f80 diff --git a/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/Microsoft.Bcl.AsyncInterfaces.dll.meta b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/Microsoft.Bcl.AsyncInterfaces.dll.meta new file mode 100644 index 0000000..4f56423 --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/Microsoft.Bcl.AsyncInterfaces.dll.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c79692c323e7480ba5ee69b96fc8d7d4 diff --git a/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/Microsoft.NET.StringTools.dll.meta b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/Microsoft.NET.StringTools.dll.meta new file mode 100644 index 0000000..aba7ebf --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/Microsoft.NET.StringTools.dll.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 315e7441f09a45be9145642a8e20fda9 diff --git a/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/NxGraph.Serialization.dll.meta b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/NxGraph.Serialization.dll.meta new file mode 100644 index 0000000..348753c --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/NxGraph.Serialization.dll.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 61d27b088ac44455bfd1ea259900d9fc diff --git a/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/NxGraph.Serialization.pdb.meta b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/NxGraph.Serialization.pdb.meta new file mode 100644 index 0000000..8783bc9 --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/NxGraph.Serialization.pdb.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 75f937e85dff4039a3b5ff814e9be710 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/NxGraph.Serialization.xml.meta b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/NxGraph.Serialization.xml.meta new file mode 100644 index 0000000..546c8a2 --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/NxGraph.Serialization.xml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 65798d98f36a4665bb13857ed1158f15 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Buffers.dll.meta b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Buffers.dll.meta new file mode 100644 index 0000000..e602c2f --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Buffers.dll.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8c62edfcd8164e7186d276c7ecb877bd diff --git a/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Collections.Immutable.dll.meta b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Collections.Immutable.dll.meta new file mode 100644 index 0000000..043df4a --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Collections.Immutable.dll.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 556f0ee7599b4074ad469b9c1ec1a802 diff --git a/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Memory.dll.meta b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Memory.dll.meta new file mode 100644 index 0000000..a0a8941 --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Memory.dll.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c037bbb7f778472c999faa6ad308d0f0 diff --git a/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Numerics.Vectors.dll.meta b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Numerics.Vectors.dll.meta new file mode 100644 index 0000000..4d7cda9 --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Numerics.Vectors.dll.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ce818b56e7b6481184e31ea2c8ef8d68 diff --git a/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Runtime.CompilerServices.Unsafe.dll.meta b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Runtime.CompilerServices.Unsafe.dll.meta new file mode 100644 index 0000000..eb96f22 --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Runtime.CompilerServices.Unsafe.dll.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8086a639653043cca5b0af7a95723165 diff --git a/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Text.Encodings.Web.dll.meta b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Text.Encodings.Web.dll.meta new file mode 100644 index 0000000..2fd4fe6 --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Text.Encodings.Web.dll.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a587ca0aa7014f2dbf24ff4de50a6c42 diff --git a/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Text.Json.dll.meta b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Text.Json.dll.meta new file mode 100644 index 0000000..aef78eb --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Text.Json.dll.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: af68283f70124cc09bf635a5a2add4d5 diff --git a/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Threading.Tasks.Extensions.dll.meta b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Threading.Tasks.Extensions.dll.meta new file mode 100644 index 0000000..dee3119 --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/Runtime/Plugins/System.Threading.Tasks.Extensions.dll.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c6a19222af4a4e8bad2a34ef1a0d4b85 diff --git a/upm/com.enzx.nxgraph.serialization/package.json b/upm/com.enzx.nxgraph.serialization/package.json new file mode 100644 index 0000000..0a248c9 --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/package.json @@ -0,0 +1,27 @@ +{ + "name": "com.enzx.nxgraph.serialization", + "displayName": "NxGraph Serialization", + "version": "2.2.0-alpha", + "description": "Optional JSON and MessagePack serialization for NxGraph: durable graph payloads, state-machine snapshots, and blackboard payloads with pluggable node-logic codecs. Bundles its own dependencies.", + "unity": "2021.3", + "license": "MIT", + "author": { + "name": "Mohamad Iraji", + "url": "https://github.com/Enzx/NxGraph" + }, + "dependencies": { + "com.enzx.nxgraph": "2.2.0-alpha" + }, + "keywords": [ + "fsm", + "state-machine", + "graph", + "serialization", + "messagepack", + "json", + "unity" + ], + "documentationUrl": "https://github.com/Enzx/NxGraph/tree/main/upm/com.enzx.nxgraph.serialization/Documentation~", + "changelogUrl": "https://github.com/Enzx/NxGraph/blob/main/upm/com.enzx.nxgraph.serialization/CHANGELOG.md", + "licensesUrl": "https://github.com/Enzx/NxGraph/blob/main/LICENSE" +} diff --git a/upm/com.enzx.nxgraph.serialization/package.json.meta b/upm/com.enzx.nxgraph.serialization/package.json.meta new file mode 100644 index 0000000..05d09df --- /dev/null +++ b/upm/com.enzx.nxgraph.serialization/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 90d0123f858f4e2db9c4366113113aff +PackageManifestImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/upm/com.enzx.nxgraph/Documentation~/build-and-release.md b/upm/com.enzx.nxgraph/Documentation~/build-and-release.md index 2c72d40..b37756d 100644 --- a/upm/com.enzx.nxgraph/Documentation~/build-and-release.md +++ b/upm/com.enzx.nxgraph/Documentation~/build-and-release.md @@ -2,6 +2,15 @@ Staging is driven by the C# build system (`NxGraph.Build`, Bullseye targets). Run all commands from the repository root (`NxGraph_Code`). +The repository produces **two** UPM packages: + +| Package | Contents | Staging modes | +| --- | --- | --- | +| `com.enzx.nxgraph` | The core library, plus the dependency-free `NxGraph.Serialization.Abstraction`. | source or binary | +| `com.enzx.nxgraph.serialization` | `NxGraph.Serialization` and its bundled third-party dependencies. | binary only | + +They share a version and are released together; the serialization package pins its dependency on the core to that exact version. + ## Source-based staging ```bash @@ -27,6 +36,8 @@ Source staging copies: It excludes `Fsm/TracingObserver.cs` from the staged Unity runtime (it is `NET8_0_OR_GREATER` only). +Source mode does not stage the serialization package, and clears it if it was staged before. Source-compiled core code becomes the Unity assembly `NxGraph.Unity.Runtime`, while a prebuilt `NxGraph.Serialization.dll` carries an assembly reference to `NxGraph` — the two cannot bind, so the combination is refused rather than shipped broken. + ## Binary staging If a binary package is needed instead: @@ -35,14 +46,28 @@ If a binary package is needed instead: dotnet run --project NxGraph.Build -- stage-binary ``` -This builds Release and stages the netstandard2.1 `NxGraph.dll` (plus PDB and XML docs) into `Runtime/Plugins`. +This builds `NxGraph.Serialization` for netstandard2.1 — which also builds the core and the abstraction it references — and distributes the output across both packages: + +- `com.enzx.nxgraph/Runtime/Plugins`: `NxGraph` and `NxGraph.Serialization.Abstraction` (each with PDB and XML docs). +- `com.enzx.nxgraph.serialization/Runtime/Plugins`: `NxGraph.Serialization` plus its whole dependency closure. The serialization project sets `CopyLocalLockFileAssemblies` on the netstandard2.1 leg precisely so that closure lands next to the assembly. + +### The `.meta` files are the allowlist + +Staged binaries are gitignored; the `.meta` sidecars beside them are committed. That is deliberate, and two rules follow from it: + +- Staging never deletes a `.meta`. Those files carry the plugin GUIDs Unity uses as reference identity — regenerating one hands every consumer project a new GUID for the same assembly. +- Staging copies only files that already have a `.meta`, and fails if the built set and the sidecar set disagree in either direction. A newly resolved transitive dependency cannot be silently bundled into a shipped package, and a dropped one cannot silently become a `TypeLoadException` at the consumer. The error names the files; the fix is to review the change and add or delete sidecars. ## Release -The `upm-release.yml` workflow (triggered by `upm/v*` tags or manually) runs `ci`, stages the chosen mode, patches `package.json` via `upm-patch-version`, creates the tarball via `upm-tarball`, pushes the package layout to the `upm` branch, and attaches the tarball to a GitHub release. +The `upm-release.yml` workflow (triggered by `upm/v*` tags or manually) runs `ci`, stages the chosen mode, patches both `package.json` files via `upm-patch-version` (pinning the serialization package's dependency on the core), creates the tarballs via `upm-tarball`, publishes each package layout at the root of its own orphan branch — `upm` and `upm-serialization` — and attaches the tarballs to a GitHub release. + +Source-mode releases publish the core alone: one tarball, one branch. ## Important Do not keep both staged source and `NxGraph.dll` in the same package layout, or Unity may see duplicate types. If a target Unity version cannot compile the staged runtime source as-is, prefer the binary package for that environment. + +The serialization package bundles assemblies that other Unity packages commonly ship too (`System.Memory`, `System.Buffers`, `System.Runtime.CompilerServices.Unsafe`, `System.Text.Encodings.Web`, …). That is the accepted cost of a zero-setup install; consumers who hit a duplicate-assembly error resolve it by keeping one copy. diff --git a/upm/com.enzx.nxgraph/Runtime/Plugins/NxGraph.Serialization.Abstraction.dll.meta b/upm/com.enzx.nxgraph/Runtime/Plugins/NxGraph.Serialization.Abstraction.dll.meta new file mode 100644 index 0000000..a11f301 --- /dev/null +++ b/upm/com.enzx.nxgraph/Runtime/Plugins/NxGraph.Serialization.Abstraction.dll.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 09e2f691b6e94a9abeda95307e3fa6b4 diff --git a/upm/com.enzx.nxgraph/Runtime/Plugins/NxGraph.Serialization.Abstraction.pdb.meta b/upm/com.enzx.nxgraph/Runtime/Plugins/NxGraph.Serialization.Abstraction.pdb.meta new file mode 100644 index 0000000..37961ee --- /dev/null +++ b/upm/com.enzx.nxgraph/Runtime/Plugins/NxGraph.Serialization.Abstraction.pdb.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: dbd2f60e217a41d4b19165d468769b65 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/upm/com.enzx.nxgraph/Runtime/Plugins/NxGraph.Serialization.Abstraction.xml.meta b/upm/com.enzx.nxgraph/Runtime/Plugins/NxGraph.Serialization.Abstraction.xml.meta new file mode 100644 index 0000000..c3ffee3 --- /dev/null +++ b/upm/com.enzx.nxgraph/Runtime/Plugins/NxGraph.Serialization.Abstraction.xml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c294d10c17c947d4970d4af31ce80b3f +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/upm/com.enzx.nxgraph/Runtime/Plugins/NxGraph.xml.meta b/upm/com.enzx.nxgraph/Runtime/Plugins/NxGraph.xml.meta new file mode 100644 index 0000000..c0989da --- /dev/null +++ b/upm/com.enzx.nxgraph/Runtime/Plugins/NxGraph.xml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1ab6b104dc5545f5b512169072597de1 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: