diff --git a/Assets/Luneraria/Editor/Setup/LunePlayerBuild.cs b/Assets/Luneraria/Editor/Setup/LunePlayerBuild.cs new file mode 100644 index 0000000..affa6e7 --- /dev/null +++ b/Assets/Luneraria/Editor/Setup/LunePlayerBuild.cs @@ -0,0 +1,32 @@ +using System.IO; +using UnityEditor; +using UnityEditor.Build.Reporting; +using UnityEngine; + +namespace Luneraria.EditorTools +{ + /// + /// Player builds (U2D). Only macOS is possible on this machine; Windows and Linux need the build + /// modules listed in docs/port/U1.5-UNITY.md. Output goes to Builds/ (ignored by git). + /// Unity -batchmode -projectPath . -executeMethod Luneraria.EditorTools.LunePlayerBuild.BuildMac -logFile - + /// + public static class LunePlayerBuild + { + public static void BuildMac() + { + string path = Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds/macOS/Luneraria.app"); + // CPU and GPU frame timings for the benchmark (FrameTimingManager). + PlayerSettings.enableFrameTimingStats = true; + var options = new BuildPlayerOptions + { + scenes = new[] { LuneWorldBuilder.ScenePath }, + locationPathName = path, + target = BuildTarget.StandaloneOSX, + options = BuildOptions.None, + }; + BuildReport report = BuildPipeline.BuildPlayer(options); + Debug.Log(string.Format("LUNE_BUILD {0}: {1}, {2:0.0} MB, {3:0.0} s", report.summary.result, path, report.summary.totalSize / 1048576.0, report.summary.totalTime.TotalSeconds)); + EditorApplication.Exit(report.summary.result == BuildResult.Succeeded ? 0 : 1); + } + } +} diff --git a/Assets/Luneraria/Editor/Setup/LunePlayerBuild.cs.meta b/Assets/Luneraria/Editor/Setup/LunePlayerBuild.cs.meta new file mode 100644 index 0000000..995bca2 --- /dev/null +++ b/Assets/Luneraria/Editor/Setup/LunePlayerBuild.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 05d92220eeaed4813a610d541ef7bd4f \ No newline at end of file diff --git a/Assets/Luneraria/Settings/Rendering/DefaultVolumeProfile.asset b/Assets/Luneraria/Settings/Rendering/DefaultVolumeProfile.asset index 5393bfe..329fd09 100644 --- a/Assets/Luneraria/Settings/Rendering/DefaultVolumeProfile.asset +++ b/Assets/Luneraria/Settings/Rendering/DefaultVolumeProfile.asset @@ -1,5 +1,560 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: +--- !u!114 &-8123393559496137545 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 11500000, guid: 66f335fb1ffd8684294ad653bf1c7564, type: 3} + m_Name: ColorAdjustments + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.ColorAdjustments + active: 1 + postExposure: + m_OverrideState: 1 + m_Value: 0 + contrast: + m_OverrideState: 1 + m_Value: 0 + colorFilter: + m_OverrideState: 1 + m_Value: {r: 1, g: 1, b: 1, a: 1} + hueShift: + m_OverrideState: 1 + m_Value: 0 + saturation: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &-7655542585027984839 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 11500000, guid: c5e1dc532bcb41949b58bc4f2abfbb7e, type: 3} + m_Name: LensDistortion + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.LensDistortion + active: 1 + intensity: + m_OverrideState: 1 + m_Value: 0 + xMultiplier: + m_OverrideState: 1 + m_Value: 1 + yMultiplier: + m_OverrideState: 1 + m_Value: 1 + center: + m_OverrideState: 1 + m_Value: {x: 0.5, y: 0.5} + scale: + m_OverrideState: 1 + m_Value: 1 +--- !u!114 &-7615108799411823199 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 11500000, guid: 3eb4b772797da9440885e8bd939e9560, type: 3} + m_Name: ColorCurves + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.ColorCurves + active: 1 + master: + m_OverrideState: 1 + m_Value: + k__BackingField: 2 + m_Loop: 0 + m_ZeroValue: 0 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + red: + m_OverrideState: 1 + m_Value: + k__BackingField: 2 + m_Loop: 0 + m_ZeroValue: 0 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + green: + m_OverrideState: 1 + m_Value: + k__BackingField: 2 + m_Loop: 0 + m_ZeroValue: 0 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + blue: + m_OverrideState: 1 + m_Value: + k__BackingField: 2 + m_Loop: 0 + m_ZeroValue: 0 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + hueVsHue: + m_OverrideState: 1 + m_Value: + k__BackingField: 0 + m_Loop: 1 + m_ZeroValue: 0.5 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + hueVsSat: + m_OverrideState: 1 + m_Value: + k__BackingField: 0 + m_Loop: 1 + m_ZeroValue: 0.5 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + satVsSat: + m_OverrideState: 1 + m_Value: + k__BackingField: 0 + m_Loop: 0 + m_ZeroValue: 0.5 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + lumVsSat: + m_OverrideState: 1 + m_Value: + k__BackingField: 0 + m_Loop: 0 + m_ZeroValue: 0.5 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 +--- !u!114 &-7576830524726348909 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 11500000, guid: c01700fd266d6914ababb731e09af2eb, type: 3} + m_Name: DepthOfField + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.DepthOfField + active: 1 + mode: + m_OverrideState: 1 + m_Value: 0 + gaussianStart: + m_OverrideState: 1 + m_Value: 10 + gaussianEnd: + m_OverrideState: 1 + m_Value: 30 + gaussianMaxRadius: + m_OverrideState: 1 + m_Value: 1 + highQualitySampling: + m_OverrideState: 1 + m_Value: 0 + focusDistance: + m_OverrideState: 1 + m_Value: 10 + aperture: + m_OverrideState: 1 + m_Value: 5.6 + focalLength: + m_OverrideState: 1 + m_Value: 50 + bladeCount: + m_OverrideState: 1 + m_Value: 5 + bladeCurvature: + m_OverrideState: 1 + m_Value: 1 + bladeRotation: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &-6858918158855671789 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 11500000, guid: fb60a22f311433c4c962b888d1393f88, type: 3} + m_Name: PaniniProjection + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.PaniniProjection + active: 1 + distance: + m_OverrideState: 1 + m_Value: 0 + cropToFit: + m_OverrideState: 1 + m_Value: 1 +--- !u!114 &-5760856276792176683 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 11500000, guid: 899c54efeace73346a0a16faa3afe726, type: 3} + m_Name: Vignette + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.Vignette + active: 1 + color: + m_OverrideState: 1 + m_Value: {r: 0, g: 0, b: 0, a: 1} + center: + m_OverrideState: 1 + m_Value: {x: 0.5, y: 0.5} + intensity: + m_OverrideState: 1 + m_Value: 0 + smoothness: + m_OverrideState: 1 + m_Value: 0.2 + rounded: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &-5495840893406415533 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 11500000, guid: 29fa0085f50d5e54f8144f766051a691, type: 3} + m_Name: FilmGrain + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.FilmGrain + active: 1 + type: + m_OverrideState: 1 + m_Value: 0 + intensity: + m_OverrideState: 1 + m_Value: 0 + response: + m_OverrideState: 1 + m_Value: 0.8 + texture: + m_OverrideState: 1 + m_Value: {fileID: 0} +--- !u!114 &-5026977458242833459 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 11500000, guid: 221518ef91623a7438a71fef23660601, type: 3} + m_Name: WhiteBalance + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.WhiteBalance + active: 1 + temperature: + m_OverrideState: 1 + m_Value: 0 + tint: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &-2986203292941192888 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 11500000, guid: 0b2db86121404754db890f4c8dfe81b2, type: 3} + m_Name: Bloom + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.Bloom + active: 1 + skipIterations: + m_OverrideState: 1 + m_Value: 1 + threshold: + m_OverrideState: 1 + m_Value: 0.9 + intensity: + m_OverrideState: 1 + m_Value: 0 + scatter: + m_OverrideState: 1 + m_Value: 0.7 + clamp: + m_OverrideState: 1 + m_Value: 65472 + tint: + m_OverrideState: 1 + m_Value: {r: 1, g: 1, b: 1, a: 1} + highQualityFiltering: + m_OverrideState: 1 + m_Value: 0 + filter: + m_OverrideState: 1 + m_Value: 0 + downscale: + m_OverrideState: 1 + m_Value: 0 + maxIterations: + m_OverrideState: 1 + m_Value: 6 + dirtTexture: + m_OverrideState: 1 + m_Value: {fileID: 0} + dimension: 1 + dirtIntensity: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &-2319901517658964290 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 11500000, guid: 97c23e3b12dc18c42a140437e53d3951, type: 3} + m_Name: Tonemapping + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.Tonemapping + active: 1 + mode: + m_OverrideState: 1 + m_Value: 0 + neutralHDRRangeReductionMode: + m_OverrideState: 1 + m_Value: 2 + acesPreset: + m_OverrideState: 1 + m_Value: 3 + hueShiftAmount: + m_OverrideState: 1 + m_Value: 0 + detectPaperWhite: + m_OverrideState: 1 + m_Value: 0 + paperWhite: + m_OverrideState: 1 + m_Value: 300 + detectBrightnessLimits: + m_OverrideState: 1 + m_Value: 1 + minNits: + m_OverrideState: 1 + m_Value: 0.005 + maxNits: + m_OverrideState: 1 + m_Value: 1000 +--- !u!114 &-1860047564659748416 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 11500000, guid: 06437c1ff663d574d9447842ba0a72e4, type: 3} + m_Name: ScreenSpaceLensFlare + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.ScreenSpaceLensFlare + active: 1 + intensity: + m_OverrideState: 1 + m_Value: 0 + tintColor: + m_OverrideState: 1 + m_Value: {r: 1, g: 1, b: 1, a: 1} + bloomMip: + m_OverrideState: 1 + m_Value: 1 + firstFlareIntensity: + m_OverrideState: 1 + m_Value: 1 + secondaryFlareIntensity: + m_OverrideState: 1 + m_Value: 1 + warpedFlareIntensity: + m_OverrideState: 1 + m_Value: 1 + warpedFlareScale: + m_OverrideState: 1 + m_Value: {x: 1, y: 1} + samples: + m_OverrideState: 1 + m_Value: 1 + sampleDimmer: + m_OverrideState: 1 + m_Value: 0.5 + vignetteEffect: + m_OverrideState: 1 + m_Value: 1 + startingPosition: + m_OverrideState: 1 + m_Value: 1.25 + scale: + m_OverrideState: 1 + m_Value: 1.5 + streaksIntensity: + m_OverrideState: 1 + m_Value: 0 + streaksLength: + m_OverrideState: 1 + m_Value: 0.5 + streaksOrientation: + m_OverrideState: 1 + m_Value: 0 + streaksThreshold: + m_OverrideState: 1 + m_Value: 0.25 + resolution: + m_OverrideState: 1 + m_Value: 4 + chromaticAbberationIntensity: + m_OverrideState: 1 + m_Value: 0.5 +--- !u!114 &-1262730450789330644 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 11500000, guid: 81180773991d8724ab7f2d216912b564, type: 3} + m_Name: ChromaticAberration + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.ChromaticAberration + active: 1 + intensity: + m_OverrideState: 1 + m_Value: 0 --- !u!114 &11400000 MonoBehaviour: m_ObjectHideFlags: 0 @@ -12,4 +567,232 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: d7fd9488000d3734a9e00ee676215985, type: 3} m_Name: DefaultVolumeProfile m_EditorClassIdentifier: Unity.RenderPipelines.Core.Runtime::UnityEngine.Rendering.VolumeProfile - components: [] + components: + - {fileID: 743231449427135496} + - {fileID: 3500651641176376349} + - {fileID: -7615108799411823199} + - {fileID: -7576830524726348909} + - {fileID: 1681678413439439198} + - {fileID: -5760856276792176683} + - {fileID: 3980703659364065184} + - {fileID: -1860047564659748416} + - {fileID: -7655542585027984839} + - {fileID: 8136988871774656336} + - {fileID: -2986203292941192888} + - {fileID: -8123393559496137545} + - {fileID: -6858918158855671789} + - {fileID: -1262730450789330644} + - {fileID: -2319901517658964290} + - {fileID: -5495840893406415533} + - {fileID: -5026977458242833459} + - {fileID: 329775769526288344} + - {fileID: 6038158131134407384} +--- !u!114 &329775769526288344 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 11500000, guid: e021b4c809a781e468c2988c016ebbea, type: 3} + m_Name: ColorLookup + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.ColorLookup + active: 1 + texture: + m_OverrideState: 1 + m_Value: {fileID: 0} + dimension: 1 + contribution: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &743231449427135496 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 11500000, guid: 558a8e2b6826cf840aae193990ba9f2e, type: 3} + m_Name: ShadowsMidtonesHighlights + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.ShadowsMidtonesHighlights + active: 1 + shadows: + m_OverrideState: 1 + m_Value: {x: 1, y: 1, z: 1, w: 0} + midtones: + m_OverrideState: 1 + m_Value: {x: 1, y: 1, z: 1, w: 0} + highlights: + m_OverrideState: 1 + m_Value: {x: 1, y: 1, z: 1, w: 0} + shadowsStart: + m_OverrideState: 1 + m_Value: 0 + shadowsEnd: + m_OverrideState: 1 + m_Value: 0.3 + highlightsStart: + m_OverrideState: 1 + m_Value: 0.55 + highlightsEnd: + m_OverrideState: 1 + m_Value: 1 +--- !u!114 &1681678413439439198 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 11500000, guid: ccf1aba9553839d41ae37dd52e9ebcce, type: 3} + m_Name: MotionBlur + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.MotionBlur + active: 1 + mode: + m_OverrideState: 1 + m_Value: 0 + quality: + m_OverrideState: 1 + m_Value: 0 + intensity: + m_OverrideState: 1 + m_Value: 0 + clamp: + m_OverrideState: 1 + m_Value: 0.05 +--- !u!114 &3500651641176376349 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 11500000, guid: cdfbdbb87d3286943a057f7791b43141, type: 3} + m_Name: ChannelMixer + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.ChannelMixer + active: 1 + redOutRedIn: + m_OverrideState: 1 + m_Value: 100 + redOutGreenIn: + m_OverrideState: 1 + m_Value: 0 + redOutBlueIn: + m_OverrideState: 1 + m_Value: 0 + greenOutRedIn: + m_OverrideState: 1 + m_Value: 0 + greenOutGreenIn: + m_OverrideState: 1 + m_Value: 100 + greenOutBlueIn: + m_OverrideState: 1 + m_Value: 0 + blueOutRedIn: + m_OverrideState: 1 + m_Value: 0 + blueOutGreenIn: + m_OverrideState: 1 + m_Value: 0 + blueOutBlueIn: + m_OverrideState: 1 + m_Value: 100 +--- !u!114 &3980703659364065184 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 11500000, guid: 5485954d14dfb9a4c8ead8edb0ded5b1, type: 3} + m_Name: LiftGammaGain + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.LiftGammaGain + active: 1 + lift: + m_OverrideState: 1 + m_Value: {x: 1, y: 1, z: 1, w: 0} + gamma: + m_OverrideState: 1 + m_Value: {x: 1, y: 1, z: 1, w: 0} + gain: + m_OverrideState: 1 + m_Value: {x: 1, y: 1, z: 1, w: 0} +--- !u!114 &6038158131134407384 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 11500000, guid: 6bd486065ce11414fa40e631affc4900, type: 3} + m_Name: ProbeVolumesOptions + m_EditorClassIdentifier: Unity.RenderPipelines.Core.Runtime::UnityEngine.Rendering.ProbeVolumesOptions + active: 1 + normalBias: + m_OverrideState: 1 + m_Value: 0.05 + viewBias: + m_OverrideState: 1 + m_Value: 0.1 + scaleBiasWithMinProbeDistance: + m_OverrideState: 1 + m_Value: 0 + samplingNoise: + m_OverrideState: 1 + m_Value: 0.1 + animateSamplingNoise: + m_OverrideState: 1 + m_Value: 1 + leakReductionMode: + m_OverrideState: 1 + m_Value: 2 + minValidDotProductValue: + m_OverrideState: 1 + m_Value: 0.1 + occlusionOnlyReflectionNormalization: + m_OverrideState: 1 + m_Value: 1 + intensityMultiplier: + m_OverrideState: 1 + m_Value: 1 + skyOcclusionIntensityMultiplier: + m_OverrideState: 1 + m_Value: 1 + worldOffset: + m_OverrideState: 1 + m_Value: {x: 0, y: 0, z: 0} +--- !u!114 &8136988871774656336 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 11500000, guid: 70afe9e12c7a7ed47911bb608a23a8ff, type: 3} + m_Name: SplitToning + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.SplitToning + active: 1 + shadows: + m_OverrideState: 1 + m_Value: {r: 0.5, g: 0.5, b: 0.5, a: 1} + highlights: + m_OverrideState: 1 + m_Value: {r: 0.5, g: 0.5, b: 0.5, a: 1} + balance: + m_OverrideState: 1 + m_Value: 0 diff --git a/Assets/Luneraria/Settings/Rendering/Luneraria_URP.asset b/Assets/Luneraria/Settings/Rendering/Luneraria_URP.asset index 3386d2f..2c2d59e 100644 --- a/Assets/Luneraria/Settings/Rendering/Luneraria_URP.asset +++ b/Assets/Luneraria/Settings/Rendering/Luneraria_URP.asset @@ -100,42 +100,42 @@ MonoBehaviour: obsoleteHasProbeVolumes: m_Keys: [] m_Values: - m_PrefilteringModeMainLightShadows: 1 - m_PrefilteringModeAdditionalLight: 4 - m_PrefilteringModeAdditionalLightShadows: 1 - m_PrefilterXRKeywords: 0 - m_PrefilteringModeForwardPlus: 1 - m_PrefilteringModeDeferredRendering: 1 - m_PrefilteringModeScreenSpaceOcclusion: 1 - m_PrefilterDebugKeywords: 0 - m_PrefilterWriteRenderingLayers: 0 - m_PrefilterHDROutput: 0 - m_PrefilterAlphaOutput: 0 - m_PrefilterSSAODepthNormals: 0 - m_PrefilterSSAOSourceDepthLow: 0 - m_PrefilterSSAOSourceDepthMedium: 0 - m_PrefilterSSAOSourceDepthHigh: 0 - m_PrefilterSSAOInterleaved: 0 - m_PrefilterSSAOBlueNoise: 0 - m_PrefilterSSAOSampleCountLow: 0 - m_PrefilterSSAOSampleCountMedium: 0 - m_PrefilterSSAOSampleCountHigh: 0 - m_PrefilterDBufferMRT1: 0 - m_PrefilterDBufferMRT2: 0 - m_PrefilterDBufferMRT3: 0 - m_PrefilterSoftShadowsQualityLow: 0 - m_PrefilterSoftShadowsQualityMedium: 0 - m_PrefilterSoftShadowsQualityHigh: 0 + m_PrefilteringModeMainLightShadows: 3 + m_PrefilteringModeAdditionalLight: 3 + m_PrefilteringModeAdditionalLightShadows: 0 + m_PrefilterXRKeywords: 1 + m_PrefilteringModeForwardPlus: 0 + m_PrefilteringModeDeferredRendering: 0 + m_PrefilteringModeScreenSpaceOcclusion: 0 + m_PrefilterDebugKeywords: 1 + m_PrefilterWriteRenderingLayers: 1 + m_PrefilterHDROutput: 1 + m_PrefilterAlphaOutput: 1 + m_PrefilterSSAODepthNormals: 1 + m_PrefilterSSAOSourceDepthLow: 1 + m_PrefilterSSAOSourceDepthMedium: 1 + m_PrefilterSSAOSourceDepthHigh: 1 + m_PrefilterSSAOInterleaved: 1 + m_PrefilterSSAOBlueNoise: 1 + m_PrefilterSSAOSampleCountLow: 1 + m_PrefilterSSAOSampleCountMedium: 1 + m_PrefilterSSAOSampleCountHigh: 1 + m_PrefilterDBufferMRT1: 1 + m_PrefilterDBufferMRT2: 1 + m_PrefilterDBufferMRT3: 1 + m_PrefilterSoftShadowsQualityLow: 1 + m_PrefilterSoftShadowsQualityMedium: 1 + m_PrefilterSoftShadowsQualityHigh: 1 m_PrefilterSoftShadows: 0 - m_PrefilterScreenCoord: 0 - m_PrefilterScreenSpaceIrradiance: 0 - m_PrefilterNativeRenderPass: 0 + m_PrefilterScreenCoord: 1 + m_PrefilterScreenSpaceIrradiance: 1 + m_PrefilterNativeRenderPass: 1 m_PrefilterUseLegacyLightmaps: 0 - m_PrefilterBicubicLightmapSampling: 0 + m_PrefilterBicubicLightmapSampling: 1 m_PrefilterReflectionProbeRotation: 0 - m_PrefilterReflectionProbeBlending: 0 - m_PrefilterReflectionProbeBoxProjection: 0 - m_PrefilterReflectionProbeAtlas: 0 + m_PrefilterReflectionProbeBlending: 1 + m_PrefilterReflectionProbeBoxProjection: 1 + m_PrefilterReflectionProbeAtlas: 1 m_ShaderVariantLogLevel: 0 m_ShadowCascades: 0 m_Textures: diff --git a/Assets/Luneraria/Settings/Rendering/UniversalRenderPipelineGlobalSettings.asset b/Assets/Luneraria/Settings/Rendering/UniversalRenderPipelineGlobalSettings.asset index a879f0d..95823e9 100644 --- a/Assets/Luneraria/Settings/Rendering/UniversalRenderPipelineGlobalSettings.asset +++ b/Assets/Luneraria/Settings/Rendering/UniversalRenderPipelineGlobalSettings.asset @@ -68,7 +68,21 @@ MonoBehaviour: - rid: 5026820519263993890 - rid: 5026820519263993891 m_RuntimeSettings: - m_List: [] + m_List: + - rid: 5026820519263993859 + - rid: 5026820519263993860 + - rid: 5026820519263993863 + - rid: 5026820519263993864 + - rid: 5026820519263993869 + - rid: 5026820519263993870 + - rid: 5026820519263993871 + - rid: 5026820519263993872 + - rid: 5026820519263993876 + - rid: 5026820519263993880 + - rid: 5026820519263993881 + - rid: 5026820519263993882 + - rid: 5026820519263993887 + - rid: 5026820519263993891 m_AssetVersion: 10 m_ObsoleteDefaultVolumeProfile: {fileID: 0} m_RenderingLayerNames: diff --git a/Assets/Luneraria/Tests/View/PlayMode/VerticalFunctionTests.cs b/Assets/Luneraria/Tests/View/PlayMode/VerticalFunctionTests.cs new file mode 100644 index 0000000..7f8056a --- /dev/null +++ b/Assets/Luneraria/Tests/View/PlayMode/VerticalFunctionTests.cs @@ -0,0 +1,278 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Luneraria.Core; +using NUnit.Framework; +using UnityEngine; +using UnityEngine.TestTools; + +namespace Luneraria.View.Tests +{ + /// + /// U2D vertical function test: complete bot matches visible in the Unity scene, before the full + /// asset import. Match 1 (seed 2) runs from round 1 to the fall of an Ancient: lanes, towers + /// fall, heroes fight, the grotto boss is won and deployed. Match 2 (seed 9) starts at round 21 + /// with the fixture of the golden scenario high_wave_21 (waves above 20). Both must end with the + /// fingerprint of the plain core run. A camera director photographs the key moments + /// (docs/port/screenshots/u2d/); results and frame times go to docs/port/logs/u2d/. + /// + public sealed class VerticalFunctionTests + { + const float Speed = 6f; + + sealed class Shot + { + public string Label; + public Func Trigger; + public Action Aim; + public float Delay = .35f; + public bool Done; + } + + sealed class Stats + { + public int Frames; + public double Seconds; + public readonly List FrameMs = new List(); + public double AdvanceMs; + public double SyncMs; + public int Units; + } + + [UnityTest] + [Timeout(3600000)] + public IEnumerator BotMatchesRunVisiblyAndMatchTheCore() + { + var report = new StringBuilder("{\n \"runs\": [\n"); + var failures = new List(); + yield return Play(2, 1, 0, "match-seed2", SeedTwoShots(), report, failures, false); + report.Append(",\n"); + yield return Play(9, 21, 4000, "match-seed9-round21", WaveShots(), report, failures, true); + report.Append("\n ]\n}\n"); + string logs = Path.Combine(PlayModeSupport.Root, "docs/port/logs/u2d"); + Directory.CreateDirectory(logs); + File.WriteAllText(Path.Combine(logs, "vertical-function-test.json"), report.ToString()); + Assert.IsEmpty(failures, string.Join("\n", failures)); + } + + static IEnumerator Play(int seed, int startRound, int extraGold, string label, List shots, StringBuilder report, List failures, bool measure) + { + var options = new MatchOptions { Seed = seed, HumanSlot = -1 }; + LuneTrace core = LuneTrace.RunCore(options, startRound, extraGold, ""); + QualitySettings.vSyncCount = 0; + Application.targetFrameRate = 60; + yield return PlayModeSupport.Load(); + var driver = UnityEngine.Object.FindAnyObjectByType(); + var view = UnityEngine.Object.FindAnyObjectByType(); + var rig = UnityEngine.Object.FindAnyObjectByType(); + Camera camera = Camera.main; + rig.Interactive = false; + driver.Seed = seed; + driver.StartRound = startRound; + driver.ExtraGold = extraGold; + driver.Speed = Speed; + driver.Restart(); + LuneMatchRunner runner = driver.Runner; + rig.Overview(true); + var rounds = new List(); + var events = new List(); + int maxUnits = 0; + int maxHeroes = 0; + runner.Settled += settlement => + { + rounds.Add(string.Format("{{\"round\": {0}, \"combat_seconds\": {1}, \"lost\": [{2}], \"boss\": \"{3}\", \"end\": \"{4}\"}}", settlement.Round, + PlayModeSupport.Number(settlement.CombatTime), string.Join(", ", settlement.BuildingsLost.Select(b => "\"" + b + "\"")), settlement.Boss, settlement.EndReason)); + foreach (string building in settlement.BuildingsLost) + events.Add(string.Format("\"round {0}: {1} destroyed\"", settlement.Round, building)); + if (settlement.Boss != "none") + events.Add(string.Format("\"round {0}: grotto boss {1}\"", settlement.Round, settlement.Boss)); + }; + var captures = new List(); + Shot active = null; + float activeSince = 0f; + var stats = new Stats(); + bool measuring = false; + float realStart = Time.realtimeSinceStartup; + float overSince = -1f; + while (Time.realtimeSinceStartup - realStart < 900f) + { + yield return null; + LuneMatch match = runner.Match; + if (match.Combat != null && runner.Current == LuneMatchRunner.Stage.Combat) + { + maxUnits = Math.Max(maxUnits, match.Combat.Units.Count(u => u.IsMobile() && u.Alive)); + maxHeroes = Math.Max(maxHeroes, match.Combat.Units.Count(u => u.Kind == "hero" && u.Alive)); + } + // Frame times at normal game speed with the most units on the map (match 2, round 21). + if (measure && runner.Current == LuneMatchRunner.Stage.Combat && match.RoundNumber == startRound) + { + double elapsed = match.Combat.Elapsed; + if (!measuring && elapsed >= 10.0 && stats.Frames == 0) + { + measuring = true; + driver.Speed = 1f; + Application.targetFrameRate = -1; + rig.LookAt(new Vec2(0, 0), 64f, true); + } + if (measuring) + { + stats.Frames++; + stats.Seconds += Time.unscaledDeltaTime; + stats.FrameMs.Add(Time.unscaledDeltaTime * 1000.0); + stats.AdvanceMs += driver.LastAdvanceMs; + stats.SyncMs += view.LastSyncMs; + stats.Units = Math.Max(stats.Units, match.Combat.Units.Count(u => u.IsMobile() && u.Alive)); + if (stats.Seconds >= 20.0) + { + measuring = false; + driver.Speed = Speed; + Application.targetFrameRate = 60; + } + } + } + if (measuring) + continue; + if (active == null) + { + active = shots.FirstOrDefault(s => !s.Done && s.Trigger(runner, view)); + if (active != null) + { + rig.SetYaw(0f, true); + active.Aim(runner, view, rig); + activeSince = Time.realtimeSinceStartup; + } + } + else if (Time.realtimeSinceStartup - activeSince >= active.Delay) + { + // Render directly: WaitForEndOfFrame never resumes in batch mode. + string file = Path.Combine(PlayModeSupport.Root, "docs/port/screenshots/u2d", active.Label + ".png"); + LuneCapture.Render(camera, file); + captures.Add("\"" + active.Label + "\""); + Debug.Log("LUNE_U2D shot " + active.Label + " round " + runner.Match.RoundNumber + " " + runner.Current); + active.Done = true; + active = null; + } + if (runner.Current == LuneMatchRunner.Stage.Over) + { + if (overSince < 0f) + overSince = Time.realtimeSinceStartup; + bool pending = shots.Any(s => !s.Done && s.Trigger(runner, view)) || active != null; + if (!pending && Time.realtimeSinceStartup - overSince > 3.5f) + break; + if (Time.realtimeSinceStartup - overSince > 12f) + break; + } + } + LuneTrace trace = runner.Trace; + bool same = runner.Current == LuneMatchRunner.Stage.Over && trace.Hash == core.Hash && trace.Steps == core.Steps; + if (!same) + failures.Add(label + ": fingerprint " + trace.Hash.ToString("X16") + " / core " + core.Hash.ToString("X16")); + foreach (Shot shot in shots.Where(s => !s.Done)) + failures.Add(label + ": no shot " + shot.Label); + double[] frameMs = stats.FrameMs.OrderBy(v => v).ToArray(); + string performance = stats.Frames == 0 ? "null" : string.Format("{{\"window\": \"20 s real time at 1x speed, unlimited frame rate, round {0}\", \"frames\": {1}, \"fps\": {2}, \"frame_ms_avg\": {3}, \"frame_ms_p95\": {4}, \"simulation_ms_per_frame\": {5}, \"views_ms_per_frame\": {6}, \"units_alive_max\": {7}}}", + startRound, stats.Frames, PlayModeSupport.Number(stats.Frames / stats.Seconds), PlayModeSupport.Number(stats.Seconds * 1000.0 / stats.Frames), + PlayModeSupport.Number(frameMs[(int)(frameMs.Length * .95)]), PlayModeSupport.Number(stats.AdvanceMs / stats.Frames), PlayModeSupport.Number(stats.SyncMs / stats.Frames), stats.Units); + report.AppendFormat(" {{\"label\": \"{0}\", \"seed\": {1}, \"start_round\": {2}, \"extra_gold\": {3}, \"speed\": {4}, \"winner\": {5}, \"end_note\": \"{6}\", \"steps\": {7}, \"hash\": \"{8:X16}\", \"core_hash\": \"{9:X16}\", \"same_as_core\": {10},\n \"units_alive_max\": {11}, \"heroes_alive_max\": {12}, \"boss_log\": [{13}],\n \"rounds\": [{14}],\n \"events\": [{15}],\n \"shots\": [{16}],\n \"performance\": {17}}}", + label, seed, startRound, extraGold, Speed, runner.Match.Winner, runner.Match.EndNote, trace.Steps, trace.Hash, core.Hash, same ? "true" : "false", + maxUnits, maxHeroes, string.Join(", ", runner.Match.BossLog.Select(e => string.Format("\"round {0}: {1} team {2} {3}\"", e.Round, e.Event, e.Team, e.Lane))), + string.Join(", ", rounds), string.Join(", ", events), string.Join(", ", captures), performance); + Application.targetFrameRate = -1; + } + + static bool InCombat(LuneMatchRunner runner, int round, double from) + { + return runner.Current == LuneMatchRunner.Stage.Combat && runner.Match.RoundNumber == round && runner.Match.Combat.Elapsed >= from; + } + + static LuneUnit Find(LuneMatchRunner runner, Func predicate) + { + return runner.Match.Combat == null ? null : runner.Match.Combat.Units.FirstOrDefault(predicate); + } + + static Shot Building(string label, Func pick, LuneBuildingView.Look look, float zoom, float delay) + { + LuneBuildingView chosen = null; + return new Shot + { + Label = label, + Delay = delay, + Trigger = (runner, view) => + { + chosen = pick(view); + return chosen != null && chosen.Current == look; + }, + Aim = (runner, view, rig) => + { + // Towers are watched from their lane (open ground), not through the forest. + Vec2 at = LuneSpace.Map(chosen.transform.position); + BuildingDef definition = runner.Match.Map.BuildingDef(chosen.BuildingId); + float yaw = 0f; + if (!chosen.IsAncient && definition.Tier != "base") + yaw = LuneCameraRig.YawTowards(at, runner.Match.Map.LanePoint(definition.Team, definition.Lane, definition.Progress)); + rig.SetYaw(yaw, true); + rig.LookAt(at, zoom, true); + }, + }; + } + + static List SeedTwoShots() + { + string fallen = null; + return new List + { + new Shot { Label = "01-runde1-aufmarsch", Trigger = (r, v) => InCombat(r, 1, 9.0), Aim = (r, v, rig) => rig.LookAt(new Vec2(0, 0), 64f, true) }, + new Shot { Label = "02-runde1-mid-kampf", Trigger = (r, v) => InCombat(r, 1, 24.0), Aim = (r, v, rig) => + { + LuneUnit fighter = Find(r, u => u.IsMobile() && u.Alive && u.Lane == "mid" && u.Target != null && u.InRange); + rig.LookAt(fighter != null ? fighter.Position : new Vec2(0, 0), 20f, true); + } }, + Building("03-turm-faellt", v => AnyBuilding(v, b => !b.IsAncient && b.Current == LuneBuildingView.Look.Destroying, ref fallen), LuneBuildingView.Look.Destroying, 22f, .7f), + Building("04-turm-ruine", v => fallen != null ? v.Building(fallen) : null, LuneBuildingView.Look.Ruin, 22f, .4f), + new Shot { Label = "05-grotte-bosskampf", Delay = .5f, Trigger = (r, v) => Find(r, u => u.Kind == "boss" && u.Zone == "grotto" && u.Alive && !u.Dormant) != null, + Aim = (r, v, rig) => rig.LookAt(LuneMap.Grotto, 20f, true) }, + new Shot { Label = "06-held-kaempft", Delay = .3f, Trigger = (r, v) => Find(r, u => u.Kind == "hero" && u.Alive && u.Zone == "lane" && u.Target != null && u.InRange) != null, + Aim = (r, v, rig) => rig.LookAt(Find(r, u => u.Kind == "hero" && u.Alive && u.Zone == "lane" && u.Target != null && u.InRange).Position, 16f, true) }, + new Shot { Label = "07-boss-auf-der-lane", Delay = .3f, Trigger = (r, v) => r.Current == LuneMatchRunner.Stage.Combat && r.Match.Combat.Elapsed > 12.0 && Find(r, u => u.Kind == "boss" && u.Zone == "lane" && u.Alive) != null, + Aim = (r, v, rig) => rig.LookAt(Find(r, u => u.Kind == "boss" && u.Zone == "lane" && u.Alive).Position, 22f, true) }, + Building("08-ancient-faellt", v => v.Building("blau_ancient"), LuneBuildingView.Look.Destroying, 30f, .8f), + Building("09-ancient-ruine", v => v.Building("blau_ancient"), LuneBuildingView.Look.Ruin, 30f, .5f), + new Shot { Label = "10-ende-uebersicht", Delay = .5f, Trigger = (r, v) => r.Current == LuneMatchRunner.Stage.Over && v.Building("blau_ancient").Current == LuneBuildingView.Look.Ruin, + Aim = (r, v, rig) => rig.Overview(true) }, + }; + } + + /// The first building that satisfies the condition; remembers its id. + static LuneBuildingView AnyBuilding(LuneMatchView view, Func condition, ref string remembered) + { + foreach (LuneBuildingView building in UnityEngine.Object.FindObjectsByType(FindObjectsSortMode.None).OrderBy(b => b.BuildingId, StringComparer.Ordinal)) + { + if (condition(building)) + { + remembered = building.BuildingId; + return building; + } + } + return null; + } + + static List WaveShots() + { + return new List + { + new Shot { Label = "11-welle21-uebersicht", Trigger = (r, v) => InCombat(r, 21, 6.0), Aim = (r, v, rig) => rig.LookAt(new Vec2(0, 0), 70f, true) }, + new Shot { Label = "12-welle21-kampf", Trigger = (r, v) => InCombat(r, 21, 36.0), Aim = (r, v, rig) => + { + LuneUnit fighter = Find(r, u => u.IsMobile() && u.Alive && u.Target != null && u.InRange && u.Zone == "lane"); + rig.LookAt(fighter != null ? fighter.Position : new Vec2(0, 0), 24f, true); + } }, + Building("13-ancient-rot-faellt", v => v.Building("rot_ancient"), LuneBuildingView.Look.Destroying, 30f, .8f), + new Shot { Label = "14-welle-ende", Delay = .6f, Trigger = (r, v) => r.Current == LuneMatchRunner.Stage.Over && v.Building("rot_ancient").Current == LuneBuildingView.Look.Ruin, + Aim = (r, v, rig) => rig.LookAt(r.Match.Map.CorePosition(1), 34f, true) }, + }; + } + } +} diff --git a/Assets/Luneraria/Tests/View/PlayMode/VerticalFunctionTests.cs.meta b/Assets/Luneraria/Tests/View/PlayMode/VerticalFunctionTests.cs.meta new file mode 100644 index 0000000..3ace985 --- /dev/null +++ b/Assets/Luneraria/Tests/View/PlayMode/VerticalFunctionTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 26a9b53c1b823413f92f2dc0a48c6412 \ No newline at end of file diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index 5d65bdf..e6bb12d 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -154,7 +154,7 @@ PlayerSettings: vrSettings: enable360StereoCapture: 0 isWsaHolographicRemotingEnabled: 0 - enableFrameTimingStats: 0 + enableFrameTimingStats: 1 enableOpenGLProfilerGPURecorders: 1 allowHDRDisplaySupport: 0 useHDRDisplay: 0 @@ -296,7 +296,10 @@ PlayerSettings: androidSymbolsSizeThreshold: 800 m_BuildTargetIcons: [] m_BuildTargetPlatformIcons: [] - m_BuildTargetBatching: [] + m_BuildTargetBatching: + - m_BuildTarget: Standalone + m_StaticBatching: 1 + m_DynamicBatching: 0 m_BuildTargetShaderSettings: [] m_BuildTargetGraphicsJobs: [] m_BuildTargetGraphicsJobMode: [] diff --git a/README.md b/README.md index 9df02ae..19e1e7c 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,9 @@ Drei-Lane-Autobattler 3 gegen 3 (Mischung aus Dota 2 und Legion TD 2), portiert ## Aufbau - `Assets/Luneraria/Core/`: Regelkern ohne Unity-Abhängigkeit (`Luneraria.Core`). +- `Assets/Luneraria/View/`: Host-Schleife (fester Takt), Ansichten, Kamera (`Luneraria.View`); `Scenes/G1_Map.unity` ist die spielbare Karte. +- `Assets/Luneraria/Art/`: FBX aus der Blender-Pipeline (`tools/blender/`); `World/Bake/`: gebackene G1-Welt aus dem Godot-Generator. +- `Assets/Luneraria/Editor/`: Importregeln, Asset-Prüfung, Welt- und Szenenbau, Player-Build. - `Assets/Luneraria/Tests/Core/`: Prüfsuiten mit Golden-Referenzen aus Godot, Diagnose (Float-Probe, Schritt-Trace, Benchmark); laufen im Unity Test Runner und mit dem .NET SDK. - `tools/`: .NET-Projekte (Ausgabe nach `tools/out/`), Godot-Referenzwerkzeuge, Portwerkzeuge. - `docs/port/`: Stand, Entscheidungen und QA je Meilenstein ([PORT-STATUS.md](docs/port/PORT-STATUS.md)). @@ -27,6 +30,14 @@ Dieselben Tests im Unity Test Runner: /Applications/Unity/Hub/Editor/6000.3.20f1/Unity.app/Contents/MacOS/Unity -batchmode -projectPath "$PWD" -runTests -testPlatform EditMode -testResults "$PWD/tools/out/editmode-results.xml" -logFile - ``` +Szene neu bauen (nach geänderter Welt, Materialien oder Assets): + +```bash +/Applications/Unity/Hub/Editor/6000.3.20f1/Unity.app/Contents/MacOS/Unity -batchmode -projectPath "$PWD" -executeMethod Luneraria.EditorTools.LuneWorldBuilder.BuildScene -logFile - +``` + +Spielen: `Assets/Luneraria/Scenes/G1_Map.unity` im Editor öffnen und Play drücken (Bot-Partie, Kamera mit WASD, Mausrad, Q/E, R, O). + Leistung (.NET bzw. Editor über `-executeMethod Luneraria.Core.Tests.CoreBatch.Benchmark`): ```bash diff --git a/docs/port/KNOWN-BEHAVIOR-DIFFERENCES.md b/docs/port/KNOWN-BEHAVIOR-DIFFERENCES.md index a996d25..01fcda2 100644 --- a/docs/port/KNOWN-BEHAVIOR-DIFFERENCES.md +++ b/docs/port/KNOWN-BEHAVIOR-DIFFERENCES.md @@ -32,6 +32,10 @@ Diese Fehler der Referenz sind im Port absichtlich nachgebildet. Die Golden-Pari Details: [U1.5-UNITY.md](U1.5-UNITY.md#float-befund). +## Unity-Szene (U2) + +Die Szene ändert kein Verhalten. Der Host treibt den Kern im festen Takt; die Ansichten lesen nur. Die vollständige Bot-Partie (Seed 2) und die Partie ab Runde 21 (Seed 9) liefern in der Szene denselben Fingerabdruck wie der reine Kernlauf. Das gilt auch bei 30, 60 und 120 fps, unbegrenzter Bildrate, Rucklern und erhöhtem Spieltempo ([U2-WORLD.md](U2-WORLD.md#u2c--simulation-und-darstellung)). + ## Darstellungswerte | Wert | Warum kein Regelunterschied | diff --git a/docs/port/PORT-QA.md b/docs/port/PORT-QA.md index 5de853b..ed3f60b 100644 --- a/docs/port/PORT-QA.md +++ b/docs/port/PORT-QA.md @@ -30,6 +30,18 @@ Hinweis: Die Projektdateien des .NET-Harness (`tools/dotnet/*/*.csproj`) fehlten | Offen | IL2CPP- und Player-Läufe unter Windows 11 und Fedora 44 (Build-Module fehlen, Installation nach Freigabe) | | Commit | Zweig `luneraria/u1.5` | -## U2 bis U5 +## U2 · Unity-Spielwelt -U2 ist der nächste Schritt; U3 bis U5 sind noch nicht begonnen. +| Punkt | Ergebnis | +| --- | --- | +| Tests | Blender-Pipeline 176/176 und Unity-Verifier 128/128 (9 Assets). Test Runner EditMode 11/11: Kern 402 Prüfungen, 2 Integrationstests, 4 Bildratentests. PlayMode 2/2: Szene bei echten Bildraten, Vertical Function Test | +| Parität | Bot-Partie Seed 2 (9 Runden) und Seed 9 ab Runde 21 in der sichtbaren Szene mit demselben Fingerabdruck wie der reine Kern; ebenso bei 30, 60, 120 fps, unbegrenzt, mit Rucklern und bei 8× Tempo | +| Bild | `screenshots/u2a/` (Assets), `u2b/` (Karte mit Godot-Kameraeinstellungen; Vergleich mit `g2/nachher`), `u2d/` (14 Schlüsselmomente der Partien) | +| Leistung | macOS-Player (M5, 1080p, VSync aus) mit 116 Einheiten: 161–199 fps; Hauptthread 1,3 ms, Render-Thread 1,3 ms, Simulation unter 0,1 ms. Ausreißer beim Present (p95 18–26 ms) offen für U5 | +| Bekannte Unterschiede | keine Verhaltensunterschiede. Darstellung vereinfacht: Platzhaltermodelle für Einheiten, Materialien, Effekte, Debug-Anzeige statt HUD ([U2-WORLD.md](U2-WORLD.md)) | +| Offen | Batch-Import der übrigen Assets; Windows-/Linux-Player (Build-Module); Leistungsspitzen | +| Commits | `luneraria/u2`: U2A `49cb4af`, U2B `8a72cb1`, U2C, U2D | + +## U3 bis U5 + +U3 (G3-HUD portieren) ist der nächste Schritt; U4 und U5 sind noch nicht begonnen. diff --git a/docs/port/PORT-STATUS.md b/docs/port/PORT-STATUS.md index 09e3942..20893f2 100644 --- a/docs/port/PORT-STATUS.md +++ b/docs/port/PORT-STATUS.md @@ -1,6 +1,6 @@ # Port-Status · Champions of Luneraria in Unity -Stand: 30. September 2026. +Stand: 1. Oktober 2026. Referenz ist der Godot-Stand `luneraria/g3` (`1b540f2`) in `../saumwacht-godot`; er wird nicht mehr verändert. Engine: Unity 6.3 LTS (6000.3.20f1), Renderer URP. HDRP ist ausgeschlossen, bis ein Vergleich mit einer echten Szene etwas anderes nahelegt. @@ -10,8 +10,8 @@ Zielplattformen sind Fedora 44 und Windows 11; macOS ist die Entwicklungsplattfo | --- | --- | --- | | U1 · C#-Simulation | **fertig** (Referenzmeilenstein, `luneraria/u1` = `4d6ed17`): 402/402 Prüfungen, Golden-Parität mit Godot | [U1-RULES.md](U1-RULES.md) | | U1.5 · Unity-Integrationsprüfung | **fertig**: Kern im Unity-Editor 402/402 (Release und Debug), Golden bitgleich nach expliziter float32-Rundung in `Vec2`, Editor-Benchmark | [U1.5-UNITY.md](U1.5-UNITY.md) | -| U2 · Unity-Spielwelt | nächster Schritt | [U2-WORLD.md](U2-WORLD.md) | -| U3 · G3-HUD portieren | nicht begonnen | [U3-UI.md](U3-UI.md) | +| U2 · Unity-Spielwelt | **fertig**: U2A Blender→FBX-Pipeline (9 Assets geprüft), U2B G1-Karte mit Materialsystem, U2C fester Takt und Ansichten (bildratenunabhängig nachgewiesen), U2D vollständige Bot-Partien sichtbar und gleich dem Kern | [U2-WORLD.md](U2-WORLD.md) | +| U3 · G3-HUD portieren | nächster Schritt | [U3-UI.md](U3-UI.md) | | U4 · Netzwerk | nicht begonnen; M4-Umfang ist erfasst | [U4-NETWORK.md](U4-NETWORK.md) | | U5 · Visuelle Neuausrichtung (Vertical Slice Mid-Lane) | nicht begonnen | [U5-VISUAL.md](U5-VISUAL.md) | @@ -22,7 +22,8 @@ Bekannte Verhaltensunterschiede, auch die bewusst übernommenen Referenzfehler: ## Offene Voraussetzungen - **Build-Module für die Zielplattformen fehlen:** Windows Build Support (Mono) und Linux Build Support (Mono), optional Linux IL2CPP und Linux Dedicated Server. Installation nur nach Freigabe (Details in U1.5-UNITY.md). -- Kerntests und Player auf Windows 11 und Fedora 44 stehen deshalb aus. +- Kerntests und Player auf Windows 11 und Fedora 44 stehen deshalb aus; gemessen ist bisher der macOS-Player. +- **Batch-Import der übrigen Assets** (58 Phase-4-Modelle, 5 Figuren, 7 Völker) ist nach dem Vertical Function Test jetzt an der Reihe. ## Entscheidungen @@ -32,13 +33,18 @@ Bekannte Verhaltensunterschiede, auch die bewusst übernommenen Referenzfehler: - **Tabellen** einmal aus Godot erzeugt (`tools/port/gen_content.py`); danach ist `ContentData.cs` die gepflegte Quelle. - **Referenzfehler R1** im Bot-Gedächtnis ist bewusst übernommen (Parität) und für eine spätere Bot-Phase vorgemerkt. - **Geplante Helden** (Lucy, Ghaliga, Siegfried, Feena) stehen im Datenmodell, sind aber inaktiv, bis eine Heldenphase ihre Regeln umsetzt. -- **Assets:** Blender-Quellen und Generatoren sind die Quelle. Ein zentraler, reproduzierbarer Blender-Export erzeugt FBX für Unity; GLB nur, wo keine bessere Quelle existiert (U2). +- **Assets:** Blender-Quellen und Generatoren sind die Quelle. Ein zentraler, reproduzierbarer Blender-Export erzeugt FBX für Unity; GLB nur, wo keine bessere Quelle existiert (U2A). +- **Prozedurale Welt gebacken (U2B):** Gelände und Vegetation der G1-Karte hängen an Godots Rauschen und Zufallsgenerator; ein Godot-Werkzeug backt die Welt aus dem Referenzgenerator, Unity baut daraus die Szene. U5 bekommt eine neue Weltquelle. +- **Koordinaten:** Unity = (−x, Höhe, y) der Kartenpunkte; FBX-Pipeline, Welt und Kamera nutzen dieselbe Umrechnung, das Bild entspricht Godots. +- **Host-Schleife (U2C):** fester Takt mit Akkumulator; die Bildrate bestimmt nur die Zahl der Schritte je Bild. Nachweis über Fingerabdrücke der Partie. ## Arbeitsweise - Ein Zweig je Meilenstein: `luneraria/u1`, `luneraria/u1.5`, `luneraria/u2`, … Nach jedem Meilenstein kommen Tests, Bild, Leistung, bekannte Unterschiede und ein Commit. - Werkzeuge: - `tools/run_core_tests.sh` (Kern mit .NET). - - Unity Test Runner (EditMode) und `CoreBatch` im Batchmodus (Kern im Editor). + - Unity Test Runner: EditMode (Kern, Integration, Bildraten-Logik) und PlayMode (Szene bei echten Bildraten, Vertical Function Test). + - `CoreBatch`, `LuneAssetVerifier`, `LuneWorldBuilder`, `LuneWorldCapture`, `LunePlayerBuild` im Batchmodus. + - `tools/blender/export_fbx.sh` (Assets), `tools/godot-golden/world_export.gd` (Weltbake). - `tools/godot-golden/run_godot.sh` (Godot-Referenz). - `tools/dotnet/Luneraria.Core.Bench` und `CoreBatch.Benchmark` (Leistung). diff --git a/docs/port/U2-WORLD.md b/docs/port/U2-WORLD.md index 919e36b..23aca05 100644 --- a/docs/port/U2-WORLD.md +++ b/docs/port/U2-WORLD.md @@ -7,7 +7,7 @@ Stand: 1. Oktober 2026. | U2A | Blender→FBX-Pipeline, sechs repräsentative Assets vollständig geprüft | **fertig** | | U2B | Weltgeometrie (G1-Karte, Türme, Ancients, Grotte, Aufstellungsbereiche), Materialsystem | **fertig** | | U2C | Simulation/Darstellung: fester Takt, Interpolation, Bildraten-Unabhängigkeit | **fertig** | -| U2D | spielbare Unity-Partie, Vertical Function Test | offen | +| U2D | spielbare Unity-Partie, Vertical Function Test | **fertig** | Voraussetzung U1.5 ist erfüllt ([U1.5-UNITY.md](U1.5-UNITY.md)). @@ -268,9 +268,101 @@ Im Batchmodus zeichnet Unity kein Bild auf einen Bildschirm; daher die sehr hohe - **Weitere Vereinfachungen:** Turmblitze sind kurze Linien. Die Einsturzsequenz ist vereinfacht (Kippen und Absinken). Der schlafende Boss zwischen den Kämpfen und die Planungsflächen fehlen noch. - **Kamera:** wie `lune_camera.gd` (WASD, Mausrad, Q/E, R, O, mittlere Maustaste), vorerst mit dem klassischen Input Manager. -## U2D +## U2D · Spielbare Unity-Partie -Folgt in diesem Dokument. +### Szene und Steuerung + +`Assets/Luneraria/Scenes/G1_Map.unity`, Play im Editor oder der macOS-Player: Eine Bot-Partie läuft (Standard: Seed 2) mit 3 Lanes, 2 Basen, 16 Türmen, 2 Ancients, Grotte und Aufstellungsbereichen auf dem echten C#-Kern. + +| Teil | Funktion | +| --- | --- | +| Kamera | wie Godot: WASD/Pfeile, Mausrad, Q/E, R, O, mittlere Maustaste | +| `LuneDebugOverlay` | Runde, Phase, Türme, Ancients, Einheiten, Helden, Boss, Sieger. Das ist eine vorläufige Anzeige, kein HUD; das G3-HUD wird in U3 portiert, nicht neu erfunden | +| `LuneMatchDriver` | Seed, Startrunde, Fixture-Gold und Spieltempo im Inspector | + +Menschliche Befehle (Kaufen, Aufstellen, Bereit) kommen mit dem HUD (U3) und dem Netzwerk (U4); bis dahin planen alle sechs Plätze als Bots über dieselbe Befehlsschnittstelle. + +### Vertical Function Test + +`VerticalFunctionTests` (PlayMode, Test Runner) spielt beide Partien sichtbar in der Szene. Das Spieltempo ist 6×, die Zielbildrate 60. Ein Kameraregisseur fotografiert die Schlüsselmomente; jede Partie muss den Fingerabdruck des reinen Kernlaufs ergeben. + +| Partie | Verlauf | Ergebnis | +| --- | --- | --- | +| Seed 2, ab Runde 1 | siehe unten | Rot gewinnt („Ancient von Blau zerstört.“); 12.690 Schritte, Fingerabdruck `DCE95C96556F3A1A` = Kern | +| Seed 9, ab Runde 21 (Fixture wie das Golden-Szenario `high_wave_21`: Runde 21, je 4.000 Gold) | Wellen über 20 mit bis zu 125 Einheiten und 6 Helden; Runde 21: 3 Rot-Türme fallen; Runde 22: Rot-Turm, beide Rot-Basistürme, ein Blau-Turm und der Rot-Ancient fallen | Blau gewinnt („Ancient von Rot zerstört.“); 4.195 Schritte, `7B8E43AEFC0D60C5` = Kern | + +Verlauf der Partie mit Seed 2: +- 9 Runden, bis zu 84 Einheiten. +- Runde 7: erster Turm fällt (`blau_bot_outer`). +- Runde 8: Rot gewinnt den Grottenboss; `rot_top_outer` und `rot_top_inner` fallen. +- Runde 9: Der Boss zieht für Rot über die Bot-Lane. Bis zu 4 Helden kämpfen. Blaus Bot-Innenturm, beide Basistürme und der Ancient fallen. + +Kein Bot-Spiel erreicht von Runde 1 aus die Welle 20: Ein Durchlauf über 200 Partien (5 Profile × 40 Seeds) endete immer nach 8 bis 12 Runden. Deshalb zeigt die zweite Partie die hohen Wellen mit derselben öffentlichen Fixture wie die Golden-Referenz. + +Bilder (`docs/port/screenshots/u2d/`): + +| Bild | zeigt | +| --- | --- | +| `01-runde1-aufmarsch`, `02-runde1-mid-kampf` | Aufmarsch auf drei Lanes, erster Kampf in der Mitte mit Turmblitz | +| `03-turm-faellt`, `04-turm-ruine` | Einsturz eines Turms und seine Ruine (Kamera von der Lane aus) | +| `05-grotte-bosskampf` | Schlundkrone kämpft in der Grotte | +| `06-held-kaempft` | Helden im Kampf | +| `07-boss-auf-der-lane` | eingesetzter Boss mit Rots Armee auf der Deltabrücke | +| `08-ancient-faellt`, `09-ancient-ruine`, `10-ende-uebersicht` | Fall des Blau-Ancient, Ruine, Endstand | +| `11-welle21-uebersicht`, `12-welle21-kampf`, `13-ancient-rot-faellt`, `14-welle-ende` | Welle 21: Übersicht, Massenkampf, Fall des Rot-Ancient | + +Protokoll: `logs/u2d/vertical-function-test.json`, mit Runden, Ereignissen, Bosslog und Bildliste. + +### Leistung + +**Player** (macOS, Mono, Release; Apple M5, Metal; 1920 × 1080 im Fenster, VSync aus): Seed 9 in Runde 21, Spieltempo 1×, gemessen ab 10 s Kampf mit `LuneBenchmark`. + +| Ansicht | Einheiten | fps (Mittel) | Bildzeit Median | p95 | Hauptthread (Mittel/p95) | Render-Thread | Warten auf Present (Mittel/p95) | +| --- | ---: | ---: | ---: | ---: | --- | --- | --- | +| ganze Karte (Zoom 64) | 116 | 161–199 | 2,3–2,9 ms | 18–26 ms | 1,3 / 2,0 ms | 1,3 ms | 4,9 / 24 ms | +| Mid-Lane nah (Zoom 22) | 63 | 274–354 | 1,9–2,5 ms | 9–13 ms | 0,9 / 1,3 ms | 0,9 ms | 2,7 / 13 ms | + +Die Spannen stammen aus vier Läufen. + +Was die Zahlen zeigen: +- Je Bild kosten die Simulation 0,02–0,07 ms und die Ansichten 0,12–0,14 ms. +- Die Ausreißer sind Wartezeit beim Present. Nur 4–27 der langsamen Bilder fielen mit einem Simulationsschritt zusammen. +- Garbage Collection war nicht die Ursache. Die Debug-Anzeige erzeugte zwar Müll in jedem Bild; das ist behoben (78 statt 111 Sammlungen in 20 s), änderte die Ausreißer aber nicht. +- Metal liefert in Unity keine GPU-Zeitstempel. Ob GPU oder Fenster-Compositor wartet, bleibt deshalb offen. Kandidaten: + - die Platzhaltermodelle (80.000 Dreiecke je Einheit, über 9 Millionen Dreiecke in der Übersicht), + - vier Schattenkaskaden bis 190 m, + - der Fenstermodus. + + Das gehört zu U5 (LOD, Dreiecksbudget, Vollbild). + +Rohdaten: `logs/u2d/player-benchmark-macos.json`. Windows- und Linux-Player brauchen die fehlenden Build-Module ([U1.5-UNITY.md](U1.5-UNITY.md#fehlende-build-module)). + +```bash +/Applications/Unity/Hub/Editor/6000.3.20f1/Unity.app/Contents/MacOS/Unity -batchmode -projectPath "$PWD" -executeMethod Luneraria.EditorTools.LunePlayerBuild.BuildMac -logFile - +``` + +```bash +Builds/macOS/Luneraria.app/Contents/MacOS/luneraria-unity -screen-width 1920 -screen-height 1080 -screen-fullscreen 0 -luneBenchmark "$PWD/tools/out/player-benchmark.json" +``` + +### Abnahme U2 + +| Vorgabe | Stand | +| --- | --- | +| Reproduzierbarer Blender→FBX-Export mit Prüfung von Einheiten, Maßstab, Achsen, Vorderseite, Root Bone, Bone-Namen, Mesh-Namen, Materialslots, Normalen, Tangenten, Clips; keine Handarbeit | erfüllt (U2A) | +| Sechs repräsentative Assets vollständig in Unity geprüft, vor dem Batchlauf | erfüllt (U2A); Batchlauf erst nach diesem Test, also jetzt freigegeben | +| Erste spielbare Szene mit echter Karte (3 Lanes, 2 Basen, 16 Türme, 2 Ancients, Grotte, Aufstellungsbereiche), an den echten Kern gebunden | erfüllt (U2B, U2D) | +| Szene besitzt keine Regeln; Zustand → Darstellung, nie umgekehrt | erfüllt (U2C) | +| Fester Takt, `Update()` entscheidet nie über den Kampf, Darstellung interpoliert | erfüllt (U2C) | +| Gleiches Ergebnis bei 30, 60, 120 fps und unbegrenzt | erfüllt, logisch und in der echten Szene (U2C) | +| Vertical Function Test: vollständige Bot-Partie sichtbar, 3 Lanes, Wellen > 20, Türme fallen, Helden kämpfen, Boss nutzbar, Ancient fällt, Partie endet, gleich der Kernpartie | erfüllt; Wellen > 20 über die Golden-Fixture (siehe oben) | + +### Bekannte Grenzen + +- **Platzhaltermodelle:** Alle Einheiten zeigen bis zum Batch-Import die repräsentativen Modelle (siehe U2C). +- **Debug-Anzeige statt HUD:** Das G3-HUD folgt in U3. Es gibt noch keine menschlichen Befehle und kein Planungsbild für einen Spieler. +- **Materialien vereinfacht** (siehe U2B); keine Partikeleffekte; Turmblitze sind einfache Linien. +- **Leistungsspitzen beim Present** offen (siehe oben). ## Abnahme (gesamt) diff --git a/docs/port/logs/u2d/player-benchmark-macos 2.json b/docs/port/logs/u2d/player-benchmark-macos 2.json new file mode 100644 index 0000000..f70bcf6 --- /dev/null +++ b/docs/port/logs/u2d/player-benchmark-macos 2.json @@ -0,0 +1,12 @@ +{ + "build": "OSXPlayer player, 6000.3.20f1, release", + "device": "Mac17,2; Apple M5; Apple M5", + "graphics_api": "Metal", + "resolution": "1920x1080", + "vsync": 0, + "match": "seed 9 from round 21 (fixture high_wave_21), speed 1x, measured after 10 s of combat", + "windows": [ + {"view": "overview (zoom 64)", "frames": 3977, "fps": 198.8, "frame_ms_avg": 5.03, "frame_ms_p95": 17.81, "frame_ms_p99": 24.41, "simulation_ms_per_frame": 0.065, "views_ms_per_frame": 0.127, "units_alive_max": 116}, + {"view": "mid lane close (zoom 22)", "frames": 3540, "fps": 354.0, "frame_ms_avg": 2.83, "frame_ms_p95": 8.87, "frame_ms_p99": 20.16, "simulation_ms_per_frame": 0.021, "views_ms_per_frame": 0.114, "units_alive_max": 63} + ] +} diff --git a/docs/port/logs/u2d/player-benchmark-macos 3.json b/docs/port/logs/u2d/player-benchmark-macos 3.json new file mode 100644 index 0000000..0dab2ce --- /dev/null +++ b/docs/port/logs/u2d/player-benchmark-macos 3.json @@ -0,0 +1,12 @@ +{ + "build": "OSXPlayer player, 6000.3.20f1, release", + "device": "Mac17,2; Apple M5; Apple M5", + "graphics_api": "Metal", + "resolution": "1920x1080", + "vsync": 0, + "match": "seed 9 from round 21 (fixture high_wave_21), speed 1x, measured after 10 s of combat", + "windows": [ + {"view": "overview (zoom 64)", "frames": 3586, "fps": 179.3, "frame_ms_avg": 5.58, "frame_ms_median": 2.40, "frame_ms_p95": 18.69, "frame_ms_p99": 27.09, "frame_ms_max": 40.68, "frames_over_16_7_ms": 277, "of_them_with_simulation_step": 23, "gc_collections": 111, "simulation_ms_per_frame": 0.068, "views_ms_per_frame": 0.137, "units_alive_max": 116}, + {"view": "mid lane close (zoom 22)", "frames": 3212, "fps": 320.8, "frame_ms_avg": 3.12, "frame_ms_median": 1.99, "frame_ms_p95": 10.92, "frame_ms_p99": 19.79, "frame_ms_max": 25.43, "frames_over_16_7_ms": 84, "of_them_with_simulation_step": 5, "gc_collections": 56, "simulation_ms_per_frame": 0.022, "views_ms_per_frame": 0.124, "units_alive_max": 63} + ] +} diff --git a/docs/port/logs/u2d/player-benchmark-macos 4.json b/docs/port/logs/u2d/player-benchmark-macos 4.json new file mode 100644 index 0000000..edfe53c --- /dev/null +++ b/docs/port/logs/u2d/player-benchmark-macos 4.json @@ -0,0 +1,12 @@ +{ + "build": "OSXPlayer player, 6000.3.20f1, release", + "device": "Mac17,2; Apple M5; Apple M5", + "graphics_api": "Metal", + "resolution": "1920x1080", + "vsync": 0, + "match": "seed 9 from round 21 (fixture high_wave_21), speed 1x, measured after 10 s of combat", + "windows": [ + {"view": "overview (zoom 64)", "frames": 3612, "fps": 180.6, "frame_ms_avg": 5.54, "frame_ms_median": 2.30, "frame_ms_p95": 19.70, "frame_ms_p99": 25.49, "frame_ms_max": 36.30, "frames_over_16_7_ms": 286, "of_them_with_simulation_step": 27, "gc_collections": 78, "simulation_ms_per_frame": 0.070, "views_ms_per_frame": 0.139, "units_alive_max": 116}, + {"view": "mid lane close (zoom 22)", "frames": 3144, "fps": 314.4, "frame_ms_avg": 3.18, "frame_ms_median": 1.90, "frame_ms_p95": 13.25, "frame_ms_p99": 22.21, "frame_ms_max": 25.20, "frames_over_16_7_ms": 102, "of_them_with_simulation_step": 11, "gc_collections": 26, "simulation_ms_per_frame": 0.024, "views_ms_per_frame": 0.137, "units_alive_max": 63} + ] +} diff --git a/docs/port/logs/u2d/player-benchmark-macos.json b/docs/port/logs/u2d/player-benchmark-macos.json new file mode 100644 index 0000000..fdde20e --- /dev/null +++ b/docs/port/logs/u2d/player-benchmark-macos.json @@ -0,0 +1,14 @@ +{ + "build": "OSXPlayer player, 6000.3.20f1, release", + "device": "Mac17,2; Apple M5; Apple M5", + "graphics_api": "Metal", + "resolution": "1920x1080", + "vsync": 0, + "match": "seed 9 from round 21 (fixture high_wave_21), speed 1x, measured after 10 s of combat", + "windows": [ + {"view": "overview (zoom 64)", "frames": 3215, "fps": 160.7, "frame_ms_avg": 6.22, "frame_ms_median": 2.89, "frame_ms_p95": 25.54, "frame_ms_p99": 43.79, "frame_ms_max": 73.93, "frames_over_16_7_ms": 304, "of_them_with_simulation_step": 24, "gc_collections": 77, "simulation_ms_per_frame": 0.072, "views_ms_per_frame": 0.125, "units_alive_max": 116}, + // timings overview (zoom 64): main thread avg 1.33 / median 1.22 / p95 2.00 ms, render thread avg 1.26 / median 1.20 / p95 1.61 ms, gpu avg 0.01 / median 0.00 / p95 0.00 ms, present wait avg 4.89 / median 1.56 / p95 23.96 ms + {"view": "mid lane close (zoom 22)", "frames": 2744, "fps": 274.4, "frame_ms_avg": 3.64, "frame_ms_median": 2.46, "frame_ms_p95": 13.47, "frame_ms_p99": 25.11, "frame_ms_max": 41.03, "frames_over_16_7_ms": 96, "of_them_with_simulation_step": 4, "gc_collections": 26, "simulation_ms_per_frame": 0.027, "views_ms_per_frame": 0.119, "units_alive_max": 63} + // timings mid lane close (zoom 22): main thread avg 0.93 / median 0.89 / p95 1.26 ms, render thread avg 0.92 / median 0.90 / p95 1.13 ms, gpu avg 0.00 / median 0.00 / p95 0.00 ms, present wait avg 2.72 / median 1.55 / p95 12.57 ms + ] +} diff --git a/docs/port/logs/u2d/vertical-function-test.json b/docs/port/logs/u2d/vertical-function-test.json new file mode 100644 index 0000000..759c93c --- /dev/null +++ b/docs/port/logs/u2d/vertical-function-test.json @@ -0,0 +1,16 @@ +{ + "runs": [ + {"label": "match-seed2", "seed": 2, "start_round": 1, "extra_gold": 0, "speed": 6, "winner": 1, "end_note": "Ancient von Blau zerstört.", "steps": 12690, "hash": "DCE95C96556F3A1A", "core_hash": "DCE95C96556F3A1A", "same_as_core": true, + "units_alive_max": 84, "heroes_alive_max": 4, "boss_log": ["round 8: won team 1 ", "round 9: deployed team 1 bot"], + "rounds": [{"round": 1, "combat_seconds": 44.9, "lost": [], "boss": "none", "end": "cleared"}, {"round": 2, "combat_seconds": 57.1, "lost": [], "boss": "none", "end": "cleared"}, {"round": 3, "combat_seconds": 54.1, "lost": [], "boss": "none", "end": "cleared"}, {"round": 4, "combat_seconds": 62.9, "lost": [], "boss": "none", "end": "cleared"}, {"round": 5, "combat_seconds": 60.7, "lost": [], "boss": "none", "end": "cleared"}, {"round": 6, "combat_seconds": 62.1, "lost": [], "boss": "none", "end": "cleared"}, {"round": 7, "combat_seconds": 66.5, "lost": ["blau_bot_outer"], "boss": "none", "end": "cleared"}, {"round": 8, "combat_seconds": 89.65, "lost": ["rot_top_outer", "rot_top_inner"], "boss": "won", "end": "cleared"}, {"round": 9, "combat_seconds": 136.55, "lost": ["blau_bot_inner", "blau_base_2", "blau_base_1", "blau_ancient"], "boss": "deployed", "end": "core"}], + "events": ["round 7: blau_bot_outer destroyed", "round 8: rot_top_outer destroyed", "round 8: rot_top_inner destroyed", "round 8: grotto boss won", "round 9: blau_bot_inner destroyed", "round 9: blau_base_2 destroyed", "round 9: blau_base_1 destroyed", "round 9: blau_ancient destroyed", "round 9: grotto boss deployed"], + "shots": ["01-runde1-aufmarsch", "02-runde1-mid-kampf", "03-turm-faellt", "04-turm-ruine", "05-grotte-bosskampf", "06-held-kaempft", "07-boss-auf-der-lane", "08-ancient-faellt", "09-ancient-ruine", "10-ende-uebersicht"], + "performance": null}, + {"label": "match-seed9-round21", "seed": 9, "start_round": 21, "extra_gold": 4000, "speed": 6, "winner": 0, "end_note": "Ancient von Rot zerstört.", "steps": 4195, "hash": "7B8E43AEFC0D60C5", "core_hash": "7B8E43AEFC0D60C5", "same_as_core": true, + "units_alive_max": 125, "heroes_alive_max": 6, "boss_log": [], + "rounds": [{"round": 21, "combat_seconds": 121.8, "lost": ["rot_mid_outer", "rot_top_outer", "rot_mid_inner"], "boss": "none", "end": "cleared"}, {"round": 22, "combat_seconds": 87.95, "lost": ["rot_top_inner", "rot_base_1", "blau_bot_outer", "rot_base_2", "rot_ancient"], "boss": "none", "end": "core"}], + "events": ["round 21: rot_mid_outer destroyed", "round 21: rot_top_outer destroyed", "round 21: rot_mid_inner destroyed", "round 22: rot_top_inner destroyed", "round 22: rot_base_1 destroyed", "round 22: blau_bot_outer destroyed", "round 22: rot_base_2 destroyed", "round 22: rot_ancient destroyed"], + "shots": ["11-welle21-uebersicht", "12-welle21-kampf", "13-ancient-rot-faellt", "14-welle-ende"], + "performance": {"window": "20 s real time at 1x speed, unlimited frame rate, round 21", "frames": 64198, "fps": 3209.869, "frame_ms_avg": 0.312, "frame_ms_p95": 0.316, "simulation_ms_per_frame": 0.004, "views_ms_per_frame": 0.116, "units_alive_max": 116}} + ] +} diff --git a/docs/port/screenshots/u2d/01-runde1-aufmarsch.png b/docs/port/screenshots/u2d/01-runde1-aufmarsch.png new file mode 100644 index 0000000..0e12fbd Binary files /dev/null and b/docs/port/screenshots/u2d/01-runde1-aufmarsch.png differ diff --git a/docs/port/screenshots/u2d/02-runde1-mid-kampf.png b/docs/port/screenshots/u2d/02-runde1-mid-kampf.png new file mode 100644 index 0000000..d43e233 Binary files /dev/null and b/docs/port/screenshots/u2d/02-runde1-mid-kampf.png differ diff --git a/docs/port/screenshots/u2d/03-turm-faellt.png b/docs/port/screenshots/u2d/03-turm-faellt.png new file mode 100644 index 0000000..248a8ce Binary files /dev/null and b/docs/port/screenshots/u2d/03-turm-faellt.png differ diff --git a/docs/port/screenshots/u2d/04-turm-ruine.png b/docs/port/screenshots/u2d/04-turm-ruine.png new file mode 100644 index 0000000..bb3374d Binary files /dev/null and b/docs/port/screenshots/u2d/04-turm-ruine.png differ diff --git a/docs/port/screenshots/u2d/05-grotte-bosskampf.png b/docs/port/screenshots/u2d/05-grotte-bosskampf.png new file mode 100644 index 0000000..a8f1fb0 Binary files /dev/null and b/docs/port/screenshots/u2d/05-grotte-bosskampf.png differ diff --git a/docs/port/screenshots/u2d/06-held-kaempft.png b/docs/port/screenshots/u2d/06-held-kaempft.png new file mode 100644 index 0000000..05b1226 Binary files /dev/null and b/docs/port/screenshots/u2d/06-held-kaempft.png differ diff --git a/docs/port/screenshots/u2d/07-boss-auf-der-lane.png b/docs/port/screenshots/u2d/07-boss-auf-der-lane.png new file mode 100644 index 0000000..34fb80c Binary files /dev/null and b/docs/port/screenshots/u2d/07-boss-auf-der-lane.png differ diff --git a/docs/port/screenshots/u2d/08-ancient-faellt.png b/docs/port/screenshots/u2d/08-ancient-faellt.png new file mode 100644 index 0000000..3cee2b9 Binary files /dev/null and b/docs/port/screenshots/u2d/08-ancient-faellt.png differ diff --git a/docs/port/screenshots/u2d/09-ancient-ruine.png b/docs/port/screenshots/u2d/09-ancient-ruine.png new file mode 100644 index 0000000..bc491dc Binary files /dev/null and b/docs/port/screenshots/u2d/09-ancient-ruine.png differ diff --git a/docs/port/screenshots/u2d/10-ende-uebersicht.png b/docs/port/screenshots/u2d/10-ende-uebersicht.png new file mode 100644 index 0000000..8aa22db Binary files /dev/null and b/docs/port/screenshots/u2d/10-ende-uebersicht.png differ diff --git a/docs/port/screenshots/u2d/11-welle21-uebersicht.png b/docs/port/screenshots/u2d/11-welle21-uebersicht.png new file mode 100644 index 0000000..a4b5148 Binary files /dev/null and b/docs/port/screenshots/u2d/11-welle21-uebersicht.png differ diff --git a/docs/port/screenshots/u2d/12-welle21-kampf.png b/docs/port/screenshots/u2d/12-welle21-kampf.png new file mode 100644 index 0000000..0f5f68e Binary files /dev/null and b/docs/port/screenshots/u2d/12-welle21-kampf.png differ diff --git a/docs/port/screenshots/u2d/13-ancient-rot-faellt.png b/docs/port/screenshots/u2d/13-ancient-rot-faellt.png new file mode 100644 index 0000000..a715f39 Binary files /dev/null and b/docs/port/screenshots/u2d/13-ancient-rot-faellt.png differ diff --git a/docs/port/screenshots/u2d/14-welle-ende.png b/docs/port/screenshots/u2d/14-welle-ende.png new file mode 100644 index 0000000..2314c7b Binary files /dev/null and b/docs/port/screenshots/u2d/14-welle-ende.png differ