savya #8

Merged
savya merged 3 commits from savya into main 2026-05-28 13:07:39 +02:00
73 changed files with 12872 additions and 140 deletions
Showing only changes of commit 09ad3469f2 - Show all commits

View File

@@ -20,6 +20,11 @@ MonoBehaviour:
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 145ae55f6571bfe4fbadaefb863ba69d
m_Address: Colorbook
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: e5f73f24e812e4a98b4c17d533fd3d6d
m_Address: Gameplay
m_ReadOnly: 0

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4c2af4ea812e45de8f189ce182b2a22e
timeCreated: 1779963993

View File

@@ -0,0 +1,3 @@
namespace Darkmatter.Core.Data.Signals.Features.MainMenu;
public record struct PlayBtnClickedSignal();

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3dfe3ef5d7da4861becbc8791ce7c852
timeCreated: 1779964014

View File

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

View File

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

View File

@@ -0,0 +1,16 @@
using Darkmatter.Libs.Installers;
using UnityEngine;
using VContainer;
using VContainer.Unity;
namespace Darkmatter.Features.Loading
{
public class LoadingFeatureModule : MonoBehaviour,IModule
{
[SerializeField] private LoadingScreenView loadingScreenView;
public void Register(IContainerBuilder builder)
{
builder.RegisterEntryPoint<LoadingPresenter>().WithParameter(loadingScreenView);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 673a21bf7c6bb430eadece2a989d79ac

View File

@@ -1,85 +0,0 @@
using PrimeTween;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace Darkmatter.Features.Loading
{
public class LoadingScreenView : MonoBehaviour
{
[SerializeField] private Slider loadingSlider;
[SerializeField] private TMP_Text statusText;
[SerializeField] private float loadingSmoothTime = 10f;
[SerializeField] private float messageHoldDuration = 2f;
[SerializeField] private float messageFadeDuration = 0.4f;
public float LoadingSmoothTime => loadingSmoothTime;
private static readonly string[] StatusLines = {
"Blue is arguing with red...",
"The crayons are dancing...",
"Yellow spilled everywhere...",
"Chasing escaped paint drops...",
"Untying rainbow knots...",
"Cleaning glitter explosions...",
"The color monsters are hungry...",
"Mixing mystery colors...",
"Someone ate the purple paint...",
"Teaching green to behave..."
};
private Sequence _statusSequence;
private int _statusIndex;
public void Show()
{
gameObject.SetActive(true);
StartStatusCycle();
}
public void Hide()
{
StopStatusCycle();
gameObject.SetActive(false);
}
public void SetProgress(float progress)
{
if (loadingSlider != null) loadingSlider.value = progress;
}
private void StartStatusCycle()
{
if (statusText == null || StatusLines.Length == 0) return;
StopStatusCycle();
_statusIndex = Random.Range(0, StatusLines.Length);
statusText.text = StatusLines[_statusIndex];
statusText.alpha = 0f;
_statusSequence = Sequence.Create(useUnscaledTime: true, cycles: -1)
.Chain(Tween.Alpha(statusText, 1f, messageFadeDuration, Ease.OutQuad))
.ChainDelay(messageHoldDuration)
.Chain(Tween.Alpha(statusText, 0f, messageFadeDuration, Ease.InQuad))
.ChainCallback(AdvanceStatusLine);
}
private void StopStatusCycle()
{
if (_statusSequence.isAlive) _statusSequence.Stop();
_statusSequence = default;
}
private void AdvanceStatusLine()
{
if (statusText == null) return;
_statusIndex = (_statusIndex + 1) % StatusLines.Length;
statusText.text = StatusLines[_statusIndex];
}
private void OnDisable()
{
StopStatusCycle();
}
}
}

View File

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

View File

@@ -0,0 +1,85 @@
using PrimeTween;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace Darkmatter.Features.Loading
{
public class LoadingScreenView : MonoBehaviour
{
[SerializeField] private Slider loadingSlider;
[SerializeField] private TMP_Text statusText;
[SerializeField] private float loadingSmoothTime = 10f;
[SerializeField] private float dotInterval = 0.4f;
public float LoadingSmoothTime => loadingSmoothTime;
private static readonly string[] StatusLines = {
"Blue is arguing with red",
"The crayons are dancing",
"Yellow spilled everywhere",
"Chasing escaped paint drops",
"Untying rainbow knots",
"Cleaning glitter explosions",
"The color monsters are hungry",
"Mixing mystery colors",
"Someone ate the purple paint",
"Teaching green to behave"
};
private static readonly string[] DotFrames = { ".", "..", "..." };
private string _baseLine;
private int _dotIndex;
private Sequence _dotSequence;
public void Show()
{
gameObject.SetActive(true);
if (statusText == null || StatusLines.Length == 0) return;
_baseLine = StatusLines[Random.Range(0, StatusLines.Length)];
_dotIndex = 0;
statusText.text = _baseLine + DotFrames[_dotIndex];
StartDotAnimation();
}
public void Hide()
{
StopDotAnimation();
gameObject.SetActive(false);
}
public void SetProgress(float progress)
{
if (loadingSlider != null) loadingSlider.value = progress;
}
private void StartDotAnimation()
{
StopDotAnimation();
_dotSequence = Sequence.Create(useUnscaledTime: true, cycles: -1)
.ChainDelay(dotInterval)
.ChainCallback(AdvanceDots);
}
private void StopDotAnimation()
{
if (_dotSequence.isAlive) _dotSequence.Stop();
_dotSequence = default;
}
private void AdvanceDots()
{
if (statusText == null || string.IsNullOrEmpty(_baseLine)) return;
_dotIndex = (_dotIndex + 1) % DotFrames.Length;
statusText.text = _baseLine + DotFrames[_dotIndex];
}
private void OnDisable()
{
StopDotAnimation();
}
}
}

View File

@@ -1,5 +1,6 @@
using System;
using Darkmatter.Core.Data.Signals.Features.AppBoot;
using Darkmatter.Core.Data.Signals.Features.MainMenu;
using Darkmatter.Libs.Observer;
using UnityEngine;
using VContainer.Unity;
@@ -32,7 +33,7 @@ namespace Darkmatter.Features.Mainmenu
private void OnPlayBtnClicked()
{
Debug.Log("Play Btn Clicked");
_eventBus.Publish(new PlayBtnClickedSignal());
}
public void Dispose()

View File

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

View File

@@ -0,0 +1,21 @@
{
"name": "Features.MainMenuFlow",
"rootNamespace": "Darkmatter.Features.MainMenuFlow",
"references": [
"GUID:6a0a834eb41764f12ba55c3fb04a40cb",
"GUID:b4c9f7fbf1e144933a1797dc208ece5f",
"GUID:c1c03c0e5b2f4412b9f2be1c20d6a9b1",
"GUID:729fabb77852b4d3eae2417d9564dc37",
"GUID:b0214a6008ed146ff8f122a6a9c2f6cc",
"GUID:f51ebe6a0ceec4240a699833d6309b23"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

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

View File

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

View File

@@ -0,0 +1,51 @@
using System;
using System.Threading;
using Cysharp.Threading.Tasks;
using Darkmatter.Core.Contracts.Features.Loading;
using Darkmatter.Core.Contracts.Services.Scenes;
using Darkmatter.Core.Data.Signals.Features.MainMenu;
using Darkmatter.Core.Enums.Services.Scenes;
using Darkmatter.Libs.Observer;
using VContainer.Unity;
namespace Darkmatter.Features.MainMenuFlow.Flow
{
public class MainMenuFlow : IAsyncStartable, IDisposable
{
private readonly ILoadingScreen _loadingScreen;
private readonly ISceneService _sceneService;
private readonly IEventBus _eventBus;
private IDisposable _playBtnClickedSubscription;
public MainMenuFlow(ILoadingScreen loadingScreen, ISceneService sceneService,IEventBus eventBus)
{
_loadingScreen = loadingScreen;
_sceneService = sceneService;
_eventBus = eventBus;
}
public UniTask StartAsync(CancellationToken cancellation = new CancellationToken())
{
_playBtnClickedSubscription = _eventBus.Subscribe<PlayBtnClickedSignal>(OnPlayBtnClicked);
return UniTask.CompletedTask;
}
private void OnPlayBtnClicked(PlayBtnClickedSignal obj)
{
LoadColorbookSceneAsync().Forget();
}
private async UniTask LoadColorbookSceneAsync(CancellationToken ct = default)
{
_loadingScreen.Show();
var progress = new Progress<float>(p => _loadingScreen.SetProgress(p * 0.5f));
await _sceneService.LoadSceneAsync(nameof(GameScene.Colorbook), progress, ct);
}
public void Dispose()
{
_playBtnClickedSubscription?.Dispose();
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,15 @@
using Darkmatter.Libs.Installers;
using UnityEngine;
using VContainer;
using VContainer.Unity;
namespace Darkmatter.Features.MainMenuFlow
{
public class MainMenuFlowFeatureModule : MonoBehaviour, IModule
{
public void Register(IContainerBuilder builder)
{
builder.RegisterEntryPoint<Flow.MainMenuFlow>();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 537a5a77a85a141519e96811f4f4e0a3

View File

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

Binary file not shown.

View File

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

View File

@@ -0,0 +1,19 @@
# UnityUtils Lib
## Purpose
`Darkmatter.Libs.UnityUtils` contains small Unity-facing helpers and editor/runtime utility code that is generic enough to be reused across slices.
## Public Entry Points
- Shared attributes and helper components under `Assets/Darkmatter/Code/Libs/UnityUtils`
## Dependencies
- Referenced by App and multiple features for inspector safety and lightweight helper behavior
- Should not accumulate gameplay rules or scene-specific orchestration
## Extension Notes
- Keep utilities narrowly scoped and reusable.
- If a helper starts depending on one features data model or service policy, move it back into that slice.

View File

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

View File

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

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a63598ae46644c6db94d7a9119c9982a
timeCreated: 1770193562

View File

@@ -0,0 +1,186 @@
using UnityEditor;
using UnityEngine;
namespace Darkmatter.Libs.UnityUtils.Editor
{
[CustomPropertyDrawer(typeof(RequireInterfaceAttribute))]
public class RequireInterfaceDrawer : PropertyDrawer
{
private const float HelpBoxHeight = 40f;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// Validate property type
if (property.propertyType != SerializedPropertyType.ObjectReference)
{
EditorGUI.HelpBox(position,
"RequireInterface attribute can only be used with Object reference fields.",
MessageType.Error);
return;
}
var requiredAttribute = attribute as RequireInterfaceAttribute;
if (requiredAttribute?.InterfaceType == null)
{
EditorGUI.PropertyField(position, property, label);
return;
}
// Validate that the required type is actually an interface
if (!requiredAttribute.InterfaceType.IsInterface)
{
EditorGUI.HelpBox(position,
$"{requiredAttribute.InterfaceType.Name} is not an interface type.",
MessageType.Error);
return;
}
// Draw the object field
DrawInterfaceObjectField(position, property, label, requiredAttribute);
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
// Show error message height if property type is invalid
if (property.propertyType != SerializedPropertyType.ObjectReference)
{
return HelpBoxHeight;
}
var requiredAttribute = attribute as RequireInterfaceAttribute;
if (requiredAttribute?.InterfaceType != null && !requiredAttribute.InterfaceType.IsInterface)
{
return HelpBoxHeight;
}
return EditorGUIUtility.singleLineHeight;
}
private void DrawInterfaceObjectField(
Rect position,
SerializedProperty property,
GUIContent label,
RequireInterfaceAttribute requiredAttribute)
{
// Enhance label with interface type info
var enhancedLabel = new GUIContent(
label.text,
$"Requires: {requiredAttribute.InterfaceType.Name}\n{label.tooltip}"
);
EditorGUI.BeginProperty(position, enhancedLabel, property);
EditorGUI.BeginChangeCheck();
// Draw the object field
var newObj = EditorGUI.ObjectField(
position,
enhancedLabel,
property.objectReferenceValue,
typeof(Object),
true
);
if (EditorGUI.EndChangeCheck())
{
HandleObjectAssignment(property, newObj, requiredAttribute);
}
EditorGUI.EndProperty();
}
private void HandleObjectAssignment(
SerializedProperty property,
Object newObj,
RequireInterfaceAttribute requiredAttribute)
{
// Clear assignment if null
if (newObj == null)
{
property.objectReferenceValue = null;
return;
}
Object validComponent = null;
// Handle GameObject drag
if (newObj is GameObject gameObject)
{
validComponent = FindInterfaceComponent(gameObject, requiredAttribute.InterfaceType);
if (validComponent == null)
{
ShowInterfaceNotFoundWarning(gameObject.name, requiredAttribute.InterfaceType, true);
}
}
// Handle Component drag
else if (newObj is Component component)
{
if (IsValidInterface(component, requiredAttribute.InterfaceType))
{
validComponent = component;
}
else
{
// Try to find interface on the same GameObject
validComponent = FindInterfaceComponent(component.gameObject, requiredAttribute.InterfaceType);
if (validComponent == null)
{
ShowInterfaceNotFoundWarning(component.name, requiredAttribute.InterfaceType, false);
}
}
}
// Handle ScriptableObject or other Object types
else
{
if (IsValidInterface(newObj, requiredAttribute.InterfaceType))
{
validComponent = newObj;
}
else
{
ShowInterfaceNotFoundWarning(newObj.name, requiredAttribute.InterfaceType, false);
}
}
// Only assign if valid
if (validComponent != null)
{
property.objectReferenceValue = validComponent;
}
}
private Object FindInterfaceComponent(GameObject gameObject, System.Type interfaceType)
{
if (gameObject == null) return null;
// Get all components and find the first one that implements the interface
var components = gameObject.GetComponents<Component>();
foreach (var component in components)
{
if (component != null && IsValidInterface(component, interfaceType))
{
return component;
}
}
return null;
}
private bool IsValidInterface(Object obj, System.Type interfaceType)
{
if (obj == null || interfaceType == null) return false;
return interfaceType.IsAssignableFrom(obj.GetType());
}
private void ShowInterfaceNotFoundWarning(string objectName, System.Type interfaceType, bool isGameObject)
{
var objectType = isGameObject ? "GameObject" : "Object";
Debug.LogWarning(
$"[RequireInterface] {objectType} '{objectName}' does not implement interface '{interfaceType.Name}'. " +
$"Assignment rejected.",
Selection.activeObject
);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 85734cfb697d4fbd9b57d0fe3d28660a
timeCreated: 1770193571

View File

@@ -0,0 +1,18 @@
{
"name": "Libs.UnityUtils.Editor",
"rootNamespace": "Darkmatter.Libs.UnityUtils.Editor",
"references": [
"GUID:729fabb77852b4d3eae2417d9564dc37"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

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

View File

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

View File

@@ -0,0 +1,103 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace Darkmatter.Libs.UnityUtils.Editor
{
[InitializeOnLoad]
internal static class ConcaveMeshColliderVisualizer
{
private const string MenuPath = "Tools/Visualize Concave Mesh Colliders";
private const string PrefKey = "Darkmatter.ConcaveMeshColliderVisualizer.Enabled";
private static readonly Color BoundsColor = new Color(1f, 0.35f, 0.15f, 0.85f);
private static readonly Color WireColor = new Color(1f, 0.85f, 0.2f, 1f);
private static readonly List<MeshCollider> Buffer = new List<MeshCollider>(512);
static ConcaveMeshColliderVisualizer()
{
EditorApplication.delayCall += () => ApplyEnabledState(EditorPrefs.GetBool(PrefKey, false));
}
[MenuItem(MenuPath)]
private static void Toggle()
{
bool next = !EditorPrefs.GetBool(PrefKey, false);
EditorPrefs.SetBool(PrefKey, next);
ApplyEnabledState(next);
SceneView.RepaintAll();
}
[MenuItem(MenuPath, validate = true)]
private static bool ToggleValidate()
{
Menu.SetChecked(MenuPath, EditorPrefs.GetBool(PrefKey, false));
return true;
}
private static void ApplyEnabledState(bool enabled)
{
SceneView.duringSceneGui -= OnSceneGUI;
if (enabled) SceneView.duringSceneGui += OnSceneGUI;
Menu.SetChecked(MenuPath, enabled);
}
private static void OnSceneGUI(SceneView view)
{
HashSet<MeshCollider> selected = CollectSelectedConcave();
Buffer.Clear();
Buffer.AddRange(Object.FindObjectsByType<MeshCollider>(FindObjectsInactive.Include, FindObjectsSortMode.None));
for (int i = 0; i < Buffer.Count; i++)
{
MeshCollider mc = Buffer[i];
if (mc == null || mc.convex || mc.sharedMesh == null) continue;
DrawBounds(mc);
if (selected.Contains(mc)) DrawWire(mc);
}
}
private static HashSet<MeshCollider> CollectSelectedConcave()
{
var set = new HashSet<MeshCollider>();
foreach (GameObject go in Selection.gameObjects)
{
foreach (MeshCollider mc in go.GetComponentsInChildren<MeshCollider>(true))
{
if (!mc.convex && mc.sharedMesh != null) set.Add(mc);
}
}
return set;
}
private static void DrawBounds(MeshCollider mc)
{
Bounds b = mc.bounds;
using (new Handles.DrawingScope(BoundsColor))
Handles.DrawWireCube(b.center, b.size);
}
private static void DrawWire(MeshCollider mc)
{
Mesh m = mc.sharedMesh;
Vector3[] verts = m.vertices;
int[] tris = m.triangles;
using (new Handles.DrawingScope(WireColor, mc.transform.localToWorldMatrix))
{
for (int i = 0; i < tris.Length; i += 3)
{
Vector3 a = verts[tris[i]];
Vector3 b = verts[tris[i + 1]];
Vector3 c = verts[tris[i + 2]];
Handles.DrawLine(a, b);
Handles.DrawLine(b, c);
Handles.DrawLine(c, a);
}
}
}
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,198 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Darkmatter.Libs.UnityUtils.Editor
{
public class SceneRendererOptimizer : EditorWindow
{
const string DefaultNamePattern = "puddle|pPlane|decal|tree|plant|grass|bush|leaf|leaves|foliage|flower|hedge|sticker";
const string DefaultMaterialPattern = "puddle|decal|tree|grass|leaf|leaves|foliage|plant|vegetation";
string namePattern = DefaultNamePattern;
string materialPattern = DefaultMaterialPattern;
bool useTransparentQueueAsDecal = true;
bool onlyActiveRenderers = true;
Vector2 scroll;
string lastReport = "";
[MenuItem("Tools/Darkmatter/Scene Renderer Optimizer")]
public static void ShowWindow()
{
var w = GetWindow<SceneRendererOptimizer>("Scene Renderer Optimizer");
w.minSize = new Vector2(520, 400);
}
void OnGUI()
{
EditorGUILayout.LabelField("Match Filters (regex, case-insensitive)", EditorStyles.boldLabel);
namePattern = EditorGUILayout.TextField("GameObject name", namePattern);
materialPattern = EditorGUILayout.TextField("Material name", materialPattern);
useTransparentQueueAsDecal = EditorGUILayout.Toggle("Treat transparent (queue>=2450) as decal", useTransparentQueueAsDecal);
onlyActiveRenderers = EditorGUILayout.Toggle("Skip inactive renderers", onlyActiveRenderers);
EditorGUILayout.Space();
EditorGUILayout.LabelField("Operations", EditorStyles.boldLabel);
EditorGUILayout.HelpBox(
"MATCHED renderers (vegetation/decals): remove all Colliders + Cast Shadows = Off.\n" +
"UNMATCHED renderers marked Batching Static: Static Shadow Caster = On.\n" +
"Operates on the currently OPEN scene. Undo supported.",
MessageType.Info);
using (new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button("Preview (dry run)")) Run(dryRun: true);
if (GUILayout.Button("Apply")) Run(dryRun: false);
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Last Report", EditorStyles.boldLabel);
scroll = EditorGUILayout.BeginScrollView(scroll);
EditorGUILayout.TextArea(lastReport, GUILayout.ExpandHeight(true));
EditorGUILayout.EndScrollView();
}
void Run(bool dryRun)
{
var scene = SceneManager.GetActiveScene();
if (!scene.IsValid())
{
lastReport = "No active scene.";
return;
}
Regex nameRx, matRx;
try
{
nameRx = new Regex(namePattern, RegexOptions.IgnoreCase);
matRx = new Regex(materialPattern, RegexOptions.IgnoreCase);
}
catch (System.Exception e)
{
lastReport = "Bad regex: " + e.Message;
return;
}
var roots = scene.GetRootGameObjects();
var allRenderers = new List<Renderer>();
foreach (var r in roots) allRenderers.AddRange(r.GetComponentsInChildren<Renderer>(includeInactive: !onlyActiveRenderers));
int matchedCount = 0, collidersRemoved = 0, shadowsOff = 0, staticShadowOn = 0, skipped = 0;
var matchedNames = new List<string>();
int undoGroup = -1;
if (!dryRun)
{
Undo.IncrementCurrentGroup();
Undo.SetCurrentGroupName("Scene Renderer Optimizer");
undoGroup = Undo.GetCurrentGroup();
}
foreach (var r in allRenderers)
{
if (!r) continue;
var go = r.gameObject;
bool matches = IsMatch(go, r, nameRx, matRx);
if (matches)
{
matchedCount++;
if (matchedNames.Count < 200) matchedNames.Add(GetHierarchyPath(go.transform));
if (!dryRun)
{
var colliders = go.GetComponents<Collider>();
foreach (var c in colliders)
{
Undo.DestroyObjectImmediate(c);
collidersRemoved++;
}
if (r.shadowCastingMode != UnityEngine.Rendering.ShadowCastingMode.Off)
{
Undo.RecordObject(r, "Disable Shadow Cast");
r.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
shadowsOff++;
EditorUtility.SetDirty(r);
}
}
else
{
collidersRemoved += go.GetComponents<Collider>().Length;
if (r.shadowCastingMode != UnityEngine.Rendering.ShadowCastingMode.Off) shadowsOff++;
}
}
else
{
var flags = GameObjectUtility.GetStaticEditorFlags(go);
bool isBatchingStatic = (flags & StaticEditorFlags.BatchingStatic) != 0;
if (isBatchingStatic && r.shadowCastingMode != UnityEngine.Rendering.ShadowCastingMode.Off)
{
if (!r.staticShadowCaster)
{
if (!dryRun)
{
Undo.RecordObject(r, "Enable Static Shadow Caster");
r.staticShadowCaster = true;
EditorUtility.SetDirty(r);
}
staticShadowOn++;
}
}
else
{
skipped++;
}
}
}
if (!dryRun)
{
Undo.CollapseUndoOperations(undoGroup);
EditorSceneManager.MarkSceneDirty(scene);
}
var sb = new System.Text.StringBuilder();
sb.AppendLine(dryRun ? "DRY RUN" : "APPLIED");
sb.AppendLine($"Scene: {scene.name}");
sb.AppendLine($"Renderers scanned: {allRenderers.Count}");
sb.AppendLine($"Matched (vegetation/decal): {matchedCount}");
sb.AppendLine($" Colliders to remove / removed: {collidersRemoved}");
sb.AppendLine($" Shadows off: {shadowsOff}");
sb.AppendLine($"Static Shadow Caster enabled: {staticShadowOn}");
sb.AppendLine($"Skipped (non-static, non-match): {skipped}");
sb.AppendLine();
sb.AppendLine("First matched (up to 200):");
foreach (var n in matchedNames) sb.AppendLine(" " + n);
lastReport = sb.ToString();
}
bool IsMatch(GameObject go, Renderer r, Regex nameRx, Regex matRx)
{
if (nameRx.IsMatch(go.name)) return true;
var mats = r.sharedMaterials;
for (int i = 0; i < mats.Length; i++)
{
var m = mats[i];
if (!m) continue;
if (matRx.IsMatch(m.name)) return true;
if (useTransparentQueueAsDecal && m.renderQueue >= 2450) return true;
}
return false;
}
static string GetHierarchyPath(Transform t)
{
var stack = new Stack<string>();
while (t)
{
stack.Push(t.name);
t = t.parent;
}
return string.Join("/", stack);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 361cb7c2dff8e4e7c905f18797743962

View File

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

View File

@@ -0,0 +1,18 @@
using System;
namespace Darkmatter.Libs.UnityUtils.Runtime.Progress;
public sealed class ActionProgress : IProgress<float>
{
private readonly Action<float> _onReport;
public ActionProgress(Action<float> onReport)
{
_onReport = onReport ?? throw new ArgumentNullException(nameof(onReport));
}
public void Report(float value)
{
_onReport(value);
}
}

View File

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

View File

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

View File

@@ -0,0 +1,40 @@
using System;
using UnityEngine;
namespace Darkmatter.Libs.UnityUtils
{
/// <summary>
/// Attribute that restricts an Object field to only accept objects implementing a specific interface.
/// Works with GameObjects (will find component), Components, and ScriptableObjects.
/// </summary>
/// <example>
/// [SerializeField, RequireInterface(typeof(IDamageable))]
/// private Object damageableTarget;
/// </example>
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public class RequireInterfaceAttribute : PropertyAttribute
{
public Type InterfaceType { get; private set; }
/// <summary>
/// Restricts the field to objects implementing the specified interface.
/// </summary>
/// <param name="interfaceType">The interface type that objects must implement.</param>
public RequireInterfaceAttribute(Type interfaceType)
{
if (interfaceType == null)
{
Debug.LogError("[RequireInterface] Interface type cannot be null.");
return;
}
if (!interfaceType.IsInterface)
{
Debug.LogError($"[RequireInterface] {interfaceType.Name} is not an interface type.");
return;
}
InterfaceType = interfaceType;
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,17 @@
using UnityEngine;
namespace Darkmatter.Libs.UnityUtils.Runtime.Gauges;
public static class AnalogGaugeMath
{
public static float EvaluateAngle(
float inputValue,
float startValue,
float endValue,
float startAngle,
float endAngle)
{
var t = Mathf.Clamp01(Mathf.InverseLerp(startValue, endValue, inputValue));
return Mathf.Lerp(startAngle, endAngle, t);
}
}

View File

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

View File

@@ -0,0 +1,38 @@
using UnityEngine;
namespace Darkmatter.Libs.UnityUtils.Runtime.Gauges;
public struct SmoothedFloat
{
private float _currentValue;
private bool _isInitialized;
public float CurrentValue => _currentValue;
public bool IsInitialized => _isInitialized;
public float Update(float targetValue, float responseSpeed, float deltaTime)
{
if (!_isInitialized)
return Snap(targetValue);
if (responseSpeed <= 0f)
return Snap(targetValue);
var blend = 1f - Mathf.Exp(-responseSpeed * Mathf.Max(0f, deltaTime));
_currentValue = Mathf.Lerp(_currentValue, targetValue, blend);
return _currentValue;
}
public float Snap(float value)
{
_currentValue = value;
_isInitialized = true;
return _currentValue;
}
public void Reset()
{
_currentValue = 0f;
_isInitialized = false;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 12e35c688b9e54636ad36981b60913f3

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b6e68b7014224451bad76d3a7bd845b1
timeCreated: 1770792751

View File

@@ -0,0 +1,29 @@
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
namespace Darkmatter.Libs.UnityUtils.Runtime.Inputs;
public static class InputUtils
{
public static bool IsPointerOverGameObject()
{
if (EventSystem.current == null) return false;
if (Touchscreen.current == null)
return EventSystem.current.IsPointerOverGameObject();
foreach (var touch in Touchscreen.current.touches)
{
if (touch.press.isPressed)
{
int touchId = touch.touchId.ReadValue();
if (EventSystem.current.IsPointerOverGameObject(touchId))
{
return true;
}
}
}
return false;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c7dd336a56054f05b73cea102c916715
timeCreated: 1770792778

View File

@@ -0,0 +1,230 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
namespace Darkmatter.Libs.UnityUtils.Runtime.Inputs;
public sealed class TouchGestureSelector
{
private int _sampleFrame = -1;
private int _activeLookTouchId = -1;
private readonly HashSet<int> _activeTouchIds = new();
private readonly HashSet<int> _busyTouchIds = new();
private readonly List<int> _releasedTouchIds = new();
private readonly List<RaycastResult> _uiRaycastResults = new(8);
private EventSystem _cachedEventSystem;
private PointerEventData _pointerEventData;
public void Reset()
{
_sampleFrame = -1;
_activeLookTouchId = -1;
_activeTouchIds.Clear();
_busyTouchIds.Clear();
_releasedTouchIds.Clear();
_uiRaycastResults.Clear();
_cachedEventSystem = null;
_pointerEventData = null;
}
public bool TryGetLookDelta(float activationDeltaPixels, out Vector2 touchDelta)
{
touchDelta = Vector2.zero;
RefreshOwnership();
Touchscreen touchscreen = Touchscreen.current;
if (touchscreen == null)
{
return false;
}
if (_activeLookTouchId >= 0 &&
!_busyTouchIds.Contains(_activeLookTouchId) &&
TryGetPressedTouchDeltaById(touchscreen, _activeLookTouchId, out Vector2 activeTouchDelta))
{
touchDelta = activeTouchDelta;
return true;
}
_activeLookTouchId = -1;
float activationDeltaSqr = Mathf.Max(0f, activationDeltaPixels);
activationDeltaSqr *= activationDeltaSqr;
foreach (var touchControl in touchscreen.touches)
{
if (!touchControl.press.isPressed)
{
continue;
}
int touchId = touchControl.touchId.ReadValue();
if (_busyTouchIds.Contains(touchId))
{
continue;
}
Vector2 delta = touchControl.delta.ReadValue();
if (delta.sqrMagnitude < activationDeltaSqr)
{
continue;
}
_activeLookTouchId = touchId;
touchDelta = delta;
return true;
}
return false;
}
public bool TryGetPinchPositions(out Vector2 firstTouch, out Vector2 secondTouch)
{
firstTouch = default;
secondTouch = default;
RefreshOwnership();
Touchscreen touchscreen = Touchscreen.current;
if (touchscreen == null)
{
return false;
}
int activeTouchCount = 0;
foreach (var touchControl in touchscreen.touches)
{
if (!touchControl.press.isPressed)
{
continue;
}
int touchId = touchControl.touchId.ReadValue();
if (_busyTouchIds.Contains(touchId))
{
continue;
}
Vector2 position = touchControl.position.ReadValue();
if (activeTouchCount == 0)
{
firstTouch = position;
}
else
{
secondTouch = position;
return true;
}
activeTouchCount++;
}
return false;
}
private void RefreshOwnership()
{
if (_sampleFrame == Time.frameCount)
{
return;
}
_sampleFrame = Time.frameCount;
Touchscreen touchscreen = Touchscreen.current;
if (touchscreen == null)
{
_activeTouchIds.Clear();
_busyTouchIds.Clear();
_releasedTouchIds.Clear();
_activeLookTouchId = -1;
return;
}
_releasedTouchIds.Clear();
foreach (int activeTouchId in _activeTouchIds)
{
_releasedTouchIds.Add(activeTouchId);
}
foreach (var touchControl in touchscreen.touches)
{
if (!touchControl.press.isPressed)
{
continue;
}
int touchId = touchControl.touchId.ReadValue();
if (_releasedTouchIds.Remove(touchId))
{
continue;
}
_activeTouchIds.Add(touchId);
if (IsScreenPositionOverUi(touchControl.position.ReadValue()))
{
_busyTouchIds.Add(touchId);
}
}
for (int i = 0; i < _releasedTouchIds.Count; i++)
{
int releasedTouchId = _releasedTouchIds[i];
_activeTouchIds.Remove(releasedTouchId);
_busyTouchIds.Remove(releasedTouchId);
if (_activeLookTouchId == releasedTouchId)
{
_activeLookTouchId = -1;
}
}
}
private static bool TryGetPressedTouchDeltaById(Touchscreen touchscreen, int touchId, out Vector2 touchDelta)
{
touchDelta = default;
if (touchscreen == null)
{
return false;
}
foreach (var touchControl in touchscreen.touches)
{
if (!touchControl.press.isPressed)
{
continue;
}
if (touchControl.touchId.ReadValue() != touchId)
{
continue;
}
touchDelta = touchControl.delta.ReadValue();
return true;
}
return false;
}
private bool IsScreenPositionOverUi(Vector2 screenPosition)
{
EventSystem eventSystem = EventSystem.current;
if (eventSystem == null)
{
return false;
}
if (_pointerEventData == null || !ReferenceEquals(_cachedEventSystem, eventSystem))
{
_cachedEventSystem = eventSystem;
_pointerEventData = new PointerEventData(eventSystem);
}
_pointerEventData.Reset();
_pointerEventData.position = screenPosition;
_uiRaycastResults.Clear();
eventSystem.RaycastAll(_pointerEventData, _uiRaycastResults);
return _uiRaycastResults.Count > 0;
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,29 @@
using System;
namespace Darkmatter.Libs.UnityUtils.Runtime.Progress;
public sealed class MappedProgress : IProgress<float>
{
private readonly IProgress<float> _target;
private readonly float _offset;
private readonly float _scale;
public MappedProgress(IProgress<float> target, float offset, float scale)
{
_target = target ?? throw new ArgumentNullException(nameof(target));
_offset = offset;
_scale = scale;
}
public void Report(float value)
{
var mapped = _offset + (value * _scale);
if (mapped < 0f)
mapped = 0f;
else if (mapped > 1f)
mapped = 1f;
_target.Report(mapped);
}
}

View File

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

View File

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

View File

@@ -0,0 +1,8 @@
namespace Darkmatter.Libs.UnityUtils.Runtime.Transforms;
public enum RotationAxis
{
X,
Y,
Z
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 26da8545c2aed450f96a49533c8724c3

View File

@@ -0,0 +1,26 @@
using UnityEngine;
namespace Darkmatter.Libs.UnityUtils.Runtime.Transforms;
public static class RotationAxisUtility
{
public static float GetAxisValue(Vector3 eulerAngles, RotationAxis axis)
{
return axis switch
{
RotationAxis.X => eulerAngles.x,
RotationAxis.Y => eulerAngles.y,
_ => eulerAngles.z
};
}
public static Vector3 WithAxisValue(Vector3 eulerAngles, RotationAxis axis, float value)
{
return axis switch
{
RotationAxis.X => new Vector3(value, eulerAngles.y, eulerAngles.z),
RotationAxis.Y => new Vector3(eulerAngles.x, value, eulerAngles.z),
_ => new Vector3(eulerAngles.x, eulerAngles.y, value)
};
}
}

View File

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

View File

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

File diff suppressed because one or more lines are too long

View File

@@ -1240,8 +1240,54 @@ Transform:
- {fileID: 445008006}
- {fileID: 1043308346}
- {fileID: 610419919}
- {fileID: 789049882}
m_Father: {fileID: 1798580248}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &789049881
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 789049882}
- component: {fileID: 789049883}
m_Layer: 0
m_Name: LoadingFeatureModule
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &789049882
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 789049881}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 752713007}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &789049883
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 789049881}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 673a21bf7c6bb430eadece2a989d79ac, type: 3}
m_Name:
m_EditorClassIdentifier: Features.Loading::Darkmatter.Features.Loading.LoadingFeatureModule
loadingScreenView: {fileID: 1424266588}
--- !u!1 &899675107
GameObject:
m_ObjectHideFlags: 0
@@ -1540,7 +1586,7 @@ MonoBehaviour:
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_DisabledColor: {r: 1, g: 1, b: 1, a: 1}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
@@ -1554,7 +1600,7 @@ MonoBehaviour:
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_Interactable: 0
m_TargetGraphic: {fileID: 0}
m_FillRect: {fileID: 1315655362}
m_HandleRect: {fileID: 0}
@@ -1643,9 +1689,9 @@ Canvas:
m_OverrideSorting: 0
m_OverridePixelPerfect: 0
m_SortingBucketNormalizedSize: 0
m_VertexColorAlwaysGammaSpace: 0
m_VertexColorAlwaysGammaSpace: 1
m_UseReflectionProbes: 0
m_AdditionalShaderChannelsFlag: 25
m_AdditionalShaderChannelsFlag: 1
m_UpdateRectTransformForStandalone: 0
m_SortingLayerID: 0
m_SortingOrder: 800
@@ -1687,6 +1733,7 @@ MonoBehaviour:
loadingSlider: {fileID: 1377420118}
statusText: {fileID: 17632382}
loadingSmoothTime: 10
dotInterval: 0.4
--- !u!1 &1740606684
GameObject:
m_ObjectHideFlags: 0
@@ -1837,6 +1884,7 @@ MonoBehaviour:
- {fileID: 610419920}
- {fileID: 1776076872}
- {fileID: 97140291}
- {fileID: 789049883}
--- !u!1 &1890425864
GameObject:
m_ObjectHideFlags: 0
@@ -1969,7 +2017,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
m_IsActive: 1
--- !u!114 &2133561495
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -2027,7 +2075,7 @@ Canvas:
m_OverrideSorting: 0
m_OverridePixelPerfect: 0
m_SortingBucketNormalizedSize: 0
m_VertexColorAlwaysGammaSpace: 0
m_VertexColorAlwaysGammaSpace: 1
m_UseReflectionProbes: 0
m_AdditionalShaderChannelsFlag: 0
m_UpdateRectTransformForStandalone: 0

View File

@@ -191,6 +191,50 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 100714806}
m_CullTransparentMesh: 1
--- !u!1 &131818674
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 131818675}
- component: {fileID: 131818676}
m_Layer: 0
m_Name: MainMenuFlowFeatureModule
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &131818675
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 131818674}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 2083222964}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &131818676
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 131818674}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 537a5a77a85a141519e96811f4f4e0a3, type: 3}
m_Name:
m_EditorClassIdentifier: Features.MainMenuFlow::Darkmatter.Features.MainMenuFlow.MainMenuFlowFeatureModule
--- !u!1 &243020571
GameObject:
m_ObjectHideFlags: 0
@@ -6406,6 +6450,7 @@ MonoBehaviour:
autoInjectGameObjects: []
serviceModules:
- {fileID: 1102850749}
- {fileID: 131818676}
--- !u!1 &1433266371
GameObject:
m_ObjectHideFlags: 0
@@ -6883,7 +6928,7 @@ GameObject:
m_Component:
- component: {fileID: 2083222964}
m_Layer: 0
m_Name: ServiceModules
m_Name: FeatureModule
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@@ -6903,6 +6948,7 @@ Transform:
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1102850748}
- {fileID: 131818675}
m_Father: {fileID: 1407834210}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &2118659397