savya #2

Merged
savya merged 6 commits from savya into main 2026-05-27 15:41:46 +02:00
236 changed files with 41978 additions and 60 deletions
Showing only changes of commit 93950e8bc6 - Show all commits

View File

@@ -13,7 +13,7 @@ namespace Darkmatter.App.LifetimeScopes
{
foreach (var module in serviceModules)
{
if (module is IServiceModule serviceModule)
if (module is IModule serviceModule)
serviceModule.Register(builder);
}
}

View File

@@ -6,6 +6,6 @@ namespace Darkmatter.Core.Contracts.Features.Coloring
public interface IColorPalette
{
string Id { get; }
IReadOnlyList<Color> Colors { get; }
List<Color> Colors { get; }
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
namespace Darkmatter.Core.Contracts.Features.DrawingCatalog;
public interface IDrawingCatalogController
{
IReadOnlyList<string> VisibleIds { get; }
event Action ListChanged;
UniTask InitializeAsync(CancellationToken ct);
void OnTemplateSelected(string id);
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b0732a5de2a84833ab4d3252d9e22851
timeCreated: 1779881997

View File

@@ -1,8 +1,9 @@
using System.Collections.Generic;
using Darkmatter.Core.Data.Dynamic.Features.Coloring;
using Darkmatter.Core.Data.Static.Features.ShapeBuilder;
using UnityEngine;
namespace Darkmatter.Core.Contracts.Features.Drawing
namespace Darkmatter.Core.Contracts.Features.DrawingCatalog
{
public interface IDrawingTemplate
{

View File

@@ -2,15 +2,15 @@ using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using UnityEngine;
namespace Darkmatter.Core.Contracts.Features.Drawing
namespace Darkmatter.Core.Contracts.Features.DrawingCatalog
{
public interface IDrawingTemplateCatalog
{
UniTask InitializeAsync();
UniTask FetchAsync();
IReadOnlyList<string> AllTemplateIds { get; }
UniTask<Sprite> GetThumbnailAsync(string id);
UniTask<IDrawingTemplate> LoadAsync(string id);
void Release(string id);
string NextUnseen(string currentId);
void ReleaseAll();
string GetNextTemplate(string currentId);
}
}

View File

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

View File

@@ -0,0 +1,25 @@
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using Darkmatter.Core.Data.Dynamic.Features.Progression;
using UnityEngine;
// Code/Core/Contracts/Features/Progression/IProgressionSystem.cs
namespace Darkmatter.Core.Contracts.Features.Progression
{
public interface IProgressionSystem
{
UniTask LoadAsync();
UniTask SaveAsync();
IReadOnlyCollection<string> CompletedTemplateIds { get; }
void MarkCompleted(string templateId);
DrawingProgress? GetProgress(string templateId);
UniTask SaveProgressAsync(DrawingProgress progress);
UniTask SaveProgressAsync(DrawingProgress progress, byte[] thumbnailPng);
UniTask ClearProgressAsync(string templateId);
bool IsCompleted(string templateId);
UniTask<Texture2D> GetCachedThumbnailAsync(string templateId);
}
}

View File

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

View File

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

View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using Darkmatter.Core.Enums.Features.Progression;
using UnityEngine;
namespace Darkmatter.Core.Data.Dynamic.Features.Progression
{
[Serializable]
public struct DrawingProgress
{
public string templateId;
public DrawingPhase phase;
public List<string> SnappedPieces;
public List<RegionColorEntry> RegionColors;
public bool hasThumbnail;
public bool hasBeenCompleted;
public int completionCount;
public DateTime UpdatedUtc;
public DateTime? FirstCompletedUtc;
public DrawingProgress(string templateId, DrawingPhase phase, List<string> snappedPieces,
List<RegionColorEntry> regionColors, bool hasThumbnail, bool hasBeenCompleted,
int completionCount, DateTime updatedUtc, DateTime? firstCompletedUtc)
{
this.templateId = templateId;
this.phase = phase;
SnappedPieces = snappedPieces;
RegionColors = regionColors;
this.hasThumbnail = hasThumbnail;
this.hasBeenCompleted = hasBeenCompleted;
this.completionCount = completionCount;
UpdatedUtc = updatedUtc;
FirstCompletedUtc = firstCompletedUtc;
}
}
}

View File

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

View File

@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
namespace Darkmatter.Core.Data.Dynamic.Features.Progression
{
[Serializable]
public struct ProgressionRootDto
{
public List<DrawingProgress> records;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3c8f422a1719468387c90bdad95cf992
timeCreated: 1779887245

View File

@@ -0,0 +1,11 @@
using System;
namespace Darkmatter.Core.Data.Dynamic.Features.Progression
{
[Serializable]
public struct RegionColorEntry
{
public string regionId;
public float r, g, b, a;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 659d6e472d07425b86684258dda5644e
timeCreated: 1779886727

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,4 @@
namespace Darkmatter.Core.Data.Signals.Features.Drawing
{
public record struct DrawingSelectedSignal(string TemplateId);
}

View File

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

View File

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

View File

@@ -0,0 +1,13 @@
using System.Collections.Generic;
using Darkmatter.Core.Contracts.Features.Coloring;
using UnityEngine;
namespace Darkmatter.Core.Data.Static.Features.Coloring
{
[CreateAssetMenu(menuName = "Darkmatter/Coloring/New Color Palette")]
public class ColorPaletteSO : ScriptableObject, IColorPalette
{
[field: SerializeField] public string Id { get; private set; }
[field: SerializeField] public List<Color> Colors { get; private set; }
}
}

View File

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

View File

@@ -1,9 +1,10 @@
using System.Collections.Generic;
using Darkmatter.Core.Contracts.Features.Drawing;
using Darkmatter.Core.Contracts.Features.DrawingCatalog;
using Darkmatter.Core.Data.Dynamic.Features.Coloring;
using Darkmatter.Core.Data.Static.Features.ShapeBuilder;
using UnityEngine;
namespace Darkmatter.Core.Data.Static.Features.Drawing
namespace Darkmatter.Core.Data.Static.Features.DrawingTemplate
{
[CreateAssetMenu(menuName = "Darkmatter/Drawing/New Drawing Template")]
public class DrawingTemplateSO : ScriptableObject, IDrawingTemplate

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 58192c2a0a784950851647d3f0130ad1
timeCreated: 1779882018

View File

@@ -1,6 +1,6 @@
using UnityEngine;
namespace Darkmatter.Core
namespace Darkmatter.Core.Data.Static.Features.ShapeBuilder
{
[CreateAssetMenu(fileName = "ShapeSO", menuName = "Darkmatter/Drawing/New Shape")]
public class ShapeSO : ScriptableObject

View File

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

View File

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

View File

@@ -0,0 +1,8 @@
namespace Darkmatter.Core.Enums.Features.Progression
{
public enum DrawingPhase
{
ShapeBuilding,
Coloring,
}
}

View File

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

View File

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

View File

@@ -0,0 +1,20 @@
{
"name": "Features.DrawingCatalog",
"rootNamespace": "Darkmatter.Features.DrawingCatalog",
"references": [
"GUID:6a0a834eb41764f12ba55c3fb04a40cb",
"GUID:c1c03c0e5b2f4412b9f2be1c20d6a9b1",
"GUID:b4c9f7fbf1e144933a1797dc208ece5f",
"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: eb9b7ee4936ff42bebd83ca110182103
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@@ -0,0 +1,21 @@
using Darkmatter.Core.Contracts.Features.DrawingCatalog;
using Darkmatter.Features.DrawingCatalog.Systems;
using Darkmatter.Libs.Installers;
using UnityEngine;
using VContainer;
using VContainer.Unity;
namespace Darkmatter.Features.DrawingCatalog.Installers
{
public class DrawingCatalogFeatureModule : MonoBehaviour, IModule
{
[SerializeField] private DrawingCatalogView drawingCatalogView;
public void Register(IContainerBuilder builder)
{
builder.Register<IDrawingCatalogController, DrawingCatalogController>(Lifetime.Singleton);
if(drawingCatalogView != null)
builder.RegisterEntryPoint<DrawingCatalogPresenter>().WithParameter(drawingCatalogView);
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using Darkmatter.Core.Contracts.Features.DrawingCatalog;
using Darkmatter.Core.Contracts.Features.Progression;
using Darkmatter.Core.Data.Signals.Features.Drawing;
using Darkmatter.Libs.Observer;
using ZLinq;
namespace Darkmatter.Features.DrawingCatalog.Systems;
public sealed class DrawingCatalogController : IDrawingCatalogController
{
private readonly IDrawingTemplateCatalog _catalog;
private readonly IEventBus _bus;
private readonly IProgressionSystem _progression;
private readonly List<string> _visible = new();
public IReadOnlyList<string> VisibleIds => _visible;
public event Action ListChanged;
public DrawingCatalogController(
IDrawingTemplateCatalog catalog,
IProgressionSystem progression,
IEventBus bus)
{
_catalog = catalog;
_progression = progression;
_bus = bus;
}
public async UniTask InitializeAsync(CancellationToken ct)
{
await _catalog.FetchAsync();
Refresh();
}
public void OnTemplateSelected(string id)
{
_bus.Publish(new DrawingSelectedSignal(id));
}
private void Refresh()
{
_visible.Clear();
var all = _catalog.AllTemplateIds;
foreach (var id in all)
if (!_progression.CompletedTemplateIds.AsValueEnumerable().Contains(id))
_visible.Add(id);
foreach (var id in all)
if (_progression.CompletedTemplateIds.AsValueEnumerable().Contains(id))
_visible.Add(id);
ListChanged?.Invoke();
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1252b78470d594aa58188c32f552c52a

View File

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

View File

@@ -0,0 +1,15 @@
using UnityEngine;
namespace Darkmatter.Features.DrawingCatalog;
public struct CatalogItemVM
{
public string Id { get; }
public Sprite Thumbnail { get; }
public CatalogItemVM(string id, Sprite thumbnail)
{
Id = id;
Thumbnail = thumbnail;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7b4274f9a3304610b13c6d01280139dc
timeCreated: 1779881383

View File

@@ -0,0 +1,18 @@
using UnityEngine;
using UnityEngine.UI;
namespace Darkmatter.Features.DrawingCatalog;
public class DrawingCatalogButton : MonoBehaviour
{
public string Id { get; private set; }
[SerializeField] private Image thumbnail;
[SerializeField] private Button button;
public void Initialize(string id,Sprite thumbnailSprite, UnityEngine.Events.UnityAction onClick)
{
Id = id;
thumbnail.sprite = thumbnailSprite;
button.onClick.AddListener(onClick);
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: da23f33bd6fc4bf99f251714180406f1
timeCreated: 1779880745

View File

@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using Darkmatter.Core.Contracts.Features.DrawingCatalog;
using Darkmatter.Features.DrawingCatalog.Systems;
using VContainer.Unity;
namespace Darkmatter.Features.DrawingCatalog
{
public class DrawingCatalogPresenter : IStartable, IDisposable
{
private readonly DrawingCatalogView _view;
private readonly IDrawingCatalogController _controller;
private readonly IDrawingTemplateCatalog _catalog;
private readonly CancellationTokenSource _cts = new();
public DrawingCatalogPresenter(DrawingCatalogView view, DrawingCatalogController controller,
IDrawingTemplateCatalog catalog)
{
_view = view;
_controller = controller;
_catalog = catalog;
}
public void Start()
{
_view.OnItemClicked += OnItemClicked;
_controller.ListChanged += OnListChanged;
}
private void OnItemClicked(string id) =>
_controller.OnTemplateSelected(id);
private void OnListChanged() =>
RefreshAsync(_cts.Token).Forget();
private async UniTask RefreshAsync(CancellationToken ct)
{
var ids = _controller.VisibleIds;
var vms = new List<CatalogItemVM>(ids.Count);
foreach (var id in ids)
{
if (ct.IsCancellationRequested) return;
var thumb = await _catalog.GetThumbnailAsync(id);
vms.Add(new CatalogItemVM(id, thumb));
}
if (ct.IsCancellationRequested) return;
_view.SetItems(vms);
}
public void Dispose()
{
_view.OnItemClicked -= OnItemClicked;
_controller.ListChanged -= OnListChanged;
_cts.Cancel();
_cts.Dispose();
}
}
}

View File

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

View File

@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Pool;
namespace Darkmatter.Features.DrawingCatalog
{
public class DrawingCatalogView : MonoBehaviour
{
[SerializeField] private RectTransform content;
[SerializeField] private DrawingCatalogButton buttonPrefab;
private readonly List<DrawingCatalogButton> _buttons = new();
public event Action<string> OnItemClicked;
public void SetItems(IReadOnlyList<CatalogItemVM> items)
{
while (_buttons.Count < items.Count)
{
var button = Instantiate(buttonPrefab, content);
var item = items[_buttons.Count];
button.Initialize(item.Id, item.Thumbnail,
() => { OnItemClicked?.Invoke(item.Id); });
_buttons.Add(button);
}
while (_buttons.Count > items.Count)
{
var last = _buttons[^1];
_buttons.RemoveAt(_buttons.Count - 1);
Destroy(last.gameObject);
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 37f3d6f10bf1349a382f7ff96cc510b7

View File

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

View File

@@ -0,0 +1,20 @@
{
"name": "Features.DrawingTemplates",
"rootNamespace": "Darkmatter.Features.DrawingTemplates",
"references": [
"GUID:6a0a834eb41764f12ba55c3fb04a40cb",
"GUID:c1c03c0e5b2f4412b9f2be1c20d6a9b1",
"GUID:efcaa22887a6b4471829c3b3878147a2",
"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: 6a005d98aed1c4439bc4689802fa2e3b
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@@ -0,0 +1,16 @@
using Darkmatter.Core.Contracts.Features.DrawingCatalog;
using Darkmatter.Features.DrawingTemplates.Systems;
using UnityEngine;
using Darkmatter.Libs.Installers;
using VContainer;
namespace Darkmatter.Features.DrawingTemplates
{
public class DrawingTemplateFeatureModule : MonoBehaviour, IModule
{
public void Register(IContainerBuilder builder)
{
builder.Register<IDrawingTemplateCatalog, AddressableDrawingTemplateCatalog>(Lifetime.Singleton);
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,112 @@
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using Darkmatter.Core.Contracts.Features.DrawingCatalog;
using Darkmatter.Core.Contracts.Features.Progression;
using Darkmatter.Core.Contracts.Services.Assets;
using Darkmatter.Core.Data.Static.Features.DrawingTemplate;
using UnityEngine;
namespace Darkmatter.Features.DrawingTemplates.Systems
{
public sealed class AddressableDrawingTemplateCatalog : IDrawingTemplateCatalog
{
private const string DrawingLabel = "drawing";
private readonly IAssetProviderService _assets;
private readonly IProgressionSystem _progression;
private readonly List<string> _allIds = new();
private readonly Dictionary<string, DrawingTemplateSO> _byId = new();
private bool _initialized;
public IReadOnlyList<string> AllTemplateIds => _allIds;
public AddressableDrawingTemplateCatalog(
IAssetProviderService assets,
IProgressionSystem progression)
{
_assets = assets;
_progression = progression;
}
public async UniTask FetchAsync()
{
if (_initialized) return;
var templates = await _assets.LoadAssetsAsync<DrawingTemplateSO>(
key: DrawingLabel,
progress: null,
cancellationToken: CancellationToken.None);
_allIds.Clear();
_byId.Clear();
foreach (var t in templates)
{
if (t == null || string.IsNullOrEmpty(t.Id)) continue;
_allIds.Add(t.Id);
_byId[t.Id] = t;
}
_allIds.Sort();
_initialized = true;
}
public UniTask<Sprite> GetThumbnailAsync(string id)
{
if (!_byId.TryGetValue(id, out var t))
throw new KeyNotFoundException($"Template '{id}' not in catalog. Did InitializeAsync run?");
return UniTask.FromResult(t.DefaultThumbnail);
}
public UniTask<IDrawingTemplate> LoadAsync(string id)
{
if (_byId.TryGetValue(id, out var t))
return UniTask.FromResult<IDrawingTemplate>(t);
return LoadIndividualAsync(id);
}
private async UniTask<IDrawingTemplate> LoadIndividualAsync(string id)
{
var t = await _assets.LoadAssetAsync<DrawingTemplateSO>(
id, progress: null, cancellationToken: CancellationToken.None);
if (t == null)
throw new KeyNotFoundException($"No drawing template at address '{id}'.");
_byId[id] = t;
if (!_allIds.Contains(id))
{
_allIds.Add(id);
_allIds.Sort();
}
return t;
}
public void ReleaseAll()
{
if (!_initialized) return;
_assets.UnloadAsset(DrawingLabel);
_byId.Clear();
_allIds.Clear();
_initialized = false;
}
public string GetNextTemplate(string currentId)
{
if (_allIds.Count == 0) return null;
int startIdx = currentId != null ? _allIds.IndexOf(currentId) : -1;
for (int i = 1; i <= _allIds.Count; i++)
{
var idx = (startIdx + i) % _allIds.Count;
var candidate = _allIds[idx];
if (!_progression.IsCompleted(candidate))
return candidate;
}
return _allIds[(startIdx + 1) % _allIds.Count];
}
}
}

View File

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

View File

@@ -6,7 +6,7 @@ using VContainer.Unity;
namespace Darkmatter.Features.History
{
public class HistoryServiceModule : MonoBehaviour, IServiceModule
public class HistoryFeatureModule : MonoBehaviour, IModule
{
[SerializeField] private HistoryButtonsView historyButtonsView;

View File

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

View File

@@ -0,0 +1,20 @@
{
"name": "Features.Progression",
"rootNamespace": "Darkmatter.Features.Progression",
"references": [
"GUID:6a0a834eb41764f12ba55c3fb04a40cb",
"GUID:c1c03c0e5b2f4412b9f2be1c20d6a9b1",
"GUID:564d11c0820a9455c8821cd85e9d0fd1",
"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: f0bb65a4e720b460289d630f2ebaf2d5
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@@ -0,0 +1,17 @@
using Darkmatter.Core.Contracts.Features.Progression;
using Darkmatter.Features.Progression.Systems;
using Darkmatter.Libs.Installers;
using UnityEngine;
using VContainer;
namespace Darkmatter.Features.Progression.Installers
{
public class ProgressionFeatureModule : MonoBehaviour, IModule
{
public void Register(IContainerBuilder builder)
{
builder.Register<ProgressionRepository>(Lifetime.Singleton);
builder.Register<IProgressionSystem, ProgressionSystem>(Lifetime.Singleton);
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,151 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Cysharp.Threading.Tasks;
using Darkmatter.Core.Data.Dynamic.Features.Progression;
using Darkmatter.Libs.PlayerPrefs;
using UnityEngine;
namespace Darkmatter.Features.Progression.Systems;
public sealed class ProgressionRepository
{
private const string ThumbnailsFolder = "thumbnails";
private readonly Dictionary<string, DrawingProgress> _records = new();
public IEnumerable<DrawingProgress> AllProgress() => _records.Values;
public DrawingProgress? TryGet(string templateId) =>
_records.TryGetValue(templateId, out var p) ? p : (DrawingProgress?)null;
public UniTask LoadAsync()
{
_records.Clear();
var json = ProtectedPlayerPrefs.GetString(PlayerPrefsKeys.Progression, "");
if (string.IsNullOrEmpty(json)) return UniTask.CompletedTask;
ProgressionRootDto root;
try
{
root = JsonUtility.FromJson<ProgressionRootDto>(json);
}
catch (Exception e)
{
Debug.LogError($"[Progression] Failed to parse saved root: {e}");
return UniTask.CompletedTask;
}
if (root.records != null)
{
foreach (var rec in root.records)
if (!string.IsNullOrEmpty(rec.templateId))
_records[rec.templateId] = rec;
}
return UniTask.CompletedTask;
}
public UniTask SaveAsync()
{
FlushRoot();
return UniTask.CompletedTask;
}
public UniTask SaveProgressAsync(DrawingProgress p)
{
if (string.IsNullOrEmpty(p.templateId))
throw new ArgumentException("DrawingProgress.templateId must be set.");
_records[p.templateId] = p;
FlushRoot();
return UniTask.CompletedTask;
}
public UniTask DeleteProgressAsync(string templateId)
{
if (string.IsNullOrEmpty(templateId)) return UniTask.CompletedTask;
_records.Remove(templateId);
FlushRoot();
TryDeleteThumbnailFile(templateId);
return UniTask.CompletedTask;
}
public async UniTask WriteThumbnailAsync(string templateId, byte[] png)
{
if (string.IsNullOrEmpty(templateId) || png == null || png.Length == 0) return;
Directory.CreateDirectory(ThumbnailDirectory());
var path = ThumbnailPath(templateId);
var tmp = path + ".tmp";
await UniTask.RunOnThreadPool(() =>
{
File.WriteAllBytes(tmp, png);
if (File.Exists(path)) File.Delete(path);
File.Move(tmp, path);
});
}
public async UniTask<Texture2D> LoadThumbnailAsync(string templateId)
{
if (string.IsNullOrEmpty(templateId)) return null;
var path = ThumbnailPath(templateId);
if (!File.Exists(path)) return null;
byte[] bytes;
try
{
bytes = await UniTask.RunOnThreadPool(() => File.ReadAllBytes(path));
}
catch (Exception e)
{
Debug.LogWarning($"[Progression] Failed reading thumbnail '{templateId}': {e.Message}");
return null;
}
await UniTask.SwitchToMainThread();
var tex = new Texture2D(2, 2, TextureFormat.RGBA32, mipChain: false);
if (!tex.LoadImage(bytes))
{
UnityEngine.Object.Destroy(tex);
return null;
}
return tex;
}
private void FlushRoot()
{
var root = new ProgressionRootDto
{
records = _records.Values.ToList(),
};
var json = JsonUtility.ToJson(root);
ProtectedPlayerPrefs.SetString(PlayerPrefsKeys.Progression, json);
ProtectedPlayerPrefs.Save();
}
private static void TryDeleteThumbnailFile(string templateId)
{
try
{
var path = ThumbnailPath(templateId);
if (File.Exists(path)) File.Delete(path);
}
catch (Exception e)
{
Debug.LogWarning($"[Progression] Failed deleting thumbnail '{templateId}': {e.Message}");
}
}
private static string ThumbnailDirectory() =>
Path.Combine(Application.persistentDataPath, ThumbnailsFolder);
private static string ThumbnailPath(string templateId) =>
Path.Combine(ThumbnailDirectory(), SafeFileName(templateId) + ".png");
private static string SafeFileName(string templateId) =>
templateId.Replace('/', '_').Replace('\\', '_');
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: da8d941d4aa246b495da1fe0fe4a3c37
timeCreated: 1779883906

View File

@@ -0,0 +1,95 @@
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using Darkmatter.Core.Contracts.Features.Progression;
using Darkmatter.Core.Data.Dynamic.Features.Progression;
using Darkmatter.Core.Enums.Features.Progression;
using Darkmatter.Features.Progression.Systems;
using UnityEngine;
public class ProgressionSystem : IProgressionSystem
{
private readonly ProgressionRepository _repository;
private readonly Dictionary<string, DrawingProgress> _records = new();
private readonly HashSet<string> _completed = new();
private readonly SemaphoreSlim _writeLock = new(1, 1);
public IReadOnlyCollection<string> CompletedTemplateIds => _completed;
public ProgressionSystem(ProgressionRepository repository)
{
_repository = repository;
}
public async UniTask LoadAsync()
{
await _repository.LoadAsync();
_records.Clear();
_completed.Clear();
foreach (var p in _repository.AllProgress())
{
_records[p.templateId] = p;
if (p.hasBeenCompleted) _completed.Add(p.templateId);
}
}
public UniTask SaveAsync() => _repository.SaveAsync();
public void MarkCompleted(string templateId)
{
if (!_records.TryGetValue(templateId, out var p))
{
p = new DrawingProgress { templateId = templateId, phase = DrawingPhase.Coloring };
}
p.hasBeenCompleted = true;
p.completionCount += 1;
_records[templateId] = p;
_completed.Add(templateId);
}
public DrawingProgress? GetProgress(string templateId) =>
_records.TryGetValue(templateId, out var p) ? p : (DrawingProgress?)null;
public UniTask SaveProgressAsync(DrawingProgress progress) =>
SaveProgressAsync(progress, thumbnailPng: null);
public async UniTask SaveProgressAsync(DrawingProgress progress, byte[] thumbnailPng)
{
await _writeLock.WaitAsync();
try
{
_records[progress.templateId] = progress;
if (progress.hasBeenCompleted) _completed.Add(progress.templateId);
await _repository.SaveProgressAsync(progress);
if (thumbnailPng != null)
await _repository.WriteThumbnailAsync(progress.templateId, thumbnailPng);
}
finally
{
_writeLock.Release();
}
}
public async UniTask ClearProgressAsync(string templateId)
{
await _writeLock.WaitAsync();
try
{
_records.Remove(templateId);
_completed.Remove(templateId);
await _repository.DeleteProgressAsync(templateId);
}
finally
{
_writeLock.Release();
}
}
public bool IsCompleted(string templateId) => _completed.Contains(templateId);
public UniTask<Texture2D> GetCachedThumbnailAsync(string templateId) =>
_repository.LoadThumbnailAsync(templateId);
}

View File

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

View File

@@ -2,7 +2,7 @@ using VContainer;
namespace Darkmatter.Libs.Installers
{
public interface IServiceModule
public interface IModule
{
void Register(IContainerBuilder builder);
}

View File

@@ -7,45 +7,7 @@ namespace Darkmatter.Libs.PlayerPrefs
{
public static class PlayerPrefsKeys
{
/// <summary>Saves the achievements which the user has unlocked (String)</summary>
public const string Achievements = "Achievements";
public const string LocalLedger = "LocalLedger";
public static class Accounts
{
public const string SavedAuthRequest = "Accounts.SavedAuthRequest";
}
public static class Economy
{
/// <summary>Saves user's hard Currency (Int)</summary>
public const string Gold = "Economy.Gold";
/// <summary>Saves User's soft currency (Int)</summary>
public const string Rupees = "Economy.Rupees";
}
public static class Garage
{
/// <summary>Json of ids of the user owned buses (String)</summary>
public const string OwnedBusIds = "Garage.OwnedBusIds";
/// <summary>Id of the Bus that the user has selected (String)</summary>
public const string SelectedBusId = "Garage.SelectedBusId";
}
public static class Progression
{
/// <summary>Saves the user's Level (Int)</summary>
public const string Level = "Progression.Level";
/// <summary>Saves Xp of the user (Int)</summary>
public const string Xp = "Progression.Xp";
}
public static class SaveGame
{
/// <summary>Saves the users session 's json (String)</summary>
public const string Session = "SaveGame.Session";
public const string Vehicle = "SaveGame.Vehicle";
}
/// <summary>Stores User's Progression Data (String)</summary>
public const string Progression = "Progression";
}
}

View File

@@ -5,7 +5,7 @@ using VContainer.Unity;
namespace Darkmatter.Services.Analytics
{
public class AnalyticsServiceModule : MonoBehaviour, IServiceModule
public class AnalyticsModule : MonoBehaviour, IModule
{
public void Register(IContainerBuilder builder)
{

View File

@@ -7,7 +7,7 @@ using CameraType = Darkmatter.Core.Enums.Services.Camera.CameraType;
namespace Darkmatter.Services.Camera.Installers
{
public class CameraServiceModule : MonoBehaviour, IServiceModule
public class CameraModule : MonoBehaviour, IModule
{
[SerializeField] private UnityEngine.Camera mainCamera;
[SerializeField] private UnityEngine.Camera uiCamera;

View File

@@ -5,7 +5,7 @@ using VContainer;
namespace Darkmatter.Services.Capture.Installers
{
public class CaptureServiceModule : MonoBehaviour, IServiceModule
public class CaptureModule : MonoBehaviour, IModule
{
public void Register(IContainerBuilder builder)
{

View File

@@ -5,7 +5,7 @@ using VContainer;
namespace Darkmatter.Services.Gallery
{
public class GalleryServiceModule : MonoBehaviour,IServiceModule
public class GalleryModule : MonoBehaviour,IModule
{
public void Register(IContainerBuilder builder)
{

View File

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

View File

@@ -0,0 +1,15 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
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: f8ac5d9908c8049e1a3c8b8ac108b5f5, type: 3}
m_Name: PlayerPrefsKeyRegistry
m_EditorClassIdentifier: Libs.PlayerPrefs::Darkmatter.Libs.PlayerPrefs.PlayerPrefsKeyRegistry
_entries: []

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 43227e22a3e2f44c5a6dc92729ba32e0
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -531,6 +531,7 @@ Transform:
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 274737044}
- {fileID: 1709100712}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &329578013
@@ -552,6 +553,8 @@ MonoBehaviour:
serviceModules:
- {fileID: 292698385}
- {fileID: 137105225}
- {fileID: 1043308347}
- {fileID: 610419920}
--- !u!1 &519420028
GameObject:
m_ObjectHideFlags: 0
@@ -690,6 +693,94 @@ Transform:
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &610419918
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 610419919}
- component: {fileID: 610419920}
m_Layer: 0
m_Name: DrawingTemplateFeatureModule
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &610419919
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 610419918}
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: 1709100712}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &610419920
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 610419918}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: aa578cd62ad074dbf91b5228c3ac667e, type: 3}
m_Name:
m_EditorClassIdentifier: Features.DrawingTemplates::Darkmatter.Features.DrawingTemplates.DrawingTemplateFeatureModule
--- !u!1 &1043308345
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1043308346}
- component: {fileID: 1043308347}
m_Layer: 0
m_Name: ProgressionFeatureModule
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1043308346
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1043308345}
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: 1709100712}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1043308347
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1043308345}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d0af7651133b54f398413a7c19dfc9bb, type: 3}
m_Name:
m_EditorClassIdentifier: Features.Progression::Darkmatter.Features.Progression.Installers.ProgressionFeatureModule
--- !u!1 &1050564724
GameObject:
m_ObjectHideFlags: 0
@@ -766,6 +857,39 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: f03c84255756e497f96c3baa7f6abe16, type: 3}
m_Name:
m_EditorClassIdentifier: Services.Gallery::Darkmatter.Services.Gallery.GalleryServiceModule
--- !u!1 &1709100711
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1709100712}
m_Layer: 0
m_Name: FeatureModules
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1709100712
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1709100711}
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:
- {fileID: 1043308346}
- {fileID: 610419919}
m_Father: {fileID: 329578012}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1798580247
GameObject:
m_ObjectHideFlags: 0

View File

@@ -248,7 +248,6 @@ MonoBehaviour:
autoRun: 1
autoInjectGameObjects: []
serviceModules:
- {fileID: 0}
- {fileID: 1551649429}
--- !u!1 &1551649427
GameObject:
@@ -261,7 +260,7 @@ GameObject:
- component: {fileID: 1551649428}
- component: {fileID: 1551649429}
m_Layer: 0
m_Name: HistoryServiceModule
m_Name: HistoryFeatureModule
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@@ -294,6 +293,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 45c42e41a28d34b01a364a3c2631ba73, type: 3}
m_Name:
m_EditorClassIdentifier: Features.History::Darkmatter.Features.History.HistoryServiceModule
historyButtonsView: {fileID: 0}
--- !u!1 &1965442262
GameObject:
m_ObjectHideFlags: 0
@@ -304,7 +304,7 @@ GameObject:
m_Component:
- component: {fileID: 1965442263}
m_Layer: 0
m_Name: ServiceModules
m_Name: FeatureModules
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0

18
Assets/NuGet.config Normal file
View File

@@ -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>

28
Assets/NuGet.config.meta Normal file
View File

@@ -0,0 +1,28 @@
fileFormatVersion: 2
guid: 93dee7accdd284d37b22dd1818db3a4f
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:

8
Assets/Packages.meta Normal file
View File

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

View File

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

Binary file not shown.

View File

@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2007 James Newton-King
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

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

Some files were not shown because too many files have changed in this diff Show More