diff --git a/.gitignore b/.gitignore index ac9c49142..2461b9473 100644 --- a/.gitignore +++ b/.gitignore @@ -95,6 +95,7 @@ Packages/packages-lock.json GameData/run.cc GameData/player.cc GameData/RemovedMods/ +Vault/Aetheria/.obsidian/plugins/copilot/data.json # Agent scratch, sandboxed toolchain caches, and throwaway checkouts. These had # grown to 47 untracked entries; the worktree must stay legible, so they never diff --git a/.lfsconfig b/.lfsconfig deleted file mode 100644 index d9ce439fc..000000000 --- a/.lfsconfig +++ /dev/null @@ -1,2 +0,0 @@ -[lfs] - url = https://eureka.gamecult.org/forge/GameCult/Aetheria.git/info/lfs diff --git a/Assets/Editor/AetheriaBuild.cs b/Assets/Editor/AetheriaBuild.cs index 3cf434ee4..7d3c891d2 100644 --- a/Assets/Editor/AetheriaBuild.cs +++ b/Assets/Editor/AetheriaBuild.cs @@ -8,12 +8,12 @@ using UnityEditor.AddressableAssets.Settings; using UnityEditor.Build.Reporting; using Debug = UnityEngine.Debug; -// The one way to make a player directory, for Windows or Linux. Owns what the directory contains: the player and its data, +// The one way to make a Win64 player directory. Owns what the directory contains: Aetheria.exe and its data, // GameData/Aetheria.cc, GameData/Narrative/**, GameData/Mods/** and ModTools/AetherDb. Manual builds, smokes and // release cuts all call this and stage nothing themselves. // // Unity -batchmode -quit -projectPath -executeMethod AetheriaBuild.Build -// -aetheriaVersion -aetheriaOut [-aetheriaTarget win64|linux64] -logFile +// -aetheriaVersion -aetheriaOut -logFile // // AetherDb is published from tools/AetherDb, so the headless build's CULTLIB_ROOT / CULTMATH_ROOT (Directory.Build.props) // must be set for dotnet when the defaults do not hold the pinned revisions. @@ -22,14 +22,6 @@ public static class AetheriaBuild { private static readonly Regex SemVer = new Regex(@"^\d+\.\d+\.\d+([-+][0-9A-Za-z.-]+)?$"); - // A target: the player Unity builds, its executable, and the runtime AetherDb is published for. - private static (BuildTarget target, string player, string runtime, string aetherDb) Target(string name) => name switch - { - "win64" => (BuildTarget.StandaloneWindows64, "Aetheria.exe", "win-x64", "AetherDb.exe"), - "linux64" => (BuildTarget.StandaloneLinux64, "Aetheria.x86_64", "linux-x64", "AetherDb"), - _ => throw new InvalidOperationException($"-aetheriaTarget {name}: expected win64 or linux64"), - }; - public static void Build() { var step = "arguments"; @@ -38,7 +30,6 @@ public static class AetheriaBuild var version = Argument("-aetheriaVersion"); if (!SemVer.IsMatch(version)) throw new InvalidOperationException("-aetheriaVersion is not a semver"); var output = Path.GetFullPath(Argument("-aetheriaOut")); - var target = Target(Argument("-aetheriaTarget", "win64")); var repoRoot = Directory.GetParent(UnityEngine.Application.dataPath).FullName; step = "version"; @@ -55,8 +46,8 @@ public static class AetheriaBuild var report = BuildPipeline.BuildPlayer(new BuildPlayerOptions { scenes = scenes, - locationPathName = Path.Combine(output, target.player), - target = target.target, + locationPathName = Path.Combine(output, "Aetheria.exe"), + target = BuildTarget.StandaloneWindows64, options = BuildOptions.None, }); if (report.summary.result != BuildResult.Succeeded || report.summary.totalErrors != 0) @@ -66,7 +57,7 @@ public static class AetheriaBuild PlayerStaging.Stage(repoRoot, output); step = "aetherdb"; - Publish(repoRoot, Path.Combine(output, "ModTools"), target.runtime, target.aetherDb); + Publish(repoRoot, Path.Combine(output, "ModTools")); step = "burst"; var burst = Path.Combine(output, "Aetheria_BurstDebugInformation_DoNotShip"); @@ -83,11 +74,11 @@ public static class AetheriaBuild EditorApplication.Exit(0); } - private static void Publish(string repoRoot, string modTools, string runtime, string aetherDb) + private static void Publish(string repoRoot, string modTools) { var info = new ProcessStartInfo("dotnet") { - Arguments = $"publish tools/AetherDb -c Release -r {runtime} --self-contained -p:PublishSingleFile=true -o \"{modTools}\"", + Arguments = $"publish tools/AetherDb -c Release -r win-x64 --self-contained -p:PublishSingleFile=true -o \"{modTools}\"", WorkingDirectory = repoRoot, UseShellExecute = false, RedirectStandardOutput = true, @@ -101,16 +92,15 @@ public static class AetheriaBuild if (process.ExitCode != 0) throw new InvalidOperationException($"dotnet publish exited {process.ExitCode}:\n{text}\n{errors.Result}"); } - if (!File.Exists(Path.Combine(modTools, aetherDb))) - throw new InvalidOperationException($"dotnet publish produced no ModTools/{aetherDb}"); + if (!File.Exists(Path.Combine(modTools, "AetherDb.exe"))) + throw new InvalidOperationException("dotnet publish produced no ModTools/AetherDb.exe"); } - private static string Argument(string name, string fallback = null) + private static string Argument(string name) { var args = Environment.GetCommandLineArgs(); var at = Array.IndexOf(args, name); - if (at < 0 || at + 1 >= args.Length) - return fallback ?? throw new InvalidOperationException(name + " is required"); + if (at < 0 || at + 1 >= args.Length) throw new InvalidOperationException(name + " is required"); return args[at + 1]; } } diff --git a/Assets/Plugins/GPU Noise/ClassicNoise2D.cginc b/Assets/Plugins/GPU Noise/ClassicNoise2D.cginc new file mode 100644 index 000000000..ef6b2e96c --- /dev/null +++ b/Assets/Plugins/GPU Noise/ClassicNoise2D.cginc @@ -0,0 +1,129 @@ +// +// Noise Shader Library for Unity - https://github.com/keijiro/NoiseShader +// +// Original work (webgl-noise) Copyright (C) 2011 Stefan Gustavson +// Translation and modification was made by Keijiro Takahashi. +// +// This shader is based on the webgl-noise GLSL shader. For further details +// of the original shader, please see the following description from the +// original source code. +// + +// +// GLSL textureless classic 2D noise "cnoise", +// with an RSL-style periodic variant "pnoise". +// Author: Stefan Gustavson (stefan.gustavson@liu.se) +// Version: 2011-08-22 +// +// Many thanks to Ian McEwan of Ashima Arts for the +// ideas for permutation and gradient selection. +// +// Copyright (c) 2011 Stefan Gustavson. All rights reserved. +// Distributed under the MIT license. See LICENSE file. +// https://github.com/ashima/webgl-noise +// + +float4 mod(float4 x, float4 y) +{ + return x - y * floor(x / y); +} + +float4 mod289(float4 x) +{ + return x - floor(x / 289.0) * 289.0; +} + +float4 permute(float4 x) +{ + return mod289(((x*34.0)+1.0)*x); +} + +float4 taylorInvSqrt(float4 r) +{ + return (float4)1.79284291400159 - r * 0.85373472095314; +} + +float2 fade(float2 t) { + return t*t*t*(t*(t*6.0-15.0)+10.0); +} + +// Classic Perlin noise +float cnoise(float2 P) +{ + float4 Pi = floor(P.xyxy) + float4(0.0, 0.0, 1.0, 1.0); + float4 Pf = frac (P.xyxy) - float4(0.0, 0.0, 1.0, 1.0); + Pi = mod289(Pi); // To avoid truncation effects in permutation + float4 ix = Pi.xzxz; + float4 iy = Pi.yyww; + float4 fx = Pf.xzxz; + float4 fy = Pf.yyww; + + float4 i = permute(permute(ix) + iy); + + float4 gx = frac(i / 41.0) * 2.0 - 1.0 ; + float4 gy = abs(gx) - 0.5 ; + float4 tx = floor(gx + 0.5); + gx = gx - tx; + + float2 g00 = float2(gx.x,gy.x); + float2 g10 = float2(gx.y,gy.y); + float2 g01 = float2(gx.z,gy.z); + float2 g11 = float2(gx.w,gy.w); + + float4 norm = taylorInvSqrt(float4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); + g00 *= norm.x; + g01 *= norm.y; + g10 *= norm.z; + g11 *= norm.w; + + float n00 = dot(g00, float2(fx.x, fy.x)); + float n10 = dot(g10, float2(fx.y, fy.y)); + float n01 = dot(g01, float2(fx.z, fy.z)); + float n11 = dot(g11, float2(fx.w, fy.w)); + + float2 fade_xy = fade(Pf.xy); + float2 n_x = lerp(float2(n00, n01), float2(n10, n11), fade_xy.x); + float n_xy = lerp(n_x.x, n_x.y, fade_xy.y); + return 2.3 * n_xy; +} + +// Classic Perlin noise, periodic variant +float pnoise(float2 P, float2 rep) +{ + float4 Pi = floor(P.xyxy) + float4(0.0, 0.0, 1.0, 1.0); + float4 Pf = frac (P.xyxy) - float4(0.0, 0.0, 1.0, 1.0); + Pi = mod(Pi, rep.xyxy); // To create noise with explicit period + Pi = mod289(Pi); // To avoid truncation effects in permutation + float4 ix = Pi.xzxz; + float4 iy = Pi.yyww; + float4 fx = Pf.xzxz; + float4 fy = Pf.yyww; + + float4 i = permute(permute(ix) + iy); + + float4 gx = frac(i / 41.0) * 2.0 - 1.0 ; + float4 gy = abs(gx) - 0.5 ; + float4 tx = floor(gx + 0.5); + gx = gx - tx; + + float2 g00 = float2(gx.x,gy.x); + float2 g10 = float2(gx.y,gy.y); + float2 g01 = float2(gx.z,gy.z); + float2 g11 = float2(gx.w,gy.w); + + float4 norm = taylorInvSqrt(float4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); + g00 *= norm.x; + g01 *= norm.y; + g10 *= norm.z; + g11 *= norm.w; + + float n00 = dot(g00, float2(fx.x, fy.x)); + float n10 = dot(g10, float2(fx.y, fy.y)); + float n01 = dot(g01, float2(fx.z, fy.z)); + float n11 = dot(g11, float2(fx.w, fy.w)); + + float2 fade_xy = fade(Pf.xy); + float2 n_x = lerp(float2(n00, n01), float2(n10, n11), fade_xy.x); + float n_xy = lerp(n_x.x, n_x.y, fade_xy.y); + return 2.3 * n_xy; +} diff --git a/Assets/Plugins/GPU Noise/ClassicNoise2D.cginc.meta b/Assets/Plugins/GPU Noise/ClassicNoise2D.cginc.meta new file mode 100644 index 000000000..ff437e70a --- /dev/null +++ b/Assets/Plugins/GPU Noise/ClassicNoise2D.cginc.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: e1b0b5fd6a4e44923b40d856017562e1 +ShaderImporter: + defaultTextures: [] + userData: diff --git a/Assets/Plugins/GPU Noise/ClassicNoise3D.cginc b/Assets/Plugins/GPU Noise/ClassicNoise3D.cginc new file mode 100644 index 000000000..738f6d12a --- /dev/null +++ b/Assets/Plugins/GPU Noise/ClassicNoise3D.cginc @@ -0,0 +1,194 @@ +// +// Noise Shader Library for Unity - https://github.com/keijiro/NoiseShader +// +// Original work (webgl-noise) Copyright (C) 2011 Stefan Gustavson +// Translation and modification was made by Keijiro Takahashi. +// +// This shader is based on the webgl-noise GLSL shader. For further details +// of the original shader, please see the following description from the +// original source code. +// + +// +// GLSL textureless classic 3D noise "cnoise", +// with an RSL-style periodic variant "pnoise". +// Author: Stefan Gustavson (stefan.gustavson@liu.se) +// Version: 2011-10-11 +// +// Many thanks to Ian McEwan of Ashima Arts for the +// ideas for permutation and gradient selection. +// +// Copyright (c) 2011 Stefan Gustavson. All rights reserved. +// Distributed under the MIT license. See LICENSE file. +// https://github.com/ashima/webgl-noise +// + +float3 mod(float3 x, float3 y) +{ + return x - y * floor(x / y); +} + +float3 mod289(float3 x) +{ + return x - floor(x / 289.0) * 289.0; +} + +float4 mod289(float4 x) +{ + return x - floor(x / 289.0) * 289.0; +} + +float4 permute(float4 x) +{ + return mod289(((x*34.0)+1.0)*x); +} + +float4 taylorInvSqrt(float4 r) +{ + return (float4)1.79284291400159 - r * 0.85373472095314; +} + +float3 fade(float3 t) { + return t*t*t*(t*(t*6.0-15.0)+10.0); +} + +// Classic Perlin noise +float cnoise(float3 P) +{ + float3 Pi0 = floor(P); // Integer part for indexing + float3 Pi1 = Pi0 + (float3)1.0; // Integer part + 1 + Pi0 = mod289(Pi0); + Pi1 = mod289(Pi1); + float3 Pf0 = frac(P); // Fractional part for interpolation + float3 Pf1 = Pf0 - (float3)1.0; // Fractional part - 1.0 + float4 ix = float4(Pi0.x, Pi1.x, Pi0.x, Pi1.x); + float4 iy = float4(Pi0.y, Pi0.y, Pi1.y, Pi1.y); + float4 iz0 = (float4)Pi0.z; + float4 iz1 = (float4)Pi1.z; + + float4 ixy = permute(permute(ix) + iy); + float4 ixy0 = permute(ixy + iz0); + float4 ixy1 = permute(ixy + iz1); + + float4 gx0 = ixy0 / 7.0; + float4 gy0 = frac(floor(gx0) / 7.0) - 0.5; + gx0 = frac(gx0); + float4 gz0 = (float4)0.5 - abs(gx0) - abs(gy0); + float4 sz0 = step(gz0, (float4)0.0); + gx0 -= sz0 * (step((float4)0.0, gx0) - 0.5); + gy0 -= sz0 * (step((float4)0.0, gy0) - 0.5); + + float4 gx1 = ixy1 / 7.0; + float4 gy1 = frac(floor(gx1) / 7.0) - 0.5; + gx1 = frac(gx1); + float4 gz1 = (float4)0.5 - abs(gx1) - abs(gy1); + float4 sz1 = step(gz1, (float4)0.0); + gx1 -= sz1 * (step((float4)0.0, gx1) - 0.5); + gy1 -= sz1 * (step((float4)0.0, gy1) - 0.5); + + float3 g000 = float3(gx0.x,gy0.x,gz0.x); + float3 g100 = float3(gx0.y,gy0.y,gz0.y); + float3 g010 = float3(gx0.z,gy0.z,gz0.z); + float3 g110 = float3(gx0.w,gy0.w,gz0.w); + float3 g001 = float3(gx1.x,gy1.x,gz1.x); + float3 g101 = float3(gx1.y,gy1.y,gz1.y); + float3 g011 = float3(gx1.z,gy1.z,gz1.z); + float3 g111 = float3(gx1.w,gy1.w,gz1.w); + + float4 norm0 = taylorInvSqrt(float4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); + g000 *= norm0.x; + g010 *= norm0.y; + g100 *= norm0.z; + g110 *= norm0.w; + + float4 norm1 = taylorInvSqrt(float4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); + g001 *= norm1.x; + g011 *= norm1.y; + g101 *= norm1.z; + g111 *= norm1.w; + + float n000 = dot(g000, Pf0); + float n100 = dot(g100, float3(Pf1.x, Pf0.y, Pf0.z)); + float n010 = dot(g010, float3(Pf0.x, Pf1.y, Pf0.z)); + float n110 = dot(g110, float3(Pf1.x, Pf1.y, Pf0.z)); + float n001 = dot(g001, float3(Pf0.x, Pf0.y, Pf1.z)); + float n101 = dot(g101, float3(Pf1.x, Pf0.y, Pf1.z)); + float n011 = dot(g011, float3(Pf0.x, Pf1.y, Pf1.z)); + float n111 = dot(g111, Pf1); + + float3 fade_xyz = fade(Pf0); + float4 n_z = lerp(float4(n000, n100, n010, n110), float4(n001, n101, n011, n111), fade_xyz.z); + float2 n_yz = lerp(n_z.xy, n_z.zw, fade_xyz.y); + float n_xyz = lerp(n_yz.x, n_yz.y, fade_xyz.x); + return 2.2 * n_xyz; +} + +// Classic Perlin noise, periodic variant +float pnoise(float3 P, float3 rep) +{ + float3 Pi0 = mod(floor(P), rep); // Integer part, modulo period + float3 Pi1 = mod(Pi0 + (float3)1.0, rep); // Integer part + 1, mod period + Pi0 = mod289(Pi0); + Pi1 = mod289(Pi1); + float3 Pf0 = frac(P); // Fractional part for interpolation + float3 Pf1 = Pf0 - (float3)1.0; // Fractional part - 1.0 + float4 ix = float4(Pi0.x, Pi1.x, Pi0.x, Pi1.x); + float4 iy = float4(Pi0.y, Pi0.y, Pi1.y, Pi1.y); + float4 iz0 = (float4)Pi0.z; + float4 iz1 = (float4)Pi1.z; + + float4 ixy = permute(permute(ix) + iy); + float4 ixy0 = permute(ixy + iz0); + float4 ixy1 = permute(ixy + iz1); + + float4 gx0 = ixy0 / 7.0; + float4 gy0 = frac(floor(gx0) / 7.0) - 0.5; + gx0 = frac(gx0); + float4 gz0 = (float4)0.5 - abs(gx0) - abs(gy0); + float4 sz0 = step(gz0, (float4)0.0); + gx0 -= sz0 * (step((float4)0.0, gx0) - 0.5); + gy0 -= sz0 * (step((float4)0.0, gy0) - 0.5); + + float4 gx1 = ixy1 / 7.0; + float4 gy1 = frac(floor(gx1) / 7.0) - 0.5; + gx1 = frac(gx1); + float4 gz1 = (float4)0.5 - abs(gx1) - abs(gy1); + float4 sz1 = step(gz1, (float4)0.0); + gx1 -= sz1 * (step((float4)0.0, gx1) - 0.5); + gy1 -= sz1 * (step((float4)0.0, gy1) - 0.5); + + float3 g000 = float3(gx0.x,gy0.x,gz0.x); + float3 g100 = float3(gx0.y,gy0.y,gz0.y); + float3 g010 = float3(gx0.z,gy0.z,gz0.z); + float3 g110 = float3(gx0.w,gy0.w,gz0.w); + float3 g001 = float3(gx1.x,gy1.x,gz1.x); + float3 g101 = float3(gx1.y,gy1.y,gz1.y); + float3 g011 = float3(gx1.z,gy1.z,gz1.z); + float3 g111 = float3(gx1.w,gy1.w,gz1.w); + + float4 norm0 = taylorInvSqrt(float4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); + g000 *= norm0.x; + g010 *= norm0.y; + g100 *= norm0.z; + g110 *= norm0.w; + float4 norm1 = taylorInvSqrt(float4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); + g001 *= norm1.x; + g011 *= norm1.y; + g101 *= norm1.z; + g111 *= norm1.w; + + float n000 = dot(g000, Pf0); + float n100 = dot(g100, float3(Pf1.x, Pf0.y, Pf0.z)); + float n010 = dot(g010, float3(Pf0.x, Pf1.y, Pf0.z)); + float n110 = dot(g110, float3(Pf1.x, Pf1.y, Pf0.z)); + float n001 = dot(g001, float3(Pf0.x, Pf0.y, Pf1.z)); + float n101 = dot(g101, float3(Pf1.x, Pf0.y, Pf1.z)); + float n011 = dot(g011, float3(Pf0.x, Pf1.y, Pf1.z)); + float n111 = dot(g111, Pf1); + + float3 fade_xyz = fade(Pf0); + float4 n_z = lerp(float4(n000, n100, n010, n110), float4(n001, n101, n011, n111), fade_xyz.z); + float2 n_yz = lerp(n_z.xy, n_z.zw, fade_xyz.y); + float n_xyz = lerp(n_yz.x, n_yz.y, fade_xyz.x); + return 2.2 * n_xyz; +} diff --git a/Assets/Plugins/GPU Noise/ClassicNoise3D.cginc.meta b/Assets/Plugins/GPU Noise/ClassicNoise3D.cginc.meta new file mode 100644 index 000000000..b4dd551ab --- /dev/null +++ b/Assets/Plugins/GPU Noise/ClassicNoise3D.cginc.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 3ba1abd1cb44c47b68fbb577c6c4ba3e +ShaderImporter: + defaultTextures: [] + userData: diff --git a/Assets/Plugins/GPU Noise/SimplexNoise3D.cginc b/Assets/Plugins/GPU Noise/SimplexNoise3D.cginc new file mode 100644 index 000000000..0b7add240 --- /dev/null +++ b/Assets/Plugins/GPU Noise/SimplexNoise3D.cginc @@ -0,0 +1,114 @@ +// +// Noise Shader Library for Unity - https://github.com/keijiro/NoiseShader +// +// Original work (webgl-noise) Copyright (C) 2011 Ashima Arts. +// Translation and modification was made by Keijiro Takahashi. +// +// This shader is based on the webgl-noise GLSL shader. For further details +// of the original shader, please see the following description from the +// original source code. +// + +// +// Description : Array and textureless GLSL 2D/3D/4D simplex +// noise functions. +// Author : Ian McEwan, Ashima Arts. +// Maintainer : ijm +// Lastmod : 20110822 (ijm) +// License : Copyright (C) 2011 Ashima Arts. All rights reserved. +// Distributed under the MIT License. See LICENSE file. +// https://github.com/ashima/webgl-noise +// + +float3 mod289(float3 x) +{ + return x - floor(x / 289.0) * 289.0; +} + +float4 mod289(float4 x) +{ + return x - floor(x / 289.0) * 289.0; +} + +float4 permute(float4 x) +{ + return mod289((x * 34.0 + 1.0) * x); +} + +float4 taylorInvSqrt(float4 r) +{ + return 1.79284291400159 - r * 0.85373472095314; +} + +float snoise(float3 v) +{ + const float2 C = float2(1.0 / 6.0, 1.0 / 3.0); + + // First corner + float3 i = floor(v + dot(v, C.yyy)); + float3 x0 = v - i + dot(i, C.xxx); + + // Other corners + float3 g = step(x0.yzx, x0.xyz); + float3 l = 1.0 - g; + float3 i1 = min(g.xyz, l.zxy); + float3 i2 = max(g.xyz, l.zxy); + + // x1 = x0 - i1 + 1.0 * C.xxx; + // x2 = x0 - i2 + 2.0 * C.xxx; + // x3 = x0 - 1.0 + 3.0 * C.xxx; + float3 x1 = x0 - i1 + C.xxx; + float3 x2 = x0 - i2 + C.yyy; + float3 x3 = x0 - 0.5; + + // Permutations + i = mod289(i); // Avoid truncation effects in permutation + float4 p = + permute(permute(permute(i.z + float4(0.0, i1.z, i2.z, 1.0)) + + i.y + float4(0.0, i1.y, i2.y, 1.0)) + + i.x + float4(0.0, i1.x, i2.x, 1.0)); + + // Gradients: 7x7 points over a square, mapped onto an octahedron. + // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) + float4 j = p - 49.0 * floor(p / 49.0); // mod(p,7*7) + + float4 x_ = floor(j / 7.0); + float4 y_ = floor(j - 7.0 * x_); // mod(j,N) + + float4 x = (x_ * 2.0 + 0.5) / 7.0 - 1.0; + float4 y = (y_ * 2.0 + 0.5) / 7.0 - 1.0; + + float4 h = 1.0 - abs(x) - abs(y); + + float4 b0 = float4(x.xy, y.xy); + float4 b1 = float4(x.zw, y.zw); + + //float4 s0 = float4(lessThan(b0, 0.0)) * 2.0 - 1.0; + //float4 s1 = float4(lessThan(b1, 0.0)) * 2.0 - 1.0; + float4 s0 = floor(b0) * 2.0 + 1.0; + float4 s1 = floor(b1) * 2.0 + 1.0; + float4 sh = -step(h, 0.0); + + float4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; + float4 a1 = b1.xzyw + s1.xzyw * sh.zzww; + + float3 g0 = float3(a0.xy, h.x); + float3 g1 = float3(a0.zw, h.y); + float3 g2 = float3(a1.xy, h.z); + float3 g3 = float3(a1.zw, h.w); + + // Normalise gradients + float4 norm = taylorInvSqrt(float4(dot(g0, g0), dot(g1, g1), dot(g2, g2), dot(g3, g3))); + g0 *= norm.x; + g1 *= norm.y; + g2 *= norm.z; + g3 *= norm.w; + + // Mix final noise value + float4 m = max(0.6 - float4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0); + m = m * m; + m = m * m; + + float4 px = float4(dot(x0, g0), dot(x1, g1), dot(x2, g2), dot(x3, g3)); + return 42.0 * dot(m, px); +} diff --git a/Assets/Plugins/GPU Noise/SimplexNoise3D.cginc.meta b/Assets/Plugins/GPU Noise/SimplexNoise3D.cginc.meta new file mode 100644 index 000000000..612bd9ef0 --- /dev/null +++ b/Assets/Plugins/GPU Noise/SimplexNoise3D.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: b577a94f58a1398409bfcfe9cd5dbf99 +timeCreated: 1448788105 +licenseType: Pro +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/GPU Noise/SimplexNoiseGrad3D.cginc b/Assets/Plugins/GPU Noise/SimplexNoiseGrad3D.cginc new file mode 100644 index 000000000..4cfef835a --- /dev/null +++ b/Assets/Plugins/GPU Noise/SimplexNoiseGrad3D.cginc @@ -0,0 +1,118 @@ +// +// Noise Shader Library for Unity - https://github.com/keijiro/NoiseShader +// +// Original work (webgl-noise) Copyright (C) 2011 Ashima Arts. +// Translation and modification was made by Keijiro Takahashi. +// +// This shader is based on the webgl-noise GLSL shader. For further details +// of the original shader, please see the following description from the +// original source code. +// + +// +// Description : Array and textureless GLSL 2D/3D/4D simplex +// noise functions. +// Author : Ian McEwan, Ashima Arts. +// Maintainer : ijm +// Lastmod : 20110822 (ijm) +// License : Copyright (C) 2011 Ashima Arts. All rights reserved. +// Distributed under the MIT License. See LICENSE file. +// https://github.com/ashima/webgl-noise +// + +float3 mod289(float3 x) +{ + return x - floor(x / 289.0) * 289.0; +} + +float4 mod289(float4 x) +{ + return x - floor(x / 289.0) * 289.0; +} + +float4 permute(float4 x) +{ + return mod289((x * 34.0 + 1.0) * x); +} + +float4 taylorInvSqrt(float4 r) +{ + return 1.79284291400159 - r * 0.85373472095314; +} + +float3 snoise_grad(float3 v) +{ + const float2 C = float2(1.0 / 6.0, 1.0 / 3.0); + + // First corner + float3 i = floor(v + dot(v, C.yyy)); + float3 x0 = v - i + dot(i, C.xxx); + + // Other corners + float3 g = step(x0.yzx, x0.xyz); + float3 l = 1.0 - g; + float3 i1 = min(g.xyz, l.zxy); + float3 i2 = max(g.xyz, l.zxy); + + // x1 = x0 - i1 + 1.0 * C.xxx; + // x2 = x0 - i2 + 2.0 * C.xxx; + // x3 = x0 - 1.0 + 3.0 * C.xxx; + float3 x1 = x0 - i1 + C.xxx; + float3 x2 = x0 - i2 + C.yyy; + float3 x3 = x0 - 0.5; + + // Permutations + i = mod289(i); // Avoid truncation effects in permutation + float4 p = + permute(permute(permute(i.z + float4(0.0, i1.z, i2.z, 1.0)) + + i.y + float4(0.0, i1.y, i2.y, 1.0)) + + i.x + float4(0.0, i1.x, i2.x, 1.0)); + + // Gradients: 7x7 points over a square, mapped onto an octahedron. + // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) + float4 j = p - 49.0 * floor(p / 49.0); // mod(p,7*7) + + float4 x_ = floor(j / 7.0); + float4 y_ = floor(j - 7.0 * x_); // mod(j,N) + + float4 x = (x_ * 2.0 + 0.5) / 7.0 - 1.0; + float4 y = (y_ * 2.0 + 0.5) / 7.0 - 1.0; + + float4 h = 1.0 - abs(x) - abs(y); + + float4 b0 = float4(x.xy, y.xy); + float4 b1 = float4(x.zw, y.zw); + + //float4 s0 = float4(lessThan(b0, 0.0)) * 2.0 - 1.0; + //float4 s1 = float4(lessThan(b1, 0.0)) * 2.0 - 1.0; + float4 s0 = floor(b0) * 2.0 + 1.0; + float4 s1 = floor(b1) * 2.0 + 1.0; + float4 sh = -step(h, 0.0); + + float4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; + float4 a1 = b1.xzyw + s1.xzyw * sh.zzww; + + float3 g0 = float3(a0.xy, h.x); + float3 g1 = float3(a0.zw, h.y); + float3 g2 = float3(a1.xy, h.z); + float3 g3 = float3(a1.zw, h.w); + + // Normalise gradients + float4 norm = taylorInvSqrt(float4(dot(g0, g0), dot(g1, g1), dot(g2, g2), dot(g3, g3))); + g0 *= norm.x; + g1 *= norm.y; + g2 *= norm.z; + g3 *= norm.w; + + // Compute gradient of noise function at P + float4 m = max(0.6 - float4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0); + float4 m2 = m * m; + float4 m3 = m2 * m; + float4 m4 = m2 * m2; + float3 grad = + -6.0 * m3.x * x0 * dot(x0, g0) + m4.x * g0 + + -6.0 * m3.y * x1 * dot(x1, g1) + m4.y * g1 + + -6.0 * m3.z * x2 * dot(x2, g2) + m4.z * g2 + + -6.0 * m3.w * x3 * dot(x3, g3) + m4.w * g3; + return 42.0 * grad; +} diff --git a/Assets/Plugins/GPU Noise/SimplexNoiseGrad3D.cginc.meta b/Assets/Plugins/GPU Noise/SimplexNoiseGrad3D.cginc.meta new file mode 100644 index 000000000..250b646fa --- /dev/null +++ b/Assets/Plugins/GPU Noise/SimplexNoiseGrad3D.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a7111eafc2463224faacf7be3bddb9a4 +timeCreated: 1449292284 +licenseType: Pro +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Settings.asset b/Assets/Resources/Settings.asset index 46bee7272..f4c21ce13 100644 --- a/Assets/Resources/Settings.asset +++ b/Assets/Resources/Settings.asset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7f09c54dfdb87dffd76fa92365d62c53ce333457b89ccf8ead09093ffffedc42 -size 12525 +oid sha256:95d1ba64331895cc66862010f94a8cd4598ec9dd211a83b14b6091ac948afd56 +size 12327 diff --git a/Assets/Scripts/Editor/BeltFloaterLayerVerify.cs b/Assets/Scripts/Editor/BeltFloaterLayerVerify.cs index 500ae1cea..43153b267 100644 --- a/Assets/Scripts/Editor/BeltFloaterLayerVerify.cs +++ b/Assets/Scripts/Editor/BeltFloaterLayerVerify.cs @@ -122,7 +122,7 @@ namespace Aetheria.EditorTools var cache = AetheriaStores.Open(Path.Combine(_work, "belts.cc"), Path.Combine(_work, "belts-run.cc"), catalogWritable: true); cache.Upsert(new VerseGrammar { Revision = 1 }); cache.FlushAsync().Wait(); - var items = new ItemManager(1u, cache, new ProvenanceLedger(), settings, _ => { }); + var items = new ItemManager(cache, new ProvenanceLedger(), settings, _ => { }); CultRecordKey Orbit(CultRecordKey parent, float distance, float phase, float2 fixedPosition = default) { diff --git a/Assets/Scripts/Editor/CapabilityPresentationSmoke.cs b/Assets/Scripts/Editor/CapabilityPresentationSmoke.cs index 135163e24..fd8f1cffd 100644 --- a/Assets/Scripts/Editor/CapabilityPresentationSmoke.cs +++ b/Assets/Scripts/Editor/CapabilityPresentationSmoke.cs @@ -62,7 +62,7 @@ public static class CapabilityPresentationSmoke cache.FlushAsync().Wait(); var ledger = new ProvenanceLedger(); for (var i = 1; i <= 8; i++) ledger.Lots[i] = new Lot { Origin = new Attributed(), Quality = 1 }; - var items = new ItemManager(1u, cache, ledger, settings, _ => { }); + var items = new ItemManager(cache, ledger, settings, _ => { }); var zone = new Zone(items, new PlanetSettings(), new ZonePack(), new GalaxyZone { Name = "Smoke", Owner = null }, null); var hullRef = items.ItemData.RefOf(items.ItemData.GetByName("Smoke Hull")); var ship = new Ship(items, zone, new EquippableItem { Data = hullRef, Durability = 1000, Lot = 1 }, new EntitySettings()); diff --git a/Assets/Scripts/Editor/DrawnPoseWiringVerify.cs b/Assets/Scripts/Editor/DrawnPoseWiringVerify.cs index 69109a622..c1994ebeb 100644 --- a/Assets/Scripts/Editor/DrawnPoseWiringVerify.cs +++ b/Assets/Scripts/Editor/DrawnPoseWiringVerify.cs @@ -115,7 +115,7 @@ namespace Aetheria.EditorTools cache.Upsert(new SimpleCommodityData { Name = "Wiring Ore", Shape = oneCell, MaxStack = 100 }); cache.FlushAsync().Wait(); var ledger = new ProvenanceLedger(); - var items = new ItemManager(1u, cache, ledger, settings, _ => { }); + var items = new ItemManager(cache, ledger, settings, _ => { }); // A sun and a planet on a moving rail round it, both near the bodies below: the field under a floater changes with the // drawn time, so a presenter that samples it at the step's time, drops it, or reads lead 0 for the height draws a different y. @@ -159,7 +159,7 @@ namespace Aetheria.EditorTools MaxRange = 1e6f, FireRange = 1e6f, CommitTime = 1e5f, ArrivalTime = 2e5f }; var projectile = new GameObject("Wiring Round").AddComponent(); - projectile.Launch(null, zone, shot, new Vector3(0, 0, 0)); + projectile.Launch(zone, shot, new Vector3(0, 0, 0)); yield return null; zone.Update(.5f); diff --git a/Assets/Scripts/Editor/FloatingItemsDrawnSmoke.cs b/Assets/Scripts/Editor/FloatingItemsDrawnSmoke.cs index 742e8aa9d..1caf77b6c 100644 --- a/Assets/Scripts/Editor/FloatingItemsDrawnSmoke.cs +++ b/Assets/Scripts/Editor/FloatingItemsDrawnSmoke.cs @@ -124,7 +124,7 @@ public static class FloatingItemsDrawnSmoke cache.FlushAsync().Wait(); var ledger = new ProvenanceLedger(); for (var i = 1; i <= 8; i++) ledger.Lots[i] = new Lot { Origin = new Attributed(), Quality = 1 }; - var items = new ItemManager(1u, cache, ledger, settings, _ => { }); + var items = new ItemManager(cache, ledger, settings, _ => { }); var zone = new Zone(items, new PlanetSettings(), new ZonePack(), null, null); EquippableItem Make(string name, int lot) => new EquippableItem { diff --git a/Assets/Scripts/Editor/FlowFieldParityVerify.cs b/Assets/Scripts/Editor/FlowFieldParityVerify.cs index 2fa3e5fda..90979f7e8 100644 --- a/Assets/Scripts/Editor/FlowFieldParityVerify.cs +++ b/Assets/Scripts/Editor/FlowFieldParityVerify.cs @@ -106,7 +106,7 @@ namespace Aetheria.EditorTools var cache = AetheriaStores.Open(Path.Combine(work, Guid.NewGuid().ToString("N") + ".cc"), catalogWritable: true); cache.Upsert(new VerseGrammar { Revision = 1 }); cache.FlushAsync().Wait(); - var items = new ItemManager(1u, cache, new ProvenanceLedger(), settings.GameplaySettings, _ => { }); + var items = new ItemManager(cache, new ProvenanceLedger(), settings.GameplaySettings, _ => { }); return new Zone(items, new PlanetSettings { Flow = flow }, new ZonePack { Time = time }, new GalaxyZone { Name = "Parity", Owner = null }, null); } diff --git a/Assets/Scripts/Editor/GravityFieldParityVerify.cs b/Assets/Scripts/Editor/GravityFieldParityVerify.cs index d996d3227..766a58a6f 100644 --- a/Assets/Scripts/Editor/GravityFieldParityVerify.cs +++ b/Assets/Scripts/Editor/GravityFieldParityVerify.cs @@ -154,7 +154,7 @@ namespace Aetheria.EditorTools var cache = AetheriaStores.Open(Path.Combine(work, "catalog.cc"), Path.Combine(work, "run.cc"), catalogWritable: true); cache.Upsert(new VerseGrammar { Revision = 1 }); cache.FlushAsync().Wait(); - var items = new ItemManager(1u, cache, new ProvenanceLedger(), settings.GameplaySettings, _ => { }); + var items = new ItemManager(cache, new ProvenanceLedger(), settings.GameplaySettings, _ => { }); var positions = new List { new Vector2(-130f, 85f), new Vector2(610f, -240f), new Vector2(670f, -270f), new Vector2(1700f, 300f) }; var masses = new List { 14152f, 273.9f, 29.2f, 0f }; var parents = new List { -1, 0, 1, -1 }; diff --git a/Assets/Scripts/Editor/MapBeltPerf.cs b/Assets/Scripts/Editor/MapBeltPerf.cs index ea3eac5c0..edc771a50 100644 --- a/Assets/Scripts/Editor/MapBeltPerf.cs +++ b/Assets/Scripts/Editor/MapBeltPerf.cs @@ -52,7 +52,7 @@ public static class MapBeltPerf Planets = { new CultRecordRef(sunKey), new CultRecordRef(beltKey) }, Radius = 5000f, Mass = 10000f, Time = 0 }; - var items = new ItemManager(1u, cache, new ProvenanceLedger(), settings.GameplaySettings, _ => { }); + var items = new ItemManager(cache, new ProvenanceLedger(), settings.GameplaySettings, _ => { }); var zone = new Zone(items, new PlanetSettings { BodyRadius = new ExponentialCurve(), WellStrength = new ExponentialCurve { Multiplier = 1f, Exponent = 1f }, diff --git a/Assets/Scripts/Editor/MapPresenterSmoke.cs b/Assets/Scripts/Editor/MapPresenterSmoke.cs index cccc4883c..88309c40e 100644 --- a/Assets/Scripts/Editor/MapPresenterSmoke.cs +++ b/Assets/Scripts/Editor/MapPresenterSmoke.cs @@ -115,7 +115,7 @@ public static class MapPresenterSmoke }; var ledger = new ProvenanceLedger(); for (var i = 1; i <= 8; i++) ledger.Lots[i] = new Lot { Origin = new Attributed(), Quality = 1 }; - var items = new ItemManager(1u, cache, ledger, settings.GameplaySettings, _ => { }); + var items = new ItemManager(cache, ledger, settings.GameplaySettings, _ => { }); var zone = new Zone(items, planetSettings, pack, new GalaxyZone { Name = "Smoke", Owner = null }, null); var hullRef = items.ItemData.RefOf(items.ItemData.GetByName("Smoke Hull")); var ship = new Ship(items, zone, new EquippableItem { Data = hullRef, Durability = 1000, Lot = 1 }, new EntitySettings()); diff --git a/Assets/Scripts/Editor/ScenarioPickerCapture.cs b/Assets/Scripts/Editor/ScenarioPickerCapture.cs deleted file mode 100644 index b39dd7a1b..000000000 --- a/Assets/Scripts/Editor/ScenarioPickerCapture.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using UnityEditor; -using UnityEditor.SceneManagement; -using UnityEngine; -using UnityEngine.UI; - -// A render of the New Game screen as the game builds it: the real Main Menu scene's panel prototype, docked and filled -// by ScenarioPicker.Dock and ScenarioPicker.Show with every scenario group, on a plain dark background (the cloud -// backdrop is a play-mode renderer). Writes /Temp/scenario-picker.png at 1920x1080, or the path after -pngOut (Unity empties Temp on exit). -// -// Unity -batchmode -projectPath -executeMethod ScenarioPickerCapture.Run [-pngOut ] -logFile -// -// Needs a GPU device; do not pass -nographics or -quit: Run exits the Editor itself, 0 on success and 1 on any failure. -public static class ScenarioPickerCapture -{ - private const int Width = 1920, Height = 1080; - - public static void Run() - { - try - { - Capture(); - EditorApplication.Exit(0); - } - catch (Exception exception) - { - Debug.LogException(exception); - EditorApplication.Exit(1); - } - } - - // The menu's two panes built the way MainMenu.Start builds them, against the Main Menu scene. - internal static (MainMenu menu, PropertiesPanel list, PropertiesPanel detail) Build() - { - EditorSceneManager.OpenScene("Assets/Scenes/Main Menu.unity", OpenSceneMode.Single); - var menu = UnityEngine.Object.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None)[0]; - menu.PanelPrototype.gameObject.SetActive(false); - var list = menu.PanelPrototype.Instantiate(); - var detail = menu.PanelPrototype.Instantiate(); - // Edit mode runs no Awake, which is what activates each row a panel adds. - list.Awake(); - detail.Awake(); - ScenarioPicker.Dock(detail, list); - return (menu, list, detail); - } - - internal static List<(string label, Scenario[] scenarios)> AllGroups() => new List<(string label, Scenario[] scenarios)> - { - ("modes", Scenarios.Modes), ("development", Scenarios.Development), ("test arenas", Scenarios.Tests) - }; - - private static void Capture() - { - var (menu, list, detail) = Build(); - menu.Dialog.gameObject.SetActive(false); - list.Title.text = MainMenu.TitleSubtitle("new game", "scenarios"); - ScenarioPicker.Show(list, detail, AllGroups(), _ => { }, () => { }, menu.Dialog.Confirm); - list.RefreshValues(); - detail.RefreshValues(); - - var canvas = menu.GetComponentInParent(true).rootCanvas; - var target = new RenderTexture(Width, Height, 24, RenderTextureFormat.ARGB32); - var cameraObject = new GameObject("ScenarioPickerCapture camera"); - var camera = cameraObject.AddComponent(); - camera.orthographic = true; - camera.orthographicSize = 5; - camera.clearFlags = CameraClearFlags.SolidColor; - camera.backgroundColor = new Color(.04f, .05f, .08f); - camera.cullingMask = 1 << LayerMask.NameToLayer("UI"); - camera.targetTexture = target; - canvas.renderMode = RenderMode.ScreenSpaceCamera; - canvas.worldCamera = camera; - canvas.planeDistance = 10; - canvas.gameObject.SetActive(true); - Canvas.ForceUpdateCanvases(); - LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform) list.transform); - LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform) detail.transform); - foreach (var text in list.transform.GetComponentsInChildren()) - text.ForceMeshUpdate(); - Canvas.ForceUpdateCanvases(); - list.Content.GetComponentInParent().onValueChanged.Invoke(Vector2.zero); - camera.Render(); - - var previous = RenderTexture.active; - RenderTexture.active = target; - var read = new Texture2D(Width, Height, TextureFormat.RGBA32, false); - read.ReadPixels(new Rect(0, 0, Width, Height), 0, 0); - RenderTexture.active = previous; - - var background = read.GetPixel(0, 0); - var differing = 0; - foreach (var pixel in read.GetPixels32()) - if (Mathf.Abs(pixel.r / 255f - background.r) + Mathf.Abs(pixel.g / 255f - background.g) + Mathf.Abs(pixel.b / 255f - background.b) > .05f) - differing++; - if (differing < Width * Height / 100) - throw new InvalidOperationException($"The capture is uniform: only {differing} pixels differ from the background."); - - var path = Path.GetFullPath(Path.Combine(Application.dataPath, "..", "Temp", "scenario-picker.png")); - var args = Environment.GetCommandLineArgs(); - var outIndex = Array.IndexOf(args, "-pngOut"); - if (outIndex >= 0) path = Path.GetFullPath(args[outIndex + 1]); - Directory.CreateDirectory(Path.GetDirectoryName(path)); - File.WriteAllBytes(path, read.EncodeToPNG()); - Debug.Log($"[ScenarioPickerCapture] {path} ({differing} of {Width * Height} pixels differ from the background)"); - } -} diff --git a/Assets/Scripts/Editor/ScenarioPickerCapture.cs.meta b/Assets/Scripts/Editor/ScenarioPickerCapture.cs.meta deleted file mode 100644 index ebeb742e8..000000000 --- a/Assets/Scripts/Editor/ScenarioPickerCapture.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 2e79f280179150e4080250c45e07cd69 \ No newline at end of file diff --git a/Assets/Scripts/Editor/ScenarioPickerVerify.cs b/Assets/Scripts/Editor/ScenarioPickerVerify.cs deleted file mode 100644 index 6816cafc9..000000000 --- a/Assets/Scripts/Editor/ScenarioPickerVerify.cs +++ /dev/null @@ -1,265 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using TMPro; -using UnityEditor; -using UnityEngine; -using UnityEngine.EventSystems; -using UnityEngine.UI; - -// The picker's selection and keyboard rules, driven through the events the game delivers: Move and Cancel reach the -// focused Launch button through ExecuteEvents, as the Input System UI module sends them, and a click is Button.onClick. -// -// Unity -batchmode -projectPath -executeMethod ScenarioPickerVerify.Run -logFile -// -// Exits the Editor itself, 0 when every rule holds and 1 on the first that does not. -public static class ScenarioPickerVerify -{ - private sealed class Fake : Scenario - { - private readonly uint _seed; - private readonly bool _ambient; - public Fake(string name, uint seed = 0, bool ambient = true) { Name = name; _seed = seed; _ambient = ambient; } - public override string Name { get; } - public override string Id => Name.ToLowerInvariant(); - public override string Brief => $"brief of {Name}"; - public override uint Seed => _seed; - public override bool Ambient => _ambient; - public override Galaxy Generate(GalaxyStage stage) => throw new NotSupportedException(); - public override void Stage(ScenarioStage stage) => throw new NotSupportedException(); - } - - private sealed class Screen - { - public ScenarioPicker Picker; - public PropertiesPanel List, Detail; - public Button[] Rows; - public Button Back, Launch; - public readonly List Launched = new List(); - public int Backs; - public Scenario[] A, B, C; - } - - public static void Run() - { - try - { - SelectionFollowsClicksAndArrows(); - ArrowsStopAtTheEnds(); - LeftAndRightAreIgnored(); - LaunchIsOnePathAndFocusClears(); - CancelAndBackAreOnePath(); - DetailPaneFollowsSelection(); - OneGroupHasNoSectionLabel(); - LaunchesOnceHoweverItIsReached(); - ArrowingThroughTheRealListKeepsTheSelectionVisible(); - Debug.Log("[ScenarioPickerVerify] ok"); - EditorApplication.Exit(0); - } - catch (Exception exception) - { - Debug.LogException(exception); - EditorApplication.Exit(1); - } - } - - private static void Require(bool condition, string what) - { - if (!condition) throw new InvalidOperationException(what); - } - - private static Screen Build(bool oneGroup = false, bool real = false) - { - var (menu, list, detail) = ScenarioPickerCapture.Build(); - // Build opens the scene afresh, which destroys the previous EventSystem. - var events = new GameObject("verify EventSystem").AddComponent(); - // Edit mode never calls OnEnable, which is what registers an EventSystem as current. - typeof(EventSystem).GetMethod("OnEnable", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Invoke(events, null); - var screen = new Screen - { - List = list, Detail = detail, - A = new Scenario[] { new Fake("Alpha", 7), new Fake("Beta") }, - B = new Scenario[] { new Fake("Gamma", ambient: false) }, - C = new Scenario[] { new Fake("Delta"), new Fake("Echo") } - }; - var groups = real ? ScenarioPickerCapture.AllGroups() : oneGroup - ? new List<(string label, Scenario[] scenarios)> { ("modes", screen.A) } - : new List<(string label, Scenario[] scenarios)> { ("modes", screen.A), ("development", screen.B), ("test arenas", screen.C) }; - // The menu builds a panel while it is inactive and shows it afterwards; the picker must find its scroll all the same. - if (real) list.gameObject.SetActive(false); - screen.Picker = ScenarioPicker.Show(list, detail, groups, screen.Launched.Add, () => screen.Backs++, menu.Dialog.Confirm); - var buttons = list.GetComponentsInChildren(false).Where(button => !button.transform.IsChildOf(detail.transform)).Select(button => button.Button).ToArray(); - screen.Rows = buttons.Take(buttons.Length - 1).ToArray(); - screen.Back = buttons.Last(); - screen.Launch = detail.GetComponentsInChildren