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: