feat: add GiantMuseum package with deploy & core utilities

main
uc-hoba 3 weeks ago
parent bbb6cd59e6
commit a3d6a53f0f
  1. 77
      .editorconfig
  2. 3
      .gitignore
  3. 47
      Assets/Main/GlobalVolumeProfile.asset
  4. 18
      Assets/NuGet.config
  5. 28
      Assets/NuGet.config.meta
  6. 8
      Assets/Packages.meta
  7. 8
      Assets/Scripts.meta
  8. 16
      Assets/Scripts/GroundControl.cs
  9. 2
      Assets/Scripts/GroundControl.cs.meta
  10. 92
      Assets/TiltShift/Shaders/TiltShift.shader
  11. 181
      Assets/TiltShift/TiltShiftFeature.cs
  12. 2
      Assets/packages.config
  13. 28
      Assets/packages.config.meta
  14. 77
      Packages/com.ultracombos.giant-museum/.editorconfig
  15. 81
      Packages/com.ultracombos.giant-museum/.gitignore
  16. 8
      Packages/com.ultracombos.giant-museum/Editor.meta
  17. 182
      Packages/com.ultracombos.giant-museum/Editor/Deploy.cs
  18. 11
      Packages/com.ultracombos.giant-museum/Editor/Deploy.cs.meta
  19. 13
      Packages/com.ultracombos.giant-museum/Editor/ReadOnlyDrawer.cs
  20. 2
      Packages/com.ultracombos.giant-museum/Editor/ReadOnlyDrawer.cs.meta
  21. 18
      Packages/com.ultracombos.giant-museum/Editor/UltraCombos.GiantMuseum.Editor.asmdef
  22. 7
      Packages/com.ultracombos.giant-museum/Editor/UltraCombos.GiantMuseum.Editor.asmdef.meta
  23. 8
      Packages/com.ultracombos.giant-museum/Runtime.meta
  24. 48
      Packages/com.ultracombos.giant-museum/Runtime/Core.cs
  25. 11
      Packages/com.ultracombos.giant-museum/Runtime/Core.cs.meta
  26. 150
      Packages/com.ultracombos.giant-museum/Runtime/Define.cs
  27. 11
      Packages/com.ultracombos.giant-museum/Runtime/Define.cs.meta
  28. 95
      Packages/com.ultracombos.giant-museum/Runtime/DisplayConfig.cs
  29. 11
      Packages/com.ultracombos.giant-museum/Runtime/DisplayConfig.cs.meta
  30. 79
      Packages/com.ultracombos.giant-museum/Runtime/DotNetEnv.cs
  31. 2
      Packages/com.ultracombos.giant-museum/Runtime/DotNetEnv.cs.meta
  32. 21
      Packages/com.ultracombos.giant-museum/Runtime/ForceUpdater.cs
  33. 11
      Packages/com.ultracombos.giant-museum/Runtime/ForceUpdater.cs.meta
  34. 16
      Packages/com.ultracombos.giant-museum/Runtime/Log.cs
  35. 2
      Packages/com.ultracombos.giant-museum/Runtime/Log.cs.meta
  36. 3
      Packages/com.ultracombos.giant-museum/Runtime/ReadOnlyAttribute.cs
  37. 2
      Packages/com.ultracombos.giant-museum/Runtime/ReadOnlyAttribute.cs.meta
  38. 61
      Packages/com.ultracombos.giant-museum/Runtime/Singleton.cs
  39. 11
      Packages/com.ultracombos.giant-museum/Runtime/Singleton.cs.meta
  40. 16
      Packages/com.ultracombos.giant-museum/Runtime/UltraCombos.GiantMuseum.Runtime.asmdef
  41. 7
      Packages/com.ultracombos.giant-museum/Runtime/UltraCombos.GiantMuseum.Runtime.asmdef.meta
  42. 13
      Packages/com.ultracombos.giant-museum/package.json
  43. 7
      Packages/com.ultracombos.giant-museum/package.json.meta
  44. 54
      Packages/manifest.json
  45. 289
      Packages/packages-lock.json
  46. 40
      ProjectSettings/PackageManagerSettings.asset
  47. 29
      Unity-25014-ReadySetRide.slnx

@ -0,0 +1,77 @@
# Visual Studio Reference: https://docs.microsoft.com/en-us/visualstudio/ide/create-portable-custom-editor-options
# Rider Reference: https://www.jetbrains.com/help/rider/EditorConfig_Index.html
# Top-most EditorConfig file
root = true
[*]
indent_style = space
[*.{json,asmdef}]
indent_size = 2
[*.cs]
# Basic Text Settings
indent_size = 4
insert_final_newline = true
max_line_length = 120
trim_trailing_whitespace = true
charset = utf-8
# C# Code Style Settings
# Require accessibility modifiers (e.g., private, public), do not omit
dotnet_style_require_accessibility_modifiers = always:warning
# Avoid "this." unless necessary
dotnet_style_qualification_for_field = false:warning
dotnet_style_qualification_for_property = false:warning
dotnet_style_qualification_for_method = false:warning
dotnet_style_qualification_for_event = false:warning
# Use language keywords (e.g., int) instead of framework type names (e.g., Int32)
dotnet_style_predefined_type_for_locals_parameters_members = true:warning
dotnet_style_predefined_type_for_member_access = true:warning
# Prefer "var"
csharp_style_var_for_built_in_types = true:warning
csharp_style_var_when_type_is_apparent = true:warning
csharp_style_var_elsewhere = true:warning
# Prefer braces even for single-line statements
csharp_prefer_braces = true:warning
# Formatting details
csharp_space_after_cast = false
csharp_preserve_single_line_blocks = true
csharp_space_within_single_line_array_initializer_braces = true
# Naming Conventions
# 1. Define symbol groups
# All fields (variables)
dotnet_naming_symbols.all_fields.applicable_kinds = field
dotnet_naming_symbols.all_fields.applicable_accessibilities = *
# Properties
dotnet_naming_symbols.all_properties.applicable_kinds = property
dotnet_naming_symbols.all_properties.applicable_accessibilities = *
# 2. Define naming styles
# camelCase
dotnet_naming_style.style_camel_case.capitalization = camel_case
# PascalCase
dotnet_naming_style.style_pascal_case.capitalization = pascal_case
# 3. Define rules
# Rule: Use camelCase for all fields (both public and private)
dotnet_naming_rule.fields_must_be_camel_case.symbols = all_fields
dotnet_naming_rule.fields_must_be_camel_case.style = style_camel_case
dotnet_naming_rule.fields_must_be_camel_case.severity = warning
# Rule: Use PascalCase for properties
dotnet_naming_rule.properties_must_be_pascal_case.symbols = all_properties
dotnet_naming_rule.properties_must_be_pascal_case.style = style_pascal_case
dotnet_naming_rule.properties_must_be_pascal_case.severity = warning

3
.gitignore vendored

@ -70,3 +70,6 @@ crashlytics-build.properties
# Temporary auto-generated Android Assets
/[Aa]ssets/[Ss]treamingAssets/aa.meta
/[Aa]ssets/[Ss]treamingAssets/aa/*
# Custom
*.csproj.lscache

@ -99,52 +99,6 @@ MonoBehaviour:
m_Value: {x: 0, y: 0.5}
min: 0
max: 2
--- !u!114 &-5474690943039039243
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: 0
mode:
m_OverrideState: 1
m_Value: 2
gaussianStart:
m_OverrideState: 1
m_Value: 60
gaussianEnd:
m_OverrideState: 1
m_Value: 70
gaussianMaxRadius:
m_OverrideState: 1
m_Value: 1
highQualitySampling:
m_OverrideState: 1
m_Value: 0
focusDistance:
m_OverrideState: 1
m_Value: 60
aperture:
m_OverrideState: 1
m_Value: 1
focalLength:
m_OverrideState: 1
m_Value: 300
bladeCount:
m_OverrideState: 0
m_Value: 5
bladeCurvature:
m_OverrideState: 0
m_Value: 1
bladeRotation:
m_OverrideState: 0
m_Value: 0
--- !u!114 &-32820517437979890
MonoBehaviour:
m_ObjectHideFlags: 3
@ -210,7 +164,6 @@ MonoBehaviour:
components:
- {fileID: 1881579288749618558}
- {fileID: -32820517437979890}
- {fileID: -5474690943039039243}
- {fileID: -6989835814840294288}
--- !u!114 &1881579288749618558
MonoBehaviour:

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" enableCredentialProvider="false" />
</packageSources>
<disabledPackageSources />
<activePackageSource>
<add key="All" value="(Aggregate source)" />
</activePackageSource>
<config>
<add key="packageInstallLocation" value="CustomWithinAssets" />
<add key="repositoryPath" value="./Packages" />
<add key="PackagesConfigDirectoryPath" value="." />
<add key="slimRestore" value="true" />
<add key="PreferNetStandardOverNetFramework" value="true" />
</config>
</configuration>

@ -0,0 +1,28 @@
fileFormatVersion: 2
guid: dac4df2f30345e74589a00c80f392aa2
labels:
- NuGetForUnity
PluginImporter:
externalObjects: {}
serializedVersion: 3
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
Any:
enabled: 0
settings: {}
Editor:
enabled: 0
settings:
DefaultValueInitialized: true
WindowsStoreApps:
enabled: 0
settings: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 26aec5e520aedf4459f70238f1d4c30e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1ef755df0e033724aa722a2976b1614e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,16 @@
using UnityEngine;
public class GroundControl : MonoBehaviour
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 3f58a2d2c726666469a5aa224f7227bc

@ -8,72 +8,110 @@ Shader "Custom/TiltShift"
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
// DeclareDepthTexture provides TEXTURE2D_X_FLOAT(_CameraDepthTexture) and SampleSceneDepth().
// Include unconditionally; it is only sampled in DEPTH_MODE branches.
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
float _TiltShift_CenterOffset;
float _TiltShift_FocusWidth;
float _TiltShift_FalloffRange;
float _TiltShift_MaxBlurRadius;
int _TiltShift_SampleCount;
// ── Mode selection ──────────────────────────────────────────────────────────
// DEPTH_MODE: Scheimpflug-based (uses depth buffer). Default: screen-space.
#pragma multi_compile_local _ DEPTH_MODE
// _BlitTexture and _BlitTexture_TexelSize are provided by Blit.hlsl
// _BlitTexture_TexelSize: (1/w, 1/h, w, h)
// sampler_LinearClamp is provided by GlobalSamplers.hlsl (included via Blit.hlsl)
// ── Shared parameters ───────────────────────────────────────────────────────
float _TiltShift_MaxBlurRadius; // max blur in pixels
int _TiltShift_SampleCount; // samples per side per pass
// Returns blur radius in pixels for a given vertical UV coordinate.
float ComputeBlurRadius(float uvY)
// ── Screen-space mode ───────────────────────────────────────────────────────
float _TiltShift_CenterOffset; // vertical offset of sharp band (UV units, +up)
float _TiltShift_FocusWidth; // full height of sharp band as fraction of screen
float _TiltShift_FalloffRange; // blur fade-in distance in UV units
// ── Depth mode (Scheimpflug / tilt plane) ───────────────────────────────────
// _CameraDepthTexture and _ZBufferParams are provided by URP / DeclareDepthTexture.hlsl.
float _TiltShift_FocusDistance; // world-space depth of the focal plane centre
float _TiltShift_TiltFactor; // world-space depth shift per UV unit of screen height
// positive → top focuses farther (typical bird's-eye)
float _TiltShift_FocusBand; // half-width of the sharp zone in world units
float _TiltShift_DepthFalloff; // blur ramp width in world units
// ── Blur radius computation ─────────────────────────────────────────────────
float ComputeBlurRadius(float2 uv)
{
float dist = abs(uvY - 0.5 + _TiltShift_CenterOffset);
#if defined(DEPTH_MODE)
// ----------------------------------------------------------------
// Scheimpflug tilt-plane CoC
// SampleSceneDepth uses TEXTURE2D_X_FLOAT + point-clamp (from DeclareDepthTexture.hlsl).
// ----------------------------------------------------------------
float rawDepth = SampleSceneDepth(uv);
float eyeDepth = LinearEyeDepth(rawDepth, _ZBufferParams);
// Depth of the focus plane at this screen row:
// uv.y = 0 → bottom, uv.y = 1 → top (OpenGL-style; URP handles flip internally)
float focusAtY = _TiltShift_FocusDistance + _TiltShift_TiltFactor * (uv.y - 0.5);
float distToPlane = abs(eyeDepth - focusAtY);
float band = max(_TiltShift_FocusBand, 0.001);
float falloff = max(_TiltShift_DepthFalloff, 0.001);
return smoothstep(band, band + falloff, distToPlane) * _TiltShift_MaxBlurRadius;
#else
// ----------------------------------------------------------------
// Screen-space approximation (no depth buffer needed)
// ----------------------------------------------------------------
float dist = abs(uv.y - 0.5 + _TiltShift_CenterOffset);
float halfFocus = _TiltShift_FocusWidth * 0.5;
float range = max(_TiltShift_FalloffRange, 0.001);
float range = max(_TiltShift_FalloffRange, 0.001);
return smoothstep(halfFocus, halfFocus + range, dist) * _TiltShift_MaxBlurRadius;
#endif
}
// Gaussian blur in an arbitrary direction.
// direction: offset per sample step in UV space (already multiplied by texelSize)
// ── Separable Gaussian blur ─────────────────────────────────────────────────
// stepUV = one sample offset in UV space (direction × pixelSize)
float4 GaussianBlur(float2 uv, float2 stepUV)
{
int n = max(1, _TiltShift_SampleCount);
float4 color = 0;
float totalWeight = 0;
float totalWeight = 0;
[loop]
for (int i = -n; i <= n; i++)
{
// t in [-1, 1]; weight peaks at centre and falls near edges.
// t ∈ [−1, 1]; gaussian shaped so weight → ~0 at the extremes
float t = float(i) / float(n);
float weight = exp(-4.5 * t * t);
float2 sampleUV = uv + stepUV * float(i);
color += SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_LinearClamp, sampleUV, 0) * weight;
color += SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_LinearClamp, uv + stepUV * float(i), 0) * weight;
totalWeight += weight;
}
return color / totalWeight;
}
// ── Fragment shaders ────────────────────────────────────────────────────────
float4 HorizontalBlur(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = input.texcoord;
float radius = ComputeBlurRadius(uv.y);
float2 uv = input.texcoord;
float radius = ComputeBlurRadius(uv);
if (radius < 0.5)
return SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_LinearClamp, uv, 0);
// stepUV: one step in the horizontal direction, spread over [−radius, +radius] pixels
int n = max(1, _TiltShift_SampleCount);
float2 stepUV = float2((radius / float(n)) * _BlitTexture_TexelSize.x, 0.0);
int n = max(1, _TiltShift_SampleCount);
float2 stepUV = float2((radius / float(n)) * _BlitTexture_TexelSize.x, 0.0);
return GaussianBlur(uv, stepUV);
}
float4 VerticalBlur(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = input.texcoord;
float radius = ComputeBlurRadius(uv.y);
float2 uv = input.texcoord;
float radius = ComputeBlurRadius(uv);
if (radius < 0.5)
return SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_LinearClamp, uv, 0);
int n = max(1, _TiltShift_SampleCount);
float2 stepUV = float2(0.0, (radius / float(n)) * _BlitTexture_TexelSize.y);
int n = max(1, _TiltShift_SampleCount);
float2 stepUV = float2(0.0, (radius / float(n)) * _BlitTexture_TexelSize.y);
return GaussianBlur(uv, stepUV);
}
ENDHLSL

@ -4,12 +4,35 @@ using UnityEngine.Rendering.Universal;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering.RenderGraphModule.Util;
/// <summary>
/// Tilt-shift (移軸鏡) post-process effect for URP 17 (Unity 6).
///
/// Two modes:
/// • ScreenSpace — blur based on vertical screen position (fast, camera-angle dependent).
/// • DepthBased — Scheimpflug tilt-plane CoC using the depth buffer (physically accurate).
/// </summary>
public class TiltShiftFeature : ScriptableRendererFeature
{
public enum BlurMode
{
/// <summary>Blur based on vertical UV position. No depth buffer required.</summary>
ScreenSpace,
/// <summary>
/// Blur based on distance from a tilted focal plane in world space (Scheimpflug principle).
/// Requires the camera's Depth Texture to be enabled.
/// </summary>
DepthBased
}
[System.Serializable]
public class Settings
{
[Tooltip("Vertical offset of the sharp focus band from screen centre. Positive = up.")]
[Tooltip("ScreenSpace: blur by vertical screen position.\n" +
"DepthBased: physically-accurate Scheimpflug tilt-plane CoC (needs Depth Texture).")]
public BlurMode blurMode = BlurMode.ScreenSpace;
[Header("Screen-Space Mode")]
[Tooltip("Vertical offset of the sharp band from screen centre (UV units, + = up).")]
[Range(-0.4f, 0.4f)]
public float centerOffset = 0f;
@ -17,15 +40,36 @@ public class TiltShiftFeature : ScriptableRendererFeature
[Range(0.01f, 0.8f)]
public float focusWidth = 0.2f;
[Tooltip("Distance over which blur fades in at each edge of the focus band.")]
[Tooltip("Distance over which blur fades in at each edge of the focus band (UV units).")]
[Range(0.01f, 0.4f)]
public float falloffRange = 0.15f;
[Tooltip("Maximum blur radius in pixels at the extreme top and bottom.")]
[Header("Depth-Based Mode (Scheimpflug)")]
[Tooltip("Depth of the focal plane centre (world units). " +
"Increase until the subject you want sharp is in focus.")]
[Range(0.1f, 1000f)]
public float focusDistance = 10f;
[Tooltip("How much the focal plane depth shifts per screen-height unit.\n" +
"Positive → top of screen focuses deeper (typical for bird's-eye view).\n" +
"Set to 0 for standard (flat) DoF.")]
[Range(-200f, 200f)]
public float tiltFactor = 30f;
[Tooltip("Half-width of the perfectly sharp zone around the focal plane (world units).")]
[Range(0f, 50f)]
public float focusBand = 1f;
[Tooltip("World-unit distance over which blur ramps from zero to maximum.")]
[Range(0.1f, 100f)]
public float depthFalloff = 5f;
[Header("Shared")]
[Tooltip("Maximum blur radius in pixels at the extremes.")]
[Range(1f, 64f)]
public float maxBlurRadius = 20f;
[Tooltip("Samples per side per pass (higher = smoother blur, higher cost).")]
[Tooltip("Gaussian samples per side per pass. Higher = smoother, slower.")]
[Range(2, 20)]
public int sampleCount = 8;
@ -35,32 +79,33 @@ public class TiltShiftFeature : ScriptableRendererFeature
public Settings settings = new Settings();
TiltShiftPass _pass;
Material _material;
Material _material;
// ── Lifecycle ──────────────────────────────────────────────────────────────────
public override void Create()
{
var shader = Shader.Find("Custom/TiltShift");
if (shader == null)
{
Debug.LogWarning("[TiltShift] Shader 'Custom/TiltShift' not found. " +
"Make sure TiltShift.shader is in the project.");
Debug.LogWarning("[TiltShift] Shader 'Custom/TiltShift' not found.");
return;
}
_material = CoreUtils.CreateEngineMaterial(shader);
_pass = new TiltShiftPass(_material, settings);
_pass.renderPassEvent = settings.injectionPoint;
_material = CoreUtils.CreateEngineMaterial(shader);
_pass = new TiltShiftPass(_material, settings);
_pass.renderPassEvent = settings.injectionPoint;
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (_material == null || _pass == null) return;
// Skip scene view and preview cameras to avoid visual noise.
var camType = renderingData.cameraData.cameraType;
if (camType == CameraType.Preview || camType == CameraType.Reflection) return;
_pass.UpdateSettings(settings);
_pass.renderPassEvent = settings.injectionPoint;
renderer.EnqueuePass(_pass);
}
@ -69,27 +114,45 @@ public class TiltShiftFeature : ScriptableRendererFeature
CoreUtils.Destroy(_material);
}
// -------------------------------------------------------------------------
// ── Inner render pass ──────────────────────────────────────────────────────────
class TiltShiftPass : ScriptableRenderPass
sealed class TiltShiftPass : ScriptableRenderPass
{
// Shader property IDs
static readonly int s_MaxBlurRadius = Shader.PropertyToID("_TiltShift_MaxBlurRadius");
static readonly int s_SampleCount = Shader.PropertyToID("_TiltShift_SampleCount");
static readonly int s_CenterOffset = Shader.PropertyToID("_TiltShift_CenterOffset");
static readonly int s_FocusWidth = Shader.PropertyToID("_TiltShift_FocusWidth");
static readonly int s_FalloffRange = Shader.PropertyToID("_TiltShift_FalloffRange");
static readonly int s_MaxBlurRadius = Shader.PropertyToID("_TiltShift_MaxBlurRadius");
static readonly int s_SampleCount = Shader.PropertyToID("_TiltShift_SampleCount");
static readonly int s_FocusDistance = Shader.PropertyToID("_TiltShift_FocusDistance");
static readonly int s_TiltFactor = Shader.PropertyToID("_TiltShift_TiltFactor");
static readonly int s_FocusBand = Shader.PropertyToID("_TiltShift_FocusBand");
static readonly int s_DepthFalloff = Shader.PropertyToID("_TiltShift_DepthFalloff");
// Shader keyword for mode switch
const string k_DepthModeKeyword = "DEPTH_MODE";
readonly Material _material;
Settings _settings;
Settings _settings;
// PassData carries what the render func needs at execution time.
class PassData
{
public TextureHandle source;
public Material material;
public int passIndex;
}
public TiltShiftPass(Material material, Settings settings)
{
_material = material;
_settings = settings;
_material = material;
_settings = settings;
requiresIntermediateTexture = true;
}
public void UpdateSettings(Settings settings) => _settings = settings;
public void UpdateSettings(Settings s) => _settings = s;
// ── RecordRenderGraph ──────────────────────────────────────────────────────
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
@ -98,35 +161,85 @@ public class TiltShiftFeature : ScriptableRendererFeature
if (resourceData.isActiveTargetBackBuffer)
return;
// Push current settings to the material.
bool useDepth = _settings.blurMode == BlurMode.DepthBased;
// Validate depth texture availability.
if (useDepth && !resourceData.cameraDepthTexture.IsValid())
{
Debug.LogWarning("[TiltShift] DepthBased mode requires the camera's Depth Texture. " +
"Enable it in the URP Renderer asset or Camera component.");
useDepth = false;
}
// ── Push settings to material ──────────────────────────────────────────
_material.SetFloat(s_MaxBlurRadius, _settings.maxBlurRadius);
_material.SetInt (s_SampleCount, _settings.sampleCount);
_material.SetFloat(s_CenterOffset, _settings.centerOffset);
_material.SetFloat(s_FocusWidth, _settings.focusWidth);
_material.SetFloat(s_FalloffRange, _settings.falloffRange);
_material.SetFloat(s_MaxBlurRadius, _settings.maxBlurRadius);
_material.SetInt(s_SampleCount, _settings.sampleCount);
_material.SetFloat(s_FocusDistance, _settings.focusDistance);
_material.SetFloat(s_TiltFactor, _settings.tiltFactor);
_material.SetFloat(s_FocusBand, _settings.focusBand);
_material.SetFloat(s_DepthFalloff, _settings.depthFalloff);
if (useDepth) _material.EnableKeyword(k_DepthModeKeyword);
else _material.DisableKeyword(k_DepthModeKeyword);
// ── Texture handles ────────────────────────────────────────────────────
var source = resourceData.activeColorTexture;
var depth = useDepth ? resourceData.cameraDepthTexture : TextureHandle.nullHandle;
// Intermediate texture for horizontal-blur result.
var desc = renderGraph.GetTextureDesc(source);
desc.clearBuffer = false;
desc.name = "TiltShift_Temp";
TextureHandle temp = renderGraph.CreateTexture(desc);
// Final texture for vertical-blur result.
desc.name = "TiltShift_Final";
desc.name = "TiltShift_Temp";
TextureHandle temp = renderGraph.CreateTexture(desc);
desc.name = "TiltShift_Final";
TextureHandle final = renderGraph.CreateTexture(desc);
// Pass 0 — horizontal blur: source → temp
var paraH = new RenderGraphUtils.BlitMaterialParameters(source, temp, _material, 0);
renderGraph.AddBlitPass(paraH, passName: "TiltShift_H");
// ── Pass 0 — Horizontal blur (source → temp) ──────────────────────────
AddBlurPass(renderGraph, "TiltShift_H", source, depth, temp, passIndex: 0, useDepth);
// Pass 1 — vertical blur: temp → final
var paraV = new RenderGraphUtils.BlitMaterialParameters(temp, final, _material, 1);
renderGraph.AddBlitPass(paraV, passName: "TiltShift_V");
// ── Pass 1 — Vertical blur (temp → final) ────────────────────────────
AddBlurPass(renderGraph, "TiltShift_V", temp, depth, final, passIndex: 1, useDepth);
// Redirect the camera colour so subsequent passes see our result.
// Redirect camera colour so subsequent passes use our result.
resourceData.cameraColor = final;
}
// ── Helper to record one blur pass ─────────────────────────────────────────
void AddBlurPass(
RenderGraph renderGraph,
string passName,
TextureHandle source,
TextureHandle depth,
TextureHandle dest,
int passIndex,
bool useDepth)
{
using var builder = renderGraph.AddRasterRenderPass<PassData>(passName, out var passData);
passData.source = source;
passData.material = _material;
passData.passIndex = passIndex;
builder.UseTexture(source, AccessFlags.Read);
// Declare the dependency on the depth texture so the render graph correctly
// orders this pass after URP's CopyDepthPass. We do NOT call SetGlobalTexture
// here — URP's CopyDepthPass already exposes _CameraDepthTexture globally via
// SetGlobalTextureAfterPass, so the shader can sample it without any extra work.
if (useDepth && depth.IsValid())
builder.UseTexture(depth, AccessFlags.Read);
builder.SetRenderAttachment(dest, 0, AccessFlags.Write);
builder.SetRenderFunc((PassData data, RasterGraphContext ctx) =>
{
Blitter.BlitTexture(ctx.cmd, data.source, new Vector4(1, 1, 0, 0),
data.material, data.passIndex);
});
}
}
}

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<packages />

@ -0,0 +1,28 @@
fileFormatVersion: 2
guid: 97b3022388ed5df4f909d9f53d8cb399
labels:
- NuGetForUnity
PluginImporter:
externalObjects: {}
serializedVersion: 3
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
Any:
enabled: 0
settings: {}
Editor:
enabled: 0
settings:
DefaultValueInitialized: true
WindowsStoreApps:
enabled: 0
settings: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,77 @@
# Visual Studio Reference: https://docs.microsoft.com/en-us/visualstudio/ide/create-portable-custom-editor-options
# Rider Reference: https://www.jetbrains.com/help/rider/EditorConfig_Index.html
# Top-most EditorConfig file
root = true
[*]
indent_style = space
[*.{json,asmdef}]
indent_size = 2
[*.cs]
# Basic Text Settings
indent_size = 4
insert_final_newline = true
max_line_length = 120
trim_trailing_whitespace = true
charset = utf-8
# C# Code Style Settings
# Require accessibility modifiers (e.g., private, public), do not omit
dotnet_style_require_accessibility_modifiers = always:warning
# Avoid "this." unless necessary
dotnet_style_qualification_for_field = false:warning
dotnet_style_qualification_for_property = false:warning
dotnet_style_qualification_for_method = false:warning
dotnet_style_qualification_for_event = false:warning
# Use language keywords (e.g., int) instead of framework type names (e.g., Int32)
dotnet_style_predefined_type_for_locals_parameters_members = true:warning
dotnet_style_predefined_type_for_member_access = true:warning
# Prefer "var"
csharp_style_var_for_built_in_types = true:warning
csharp_style_var_when_type_is_apparent = true:warning
csharp_style_var_elsewhere = true:warning
# Prefer braces even for single-line statements
csharp_prefer_braces = true:warning
# Formatting details
csharp_space_after_cast = false
csharp_preserve_single_line_blocks = true
csharp_space_within_single_line_array_initializer_braces = true
# Naming Conventions
# 1. Define symbol groups
# All fields (variables)
dotnet_naming_symbols.all_fields.applicable_kinds = field
dotnet_naming_symbols.all_fields.applicable_accessibilities = *
# Properties
dotnet_naming_symbols.all_properties.applicable_kinds = property
dotnet_naming_symbols.all_properties.applicable_accessibilities = *
# 2. Define naming styles
# camelCase
dotnet_naming_style.style_camel_case.capitalization = camel_case
# PascalCase
dotnet_naming_style.style_pascal_case.capitalization = pascal_case
# 3. Define rules
# Rule: Use camelCase for all fields (both public and private)
dotnet_naming_rule.fields_must_be_camel_case.symbols = all_fields
dotnet_naming_rule.fields_must_be_camel_case.style = style_camel_case
dotnet_naming_rule.fields_must_be_camel_case.severity = warning
# Rule: Use PascalCase for properties
dotnet_naming_rule.properties_must_be_pascal_case.symbols = all_properties
dotnet_naming_rule.properties_must_be_pascal_case.style = style_pascal_case
dotnet_naming_rule.properties_must_be_pascal_case.severity = warning

@ -0,0 +1,81 @@
# This .gitignore file should be placed at the root of your Unity project directory
#
# Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore
#
/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/[Ll]ogs/
/[Uu]ser[Ss]ettings/
# MemoryCaptures can get excessive in size.
# They also could contain extremely sensitive data
/[Mm]emoryCaptures/
# Asset meta data should only be ignored when the corresponding asset is also ignored
!/[Aa]ssets/**/*.meta
# Uncomment this line if you wish to ignore the asset store tools plugin
# /[Aa]ssets/AssetStoreTools*
# Autogenerated Jetbrains Rider plugin
/[Aa]ssets/Plugins/Editor/JetBrains*
# Visual Studio cache directory
.vs/
# Gradle cache directory
.gradle/
# Autogenerated VS/MD/Consulo solution and project files
ExportedObj/
.consulo/
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd
*.pdb
*.mdb
*.opendb
*.VC.db
# Unity3D generated meta files
*.pidb.meta
*.pdb.meta
*.mdb.meta
# Unity3D generated file on crash reports
sysinfo.txt
# Builds
*.apk
*.unitypackage
*.unitypackage.meta
# Crashlytics generated file
crashlytics-build.properties
# Packed Addressables
/[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin*
# Temporary auto-generated Android Assets
/[Aa]ssets/[Ss]treamingAssets/aa.meta
/[Aa]ssets/[Ss]treamingAssets/aa/*
# Visual Studio Code
/.vscode/
# Rider
/.idea/
# Custom
.vsconfig
.claude

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4a919d6d440ab9846b7755d9e4f6cece
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,182 @@
#if UNITY_EDITOR
using System.IO;
using System.Linq;
using UnityEditor;
namespace UltraCombos
{
public class Deploy
{
private const string head = "[Giant Museum]";
[MenuItem(head + "/Build Project")]
public static void BuildProject()
{
Build(new BuildPlayerOptions()
{
scenes = CollectScenesPath(),
locationPathName = PlayerOutputPath,
target = EditorUserBuildSettings.activeBuildTarget,
options = BuildOptions.None,
});
}
/*
[MenuItem( head + "/Build Development" )]
public static void BuildProjectDevelopement()
{
Build( new BuildPlayerOptions()
{
scenes = CollectScenesPath(),
locationPathName = DevelopmentOutputFolder,
target = EditorUserBuildSettings.activeBuildTarget,
//options = BuildOptions.Development | BuildOptions.SymlinkLibraries,
options = BuildOptions.Development,
} );
}
*/
private static void Build(BuildPlayerOptions options)
{
BuildPlayer(options);
GenerateIgnoreFile();
GenerateAttributeFile();
#if UNITY_STANDALONE_WIN
GenerateBatchFile();
#endif
}
[MenuItem(head + "/Open Output Folder")]
public static void OpenFolder()
{
EditorUtility.RevealInFinder(RootOutputFolder);
}
private static string[] CollectScenesPath()
{
return EditorBuildSettings.scenes.Where(s => s.enabled).Select(s => s.path).ToArray();
}
private static string CheckFolder(string path)
{
if (Directory.Exists(path) == false)
{
Log.Info("Deploy", $"Create directory: {path}");
Directory.CreateDirectory(path);
}
return path;
}
private static string RootOutputFolder
{
get
{
var path = Core.BuildPath;
CheckFolder($"{path}/Material");
return CheckFolder(path);
}
}
private static string PlayerOutputFolder
{
get
{
var path = $"{RootOutputFolder}/{Core.OutputFolderName}";
return CheckFolder(path);
}
}
private static string DevelopmentOutputFolder
{
get
{
var path = $"{RootOutputFolder}/{Core.OutputFolderName} - Dev";
return CheckFolder(path);
}
}
private static string PlayerOutputPath
{
get
{
#if UNITY_STANDALONE_WIN
return $"{PlayerOutputFolder}/{PlayerSettings.productName}.exe";
#elif UNITY_ANDROID
return $"{PlayerOutputFolder}.apk";
#else
return $"{PlayerOutputFolder}";
#endif
}
}
private static void BuildPlayer(BuildPlayerOptions buildPlayerOptions)
{
var report = BuildPipeline.BuildPlayer(buildPlayerOptions);
var summary = report.summary;
var totalSizeMB = summary.totalSize / 1024.0 / 1024.0;
Log.Info("Deploy", $"Build {summary.result}: {totalSizeMB:N2} MB");
}
#if UNITY_EDITOR_WIN
private static void GenerateBatchFile()
{
var path = $"{RootOutputFolder}/startup.bat";
if (File.Exists(path))
{
return;
}
var contents = $@"@ECHO OFF
SETLOCAL
SET ""BASE_DIR=%~dp0""
ECHO Starting {PlayerSettings.productName}...
START """" /D ""%BASE_DIR%{Core.OutputFolderName}"" ""{PlayerSettings.productName}.exe""
TIMEOUT /t 10
ECHO All programs started.";
File.WriteAllText(path, contents, System.Text.Encoding.Default);
Log.Info("Deploy", $"Generate batch file: {path}");
}
#endif
private static void GenerateIgnoreFile()
{
var path = $"{RootOutputFolder}/.gitignore";
if (File.Exists(path))
{
return;
}
var contents = "\n";
File.WriteAllText(path, contents);
Log.Info("Deploy", $"Generate ignore file: {path}");
}
private static void GenerateAttributeFile()
{
var filename = ".gitattributes";
var destPath = Path.Combine(RootOutputFolder, filename);
if (!File.Exists(filename) || File.Exists(destPath))
{
return;
}
var name = Core.OutputFolderName;
var suffix = "filter=lfs diff=lfs merge=lfs";
var baseContent = File.ReadAllText(filename);
var newLines = $@"
# Build Output
Materials/**
{name}/** {suffix}
";
File.WriteAllText(destPath, baseContent + "\n" + newLines.Trim());
Log.Info("Deploy", $"Generate attribute file: {destPath}");
}
}
}
#endif

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3f893003e6b7226428811d6c5a07f82f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,13 @@
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(ReadOnlyAttribute))]
public class ReadOnlyDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
GUI.enabled = false;
EditorGUI.PropertyField(position, property, label, true);
GUI.enabled = true;
}
}

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 364be54ac7969f6418f79eb8e85de2de

@ -0,0 +1,18 @@
{
"name": "UltraCombos.GiantMuseum.Editor",
"rootNamespace": "UltraCombos.GiantMuseum",
"references": [
"GUID:b2e08e75d81bb8b408397e7998130fbb"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: bc7633bff7d9fb941a66c76cbb3de878
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9fdba1625ae889b4cb89256f3dc4aa51
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,48 @@
using UnityEngine;
namespace UltraCombos
{
public class Core
{
public static class Project
{
public static int Serial => 25014;
}
#if UNITY_EDITOR
public static string OutputFolderName
{
get
{
return $"{UnityEditor.PlayerSettings.productName.Replace(" ", "")}";
}
}
#endif
public static string BuildPath
{
get
{
#if UNITY_EDITOR
var path = $"{Application.dataPath}/../../../../Deploy/Build-{OutputFolderName}";
#else
#if UNITY_STANDALONE
var path = $"{Application.dataPath}/../..";
#else
var path = $"{Application.persistentDataPath}";
#endif
#endif
var dir = new System.IO.DirectoryInfo(path);
return dir.FullName;
}
}
public static string MaterialPath
{
get { return $"{BuildPath}/Material"; }
}
}
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cff989983e378fd45bbc38525908aefd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,150 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
namespace UltraCombos
{
public class Misc
{
public static object GetInstanceField(System.Type type, object instance, string fieldName)
{
var bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
var field = type.GetField(fieldName, bindFlags);
return field.GetValue(instance);
}
public static string NameOfCallingClass()
{
string fullName;
System.Type declaringType;
var skipFrames = 2;
do
{
var method = new System.Diagnostics.StackFrame(skipFrames, false).GetMethod();
declaringType = method.DeclaringType;
if (declaringType == null)
{
return method.Name;
}
skipFrames++;
fullName = declaringType.FullName;
}
while (declaringType.Module.Name.Equals("mscorlib.dll", System.StringComparison.OrdinalIgnoreCase));
return fullName;
}
public static byte[] ObjectToByteArray<T>(T obj)
{
if (obj == null)
{
return null;
}
var bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
using (var ms = new System.IO.MemoryStream())
{
bf.Serialize(ms, obj);
return ms.ToArray();
}
}
public static T ByteArrayToObject<T>(byte[] arrBytes)
{
using (var ms = new System.IO.MemoryStream())
{
var binForm = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
ms.Write(arrBytes, 0, arrBytes.Length);
ms.Seek(0, System.IO.SeekOrigin.Begin);
var obj = (T)binForm.Deserialize(ms);
return obj;
}
}
}
public static class Auto
{
public static IEnumerable<T> Collect<T>(Transform target) where T : MonoBehaviour
{
return target.GetComponentsInChildren<T>()
.Where(c => c.transform.parent == target);
}
public static IEnumerable<GameObject> CollectGameObjects<T>(Transform target) where T : MonoBehaviour
{
return Collect<T>(target)
.Select(c => c.gameObject);
}
public static List<GameObject> Generate<T>(Transform target, T template, int count, string naming) where T : MonoBehaviour
{
if (target == null || template == null || count < 0)
{
return new List<GameObject>();
}
var comps = Collect<T>(target).Select(c => c.gameObject).ToList();
var stack = new Stack<GameObject>();
comps.ForEach(c => stack.Push(c));
while (stack.Count < count)
{
var go = Object.Instantiate(template.gameObject, target);
go.name = $"{naming} - {stack.Count:D4}";
stack.Push(go);
}
while (stack.Count > count)
{
var go = stack.Pop();
#if UNITY_EDITOR
Object.DestroyImmediate(go);
#else
Object.Destroy( go );
#endif
}
return stack.ToList();
}
public static void Align(List<GameObject> objs, Vector3 spacing, Vector3 offset)
{
for (var i = 0; i < objs.Count; ++i)
{
var o = objs[i];
o.transform.localPosition = offset + spacing * i;
}
}
public static void Destroy<T>(Transform target) where T : MonoBehaviour
{
var objects = CollectGameObjects<T>(target);
foreach (var go in objects)
{
#if UNITY_EDITOR
Object.DestroyImmediate(go);
#else
Object.Destroy( go );
#endif
}
;
}
}
public static class Extension
{
public static Vector2 Rotate(this Vector2 v, float delta)
{
return new Vector2(
v.x * Mathf.Cos(delta) - v.y * Mathf.Sin(delta),
v.x * Mathf.Sin(delta) + v.y * Mathf.Cos(delta)
);
}
public static long ToUnixTimeMilliseconds(this System.DateTime dateTime)
{
return ((System.DateTimeOffset)dateTime).ToUnixTimeMilliseconds();
}
}
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d9f32c2ff30784f4cb45e75db1752c2f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,95 @@
using UnityEngine;
using UnityEngine.Events;
namespace UltraCombos
{
public class DisplayConfig : MonoBehaviour
{
[Header("Display")]
[SerializeField] private FullScreenMode mode = FullScreenMode.Windowed;
[SerializeField] private int displayCount = 1;
[SerializeField] private Vector2Int resolution = new Vector2Int(1600, 900);
[SerializeField] private int targetFps = 60;
[Header("Misc")]
[Range(0, 10)]
[SerializeField] private float autoHideCursor = 0;
private float cursorStamp;
private Vector2 cursorLastPosition;
[SerializeField] private bool exitOnEsc = true;
private float timestamp = 0;
[field: SerializeField, ReadOnly] public float CurrentFps { get; private set; } = 30.0f;
[Header("Event")]
public UnityEvent onQuit = new UnityEvent();
private void Awake()
{
Application.targetFrameRate = targetFps;
#if UNITY_STANDALONE || UNITY_EDITOR
if (mode == FullScreenMode.ExclusiveFullScreen)
{
var displays = Display.displays;
var num = Mathf.Min(Mathf.Max(displayCount, 1), displays.Length);
for (var i = 0; i < num; ++i)
{
displays[i].Activate();
}
Screen.SetResolution(Screen.width, Screen.height, mode);
}
else if (mode == FullScreenMode.FullScreenWindow)
{
Screen.SetResolution(Screen.width, Screen.height, mode);
}
else
{
Screen.SetResolution(resolution.x, resolution.y, mode);
}
#else
Screen.sleepTimeout = SleepTimeout.NeverSleep;
#endif
}
private void Update()
{
if (autoHideCursor > 0)
{
#if ENABLE_INPUT_SYSTEM
var pos = UnityEngine.InputSystem.Mouse.current.position.ReadValue();
#else
var pos = (Vector2)Input.mousePosition;
#endif
var bias = pos - cursorLastPosition;
if (bias.magnitude > 1)
{
cursorLastPosition = pos;
cursorStamp = Time.time;
}
Cursor.visible = Time.time - cursorStamp < autoHideCursor;
}
if (Time.time - timestamp > 0)
{
CurrentFps = Mathf.Lerp(CurrentFps, 1.0f / (Time.time - timestamp), Time.deltaTime);
timestamp = Time.time;
}
if (exitOnEsc)
{
#if ENABLE_INPUT_SYSTEM
if (UnityEngine.InputSystem.Keyboard.current.escapeKey.wasPressedThisFrame)
#else
if (Input.GetKeyDown(KeyCode.Escape))
#endif
{
onQuit.Invoke();
Application.Quit();
}
}
}
}
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 63c5372172ea740439535067b0f1a5fc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,79 @@
using System;
using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;
namespace UltraCombos
{
public static class DotNetEnv
{
private static readonly Regex lineRegex = new Regex(
@"(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*""(?:\\""|[^""])*""|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)",
RegexOptions.Multiline | RegexOptions.Compiled);
public static void Load(string path = ".env")
{
if (!File.Exists(path))
{
return;
}
var src = File.ReadAllText(path);
src = src.Replace("\r\n", "\n").Replace("\r", "\n");
var keys = new System.Collections.Generic.List<string>();
var matches = lineRegex.Matches(src);
foreach (Match match in matches)
{
var key = match.Groups[1].Value;
var value = match.Groups[2].Value.Trim();
if (string.IsNullOrEmpty(key))
{
continue;
}
var maybeQuote = value.Length > 0 ? value[0] : (char?)null;
value = Regex.Replace(value, @"^(['""`])([\s\S]*)\1$", "$2");
if (maybeQuote == '"')
{
value = value.Replace("\\n", "\n").Replace("\\r", "\r");
}
Environment.SetEnvironmentVariable(key, value);
keys.Add(key);
}
Log.Info("DotNetEnv", $"Loaded environment variable:\n{string.Join("\n", keys)}");
}
public static bool TryGet(string key, out string value)
{
value = Environment.GetEnvironmentVariable(key);
return !string.IsNullOrEmpty(value);
}
public static bool TryGetAs<T>(string key, out T value) where T : struct
{
var raw = Environment.GetEnvironmentVariable(key);
if (string.IsNullOrEmpty(raw))
{
value = default;
return false;
}
try
{
value = (T)Convert.ChangeType(raw, typeof(T), CultureInfo.InvariantCulture);
return true;
}
catch
{
value = default;
return false;
}
}
}
}

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: dedd030f6276eb64994275a87ed2af1d

@ -0,0 +1,21 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace UltraCombos
{
[ExecuteAlways]
public class ForceUpdater : MonoBehaviour
{
#if UNITY_EDITOR
private static void QueueUpdate() => EditorApplication.QueuePlayerLoopUpdate();
private void OnEnable() => EditorApplication.update += QueueUpdate;
private void OnDisable() => EditorApplication.update -= QueueUpdate;
#endif
}
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: deeebc01fb69bc44a89ee2bc02a6ae88
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,16 @@
using UnityEngine;
namespace UltraCombos
{
public static class Log
{
public static void Info(string tag, string message)
=> Debug.Log($"<b>[{tag}]</b> {message}");
public static void Warning(string tag, string message)
=> Debug.LogWarning($"<b>[{tag}]</b> {message}");
public static void Error(string tag, string message)
=> Debug.LogError($"<b>[{tag}]</b> {message}");
}
}

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b7e8119c4421cb6489c2708fe2e43b87

@ -0,0 +1,3 @@
using UnityEngine;
public class ReadOnlyAttribute : PropertyAttribute { }

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 01f0d168c9980894892226cc1453811f

@ -0,0 +1,61 @@
using UnityEngine;
namespace UltraCombos
{
public abstract class Singleton<T> : MonoBehaviour where T : Component
{
#region Fields
private static T instance;
[SerializeField]
private bool persistance = true;
#endregion
#region Properties
public static T Instance
{
get
{
if (instance == null)
{
instance = FindFirstObjectByType<T>();
if (instance == null)
{
var go = new GameObject();
go.name = typeof(T).Name;
instance = go.AddComponent<T>();
}
}
return instance;
}
}
#endregion
#region Methods
protected virtual void Awake()
{
if (instance == null)
{
instance = this as T;
if (persistance)
{
DontDestroyOnLoad(gameObject);
}
}
else
{
Destroy(gameObject);
}
}
#endregion
}
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fb66cb43872fa254e94f4f7c8e02ed8f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,16 @@
{
"name": "UltraCombos.GiantMuseum.Runtime",
"rootNamespace": "UltraCombos.GiantMuseum",
"references": [
"GUID:75469ad4d38634e559750d17036d5f7c"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b2e08e75d81bb8b408397e7998130fbb
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,13 @@
{
"name": "com.ultracombos.giant-museum",
"version": "1.0.0",
"displayName": "Giant Museum",
"description": "Unity Package for Giant Museum",
"repository": "",
"type": "library",
"author": {
"name": "ultracombos",
"url": "https://ultracombos.com",
"email": "tech@ultracombos.com"
}
}

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: f68ca7a8d533c8949af848b1a974c513
PackageManifestImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -1,49 +1,23 @@
{
"scopedRegistries": [
{
"name": "Keijiro",
"url": "https://registry.npmjs.com",
"scopes": [
"jp.keijiro"
]
}
],
"dependencies": {
"com.unity.ai.navigation": "2.0.11",
"com.unity.collab-proxy": "2.11.4",
"com.unity.ide.rider": "3.0.39",
"com.github-glitchenzo.nugetforunity": "https://github.com/GlitchEnzo/NuGetForUnity.git?path=/src/NuGetForUnity",
"com.unity.ide.visualstudio": "2.0.26",
"com.unity.inputsystem": "1.19.0",
"com.unity.multiplayer.center": "1.0.1",
"com.unity.render-pipelines.universal": "17.3.0",
"com.unity.test-framework": "1.6.0",
"com.unity.timeline": "1.8.11",
"com.unity.ugui": "2.0.0",
"com.unity.visualscripting": "1.9.11",
"com.unity.modules.accessibility": "1.0.0",
"com.unity.modules.adaptiveperformance": "1.0.0",
"com.unity.modules.ai": "1.0.0",
"com.unity.modules.androidjni": "1.0.0",
"com.unity.modules.animation": "1.0.0",
"com.unity.modules.assetbundle": "1.0.0",
"com.unity.modules.audio": "1.0.0",
"com.unity.modules.cloth": "1.0.0",
"com.unity.modules.director": "1.0.0",
"com.unity.modules.imageconversion": "1.0.0",
"com.unity.modules.imgui": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0",
"com.unity.modules.particlesystem": "1.0.0",
"com.unity.modules.physics": "1.0.0",
"com.unity.modules.physics2d": "1.0.0",
"com.unity.modules.screencapture": "1.0.0",
"com.unity.modules.terrain": "1.0.0",
"com.unity.modules.terrainphysics": "1.0.0",
"com.unity.modules.tilemap": "1.0.0",
"com.unity.modules.ui": "1.0.0",
"com.unity.modules.uielements": "1.0.0",
"com.unity.modules.umbra": "1.0.0",
"com.unity.modules.unityanalytics": "1.0.0",
"com.unity.modules.unitywebrequest": "1.0.0",
"com.unity.modules.unitywebrequestassetbundle": "1.0.0",
"com.unity.modules.unitywebrequestaudio": "1.0.0",
"com.unity.modules.unitywebrequesttexture": "1.0.0",
"com.unity.modules.unitywebrequestwww": "1.0.0",
"com.unity.modules.vectorgraphics": "1.0.0",
"com.unity.modules.vehicles": "1.0.0",
"com.unity.modules.video": "1.0.0",
"com.unity.modules.vr": "1.0.0",
"com.unity.modules.wind": "1.0.0",
"com.unity.modules.xr": "1.0.0"
"jp.keijiro.klak.spout": "https://github.com/UltraCombos/KlakSpout.git?path=Packages/jp.keijiro.klak.spout#main",
"jp.keijiro.metamesh": "1.2.0",
"jp.keijiro.metatex": "1.0.4",
"jp.keijiro.osc-jack": "2.0.0"
}
}

@ -1,13 +1,17 @@
{
"dependencies": {
"com.unity.ai.navigation": {
"version": "2.0.11",
"com.github-glitchenzo.nugetforunity": {
"version": "https://github.com/GlitchEnzo/NuGetForUnity.git?path=/src/NuGetForUnity",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.modules.ai": "1.0.0"
},
"url": "https://packages.unity.com"
"source": "git",
"dependencies": {},
"hash": "acc1c7bc9ea34c33b830e40316fca52553878d29"
},
"com.ultracombos.giant-museum": {
"version": "file:com.ultracombos.giant-museum",
"depth": 0,
"source": "embedded",
"dependencies": {}
},
"com.unity.burst": {
"version": "1.8.28",
@ -19,13 +23,6 @@
},
"url": "https://packages.unity.com"
},
"com.unity.collab-proxy": {
"version": "2.11.4",
"depth": 0,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.collections": {
"version": "2.6.5",
"depth": 2,
@ -41,19 +38,10 @@
},
"com.unity.ext.nunit": {
"version": "2.0.5",
"depth": 1,
"depth": 2,
"source": "builtin",
"dependencies": {}
},
"com.unity.ide.rider": {
"version": "3.0.39",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.ext.nunit": "1.0.6"
},
"url": "https://packages.unity.com"
},
"com.unity.ide.visualstudio": {
"version": "2.0.26",
"depth": 0,
@ -74,19 +62,11 @@
},
"com.unity.mathematics": {
"version": "1.3.3",
"depth": 2,
"depth": 1,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.multiplayer.center": {
"version": "1.0.1",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.uielements": "1.0.0"
}
},
"com.unity.nuget.mono-cecil": {
"version": "1.11.6",
"depth": 3,
@ -144,7 +124,7 @@
},
"com.unity.test-framework": {
"version": "1.6.0",
"depth": 0,
"depth": 1,
"source": "builtin",
"dependencies": {
"com.unity.ext.nunit": "2.0.3",
@ -183,71 +163,62 @@
"com.unity.modules.imgui": "1.0.0"
}
},
"com.unity.visualscripting": {
"version": "1.9.11",
"depth": 0,
"jp.keijiro.klak.lineargradient": {
"version": "1.0.2",
"depth": 1,
"source": "registry",
"dependencies": {
"com.unity.ugui": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0"
},
"url": "https://packages.unity.com"
"dependencies": {},
"url": "https://registry.npmjs.com"
},
"com.unity.modules.accessibility": {
"version": "1.0.0",
"jp.keijiro.klak.spout": {
"version": "https://github.com/UltraCombos/KlakSpout.git?path=Packages/jp.keijiro.klak.spout#main",
"depth": 0,
"source": "builtin",
"dependencies": {}
"source": "git",
"dependencies": {
"com.unity.modules.screencapture": "1.0.0"
},
"hash": "639cbdb8a9fc62ced4f4dd9f9a524d2bb352eaca"
},
"com.unity.modules.adaptiveperformance": {
"version": "1.0.0",
"jp.keijiro.metamesh": {
"version": "1.2.0",
"depth": 0,
"source": "builtin",
"source": "registry",
"dependencies": {
"com.unity.modules.subsystems": "1.0.0"
}
"com.unity.mathematics": "1.2.1"
},
"url": "https://registry.npmjs.com"
},
"com.unity.modules.ai": {
"version": "1.0.0",
"jp.keijiro.metatex": {
"version": "1.0.4",
"depth": 0,
"source": "builtin",
"dependencies": {}
"source": "registry",
"dependencies": {
"jp.keijiro.klak.lineargradient": "1.0.2"
},
"url": "https://registry.npmjs.com"
},
"com.unity.modules.androidjni": {
"version": "1.0.0",
"jp.keijiro.osc-jack": {
"version": "2.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
"source": "registry",
"dependencies": {},
"url": "https://registry.npmjs.com"
},
"com.unity.modules.animation": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.assetbundle": {
"version": "1.0.0",
"depth": 0,
"depth": 1,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.audio": {
"version": "1.0.0",
"depth": 0,
"depth": 1,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.cloth": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.physics": "1.0.0"
}
},
"com.unity.modules.director": {
"version": "1.0.0",
"depth": 0,
"depth": 1,
"source": "builtin",
"dependencies": {
"com.unity.modules.audio": "1.0.0",
@ -256,94 +227,63 @@
},
"com.unity.modules.hierarchycore": {
"version": "1.0.0",
"depth": 1,
"depth": 2,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.imageconversion": {
"version": "1.0.0",
"depth": 0,
"depth": 2,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.imgui": {
"version": "1.0.0",
"depth": 0,
"depth": 1,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.jsonserialize": {
"version": "1.0.0",
"depth": 0,
"depth": 2,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.particlesystem": {
"version": "1.0.0",
"depth": 0,
"depth": 1,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.physics": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.physics2d": {
"version": "1.0.0",
"depth": 0,
"depth": 2,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.screencapture": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.imageconversion": "1.0.0"
}
},
"com.unity.modules.subsystems": {
"version": "1.0.0",
"depth": 1,
"source": "builtin",
"dependencies": {
"com.unity.modules.jsonserialize": "1.0.0"
"com.unity.modules.imageconversion": "1.0.0"
}
},
"com.unity.modules.terrain": {
"version": "1.0.0",
"depth": 0,
"depth": 2,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.terrainphysics": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.physics": "1.0.0",
"com.unity.modules.terrain": "1.0.0"
}
},
"com.unity.modules.tilemap": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.physics2d": "1.0.0"
}
},
"com.unity.modules.ui": {
"version": "1.0.0",
"depth": 0,
"depth": 1,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.uielements": {
"version": "1.0.0",
"depth": 0,
"depth": 1,
"source": "builtin",
"dependencies": {
"com.unity.modules.ui": "1.0.0",
@ -352,121 +292,6 @@
"com.unity.modules.hierarchycore": "1.0.0",
"com.unity.modules.physics": "1.0.0"
}
},
"com.unity.modules.umbra": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.unityanalytics": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.unitywebrequest": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0"
}
},
"com.unity.modules.unitywebrequest": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.unitywebrequestassetbundle": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.assetbundle": "1.0.0",
"com.unity.modules.unitywebrequest": "1.0.0"
}
},
"com.unity.modules.unitywebrequestaudio": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.unitywebrequest": "1.0.0",
"com.unity.modules.audio": "1.0.0"
}
},
"com.unity.modules.unitywebrequesttexture": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.unitywebrequest": "1.0.0",
"com.unity.modules.imageconversion": "1.0.0"
}
},
"com.unity.modules.unitywebrequestwww": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.unitywebrequest": "1.0.0",
"com.unity.modules.unitywebrequestassetbundle": "1.0.0",
"com.unity.modules.unitywebrequestaudio": "1.0.0",
"com.unity.modules.audio": "1.0.0",
"com.unity.modules.assetbundle": "1.0.0",
"com.unity.modules.imageconversion": "1.0.0"
}
},
"com.unity.modules.vectorgraphics": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.uielements": "1.0.0",
"com.unity.modules.imageconversion": "1.0.0",
"com.unity.modules.imgui": "1.0.0"
}
},
"com.unity.modules.vehicles": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.physics": "1.0.0"
}
},
"com.unity.modules.video": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.audio": "1.0.0",
"com.unity.modules.ui": "1.0.0",
"com.unity.modules.unitywebrequest": "1.0.0"
}
},
"com.unity.modules.vr": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.jsonserialize": "1.0.0",
"com.unity.modules.physics": "1.0.0",
"com.unity.modules.xr": "1.0.0"
}
},
"com.unity.modules.wind": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.xr": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.physics": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0",
"com.unity.modules.subsystems": "1.0.0"
}
}
}
}

@ -12,11 +12,13 @@ MonoBehaviour:
m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier:
m_EnablePreviewPackages: 0
m_EnablePackageDependencies: 0
m_EnablePreReleasePackages: 0
m_AdvancedSettingsExpanded: 1
m_ScopedRegistriesSettingsExpanded: 1
m_SeeAllPackageVersions: 0
m_DismissPreviewPackagesInUse: 0
oneTimeWarningShown: 0
oneTimePackageErrorsPopUpShown: 0
m_Registries:
- m_Id: main
m_Name:
@ -24,20 +26,26 @@ MonoBehaviour:
m_Scopes: []
m_IsDefault: 1
m_Capabilities: 7
m_UserSelectedRegistryName:
m_ConfigSource: 0
m_Compliance:
m_Status: 0
m_Violations: []
- m_Id: scoped:project:Keijiro
m_Name: Keijiro
m_Url: https://registry.npmjs.com
m_Scopes:
- jp.keijiro
m_IsDefault: 0
m_Capabilities: 0
m_ConfigSource: 4
m_Compliance:
m_Status: 0
m_Violations: []
m_UserSelectedRegistryName: Keijiro
m_UserAddingNewScopedRegistry: 0
m_RegistryInfoDraft:
m_ErrorMessage:
m_Original:
m_Id:
m_Name:
m_Url:
m_Scopes: []
m_IsDefault: 0
m_Capabilities: 0
m_Modified: 0
m_Name:
m_Url:
m_Scopes:
-
m_SelectedScopeIndex: 0
m_ErrorMessage:
m_UserModificationsInstanceId: -896
m_OriginalInstanceId: -898
m_LoadAssets: 0

@ -1,42 +1,35 @@
<Solution>
<Project Path="Unity.Timeline.csproj" />
<Project Path="Unity.PlasticSCM.Editor.csproj" />
<Project Path="Unity.Mathematics.csproj" />
<Project Path="Unity.Timeline.Editor.csproj" />
<Project Path="Unity.Collections.csproj" />
<Project Path="Unity.VisualScripting.Core.Editor.csproj" />
<Project Path="Metamesh.Editor.csproj" />
<Project Path="Unity.PerformanceTesting.Editor.csproj" />
<Project Path="Unity.Burst.csproj" />
<Project Path="Unity.VisualScripting.Flow.Editor.csproj" />
<Project Path="Unity.VisualStudio.Editor.csproj" />
<Project Path="Unity.InputSystem.csproj" />
<Project Path="Unity.Searcher.Editor.csproj" />
<Project Path="Unity.VisualScripting.Core.csproj" />
<Project Path="Unity.AI.Navigation.Editor.ConversionSystem.csproj" />
<Project Path="Unity.VisualScripting.State.Editor.csproj" />
<Project Path="Unity.Burst.CodeGen.csproj" />
<Project Path="Unity.VisualScripting.Flow.csproj" />
<Project Path="Unity.PerformanceTesting.csproj" />
<Project Path="Unity.Burst.Editor.csproj" />
<Project Path="Unity.Rider.Editor.csproj" />
<Project Path="Unity.VisualScripting.State.csproj" />
<Project Path="Unity.AI.Navigation.Updater.csproj" />
<Project Path="Unity.AI.Navigation.Editor.csproj" />
<Project Path="OscJack.Runtime.csproj" />
<Project Path="NuGetForUnity.csproj" />
<Project Path="Unity.InputSystem.ForUI.csproj" />
<Project Path="Unity.AI.Navigation.csproj" />
<Project Path="Unity.Collections.CodeGen.csproj" />
<Project Path="Unity.Mathematics.Editor.csproj" />
<Project Path="Unity.VisualScripting.SettingsProvider.Editor.csproj" />
<Project Path="Klak.Spout.Runtime.csproj" />
<Project Path="HBAO.Universal.Runtime.csproj" />
<Project Path="Unity.InputSystem.TestFramework.csproj" />
<Project Path="Unity.VisualScripting.Shared.Editor.csproj" />
<Project Path="Unity.CollabProxy.Editor.csproj" />
<Project Path="Assembly-CSharp.csproj" />
<Project Path="Metatex.Editor.csproj" />
<Project Path="Klak.Spout.Editor.csproj" />
<Project Path="Klak.Chromatics.LinearGradient.Runtime.csproj" />
<Project Path="OscJack.Editor.csproj" />
<Project Path="UltraCombos.GiantMuseum.Runtime.csproj" />
<Project Path="Unity.InputSystem.DocCodeSamples.csproj" />
<Project Path="UltraCombos.GiantMuseum.Editor.csproj" />
<Project Path="HBAO.Runtime.csproj" />
<Project Path="Unity.VisualScripting.DocCodeExamples.csproj" />
<Project Path="Unity.PlasticSCM.Editor.Entities.csproj" />
<Project Path="HBAO.Editor.csproj" />
<Project Path="HBAO.Universal.Editor.csproj" />
<Project Path="Unity.Collections.Editor.csproj" />
<Project Path="Assembly-CSharp.csproj" />
</Solution>

Loading…
Cancel
Save