Merge pull request #23 from Cysharp/hadashiA/nuget-for-unity
Remove the unity project and use NuGetForUnity
This commit is contained in:
commit
43ee6ecb9d
33
.github/workflows/build-debug.yml
vendored
33
.github/workflows/build-debug.yml
vendored
@ -17,36 +17,3 @@ jobs:
|
|||||||
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
|
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
|
||||||
- run: dotnet build ObservableCollection.WithoutSandbox.slnf -c Debug
|
- run: dotnet build ObservableCollection.WithoutSandbox.slnf -c Debug
|
||||||
- run: dotnet test ObservableCollection.WithoutSandbox.slnf -c Debug --no-build
|
- run: dotnet test ObservableCollection.WithoutSandbox.slnf -c Debug --no-build
|
||||||
|
|
||||||
build-unity:
|
|
||||||
if: "((github.event_name == 'push' && github.repository_owner == 'Cysharp') || startsWith(github.event.pull_request.head.label, 'Cysharp:'))"
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
unity: ["2019.4.25f1"]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 15
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
# Execute scripts: Export Package
|
|
||||||
# /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
|
|
||||||
- name: Build Unity (.unitypacakge)
|
|
||||||
uses: Cysharp/Actions/.github/actions/unity-builder@main
|
|
||||||
env:
|
|
||||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
|
||||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
|
||||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
|
||||||
with:
|
|
||||||
projectPath: src/ObservableCollections.Unity
|
|
||||||
unityVersion: ${{ matrix.unity }}
|
|
||||||
targetPlatform: StandaloneLinux64
|
|
||||||
buildMethod: PackageExporter.Export
|
|
||||||
|
|
||||||
- uses: Cysharp/Actions/.github/actions/check-metas@main # check meta files
|
|
||||||
with:
|
|
||||||
directory: src/ObservableCollections.Unity
|
|
||||||
|
|
||||||
# Store artifacts.
|
|
||||||
- uses: actions/upload-artifact@v2
|
|
||||||
with:
|
|
||||||
name: ObservableCollections.unitypackage-${{ matrix.unity }}.zip
|
|
||||||
path: ./src/ObservableCollections.Unity/*.unitypackage
|
|
||||||
|
61
.github/workflows/build-release.yml
vendored
61
.github/workflows/build-release.yml
vendored
@ -13,22 +13,11 @@ on:
|
|||||||
type: boolean
|
type: boolean
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update-packagejson:
|
|
||||||
uses: Cysharp/Actions/.github/workflows/update-packagejson.yaml@main
|
|
||||||
with:
|
|
||||||
file-path: ./src/ObservableCollections.Unity/Assets/Plugins/ObservableCollections/package.json
|
|
||||||
tag: ${{ inputs.tag }}
|
|
||||||
dry-run: ${{ inputs.dry-run }}
|
|
||||||
|
|
||||||
build-dotnet:
|
build-dotnet:
|
||||||
needs: [update-packagejson]
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
steps:
|
steps:
|
||||||
- run: echo ${{ needs.update-packagejson.outputs.sha }}
|
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
|
||||||
ref: ${{ needs.update-packagejson.outputs.sha }}
|
|
||||||
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
|
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
|
||||||
# build and pack
|
# build and pack
|
||||||
- run: dotnet build ObservableCollection.WithoutSandbox.slnf -c Release -p:Version=${{ inputs.tag }}
|
- run: dotnet build ObservableCollection.WithoutSandbox.slnf -c Release -p:Version=${{ inputs.tag }}
|
||||||
@ -40,58 +29,14 @@ jobs:
|
|||||||
name: nuget
|
name: nuget
|
||||||
path: ./publish/
|
path: ./publish/
|
||||||
|
|
||||||
build-unity:
|
|
||||||
needs: [update-packagejson]
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
unity: ["2019.4.25f1"]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 15
|
|
||||||
steps:
|
|
||||||
- run: echo ${{ needs.update-packagejson.outputs.sha }}
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
ref: ${{ needs.update-packagejson.outputs.sha }}
|
|
||||||
# Execute scripts: Export Package
|
|
||||||
# /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
|
|
||||||
- name: Build Unity (.unitypacakge)
|
|
||||||
uses: Cysharp/Actions/.github/actions/unity-builder@main
|
|
||||||
env:
|
|
||||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
|
||||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
|
||||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
|
||||||
with:
|
|
||||||
projectPath: src/ObservableCollections.Unity
|
|
||||||
unityVersion: ${{ matrix.unity }}
|
|
||||||
targetPlatform: StandaloneLinux64
|
|
||||||
buildMethod: PackageExporter.Export
|
|
||||||
|
|
||||||
- uses: Cysharp/Actions/.github/actions/check-metas@main # check meta files
|
|
||||||
with:
|
|
||||||
directory: src/ObservableCollections.Unity
|
|
||||||
|
|
||||||
# Store artifacts.
|
|
||||||
- uses: actions/upload-artifact@v2
|
|
||||||
with:
|
|
||||||
name: ObservableCollections.${{ inputs.tag }}.unitypackage
|
|
||||||
path: ./src/ObservableCollections.Unity/ObservableCollections.${{ inputs.tag }}.unitypackage
|
|
||||||
|
|
||||||
# release
|
# release
|
||||||
create-release:
|
create-release:
|
||||||
needs: [update-packagejson, build-unity]
|
needs: [build-dotnet]
|
||||||
uses: Cysharp/Actions/.github/workflows/create-release.yaml@main
|
uses: Cysharp/Actions/.github/workflows/create-release.yaml@main
|
||||||
with:
|
with:
|
||||||
commit-id: ${{ needs.update-packagejson.outputs.sha }}
|
commit-id: ${{ github.sha }}
|
||||||
dry-run: ${{ inputs.dry-run }}
|
dry-run: ${{ inputs.dry-run }}
|
||||||
tag: ${{ inputs.tag }}
|
tag: ${{ inputs.tag }}
|
||||||
nuget-push: true
|
nuget-push: true
|
||||||
release-upload: true
|
release-upload: false
|
||||||
release-asset-path: ./ObservableCollections.${{ inputs.tag }}.unitypackage/ObservableCollections.${{ inputs.tag }}.unitypackage
|
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
cleanup:
|
|
||||||
if: ${{ needs.update-packagejson.outputs.is-branch-created == 'true' }}
|
|
||||||
needs: [update-packagejson, build-unity]
|
|
||||||
uses: Cysharp/Actions/.github/workflows/clean-packagejson-branch.yaml@main
|
|
||||||
with:
|
|
||||||
branch: ${{ needs.update-packagejson.outputs.branch-name }}
|
|
||||||
|
@ -203,6 +203,10 @@ protected override void OnClosed(EventArgs e)
|
|||||||
|
|
||||||
Unity
|
Unity
|
||||||
---
|
---
|
||||||
|
|
||||||
|
In Unity projects, you can installing `ObservableCollections` with [NugetForUnity](https://github.com/GlitchEnzo/NuGetForUnity).
|
||||||
|
|
||||||
|
|
||||||
In Unity, ObservableCollections and Views are useful as CollectionManagers, since they need to convert T to Prefab for display.
|
In Unity, ObservableCollections and Views are useful as CollectionManagers, since they need to convert T to Prefab for display.
|
||||||
|
|
||||||
Since we need to have side effects on GameObjects, we will prepare a filter and apply an action on changes.
|
Since we need to have side effects on GameObjects, we will prepare a filter and apply an action on changes.
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 23bde05b5e9d4d049a38c4edf79f9ac6
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,78 +0,0 @@
|
|||||||
#if UNITY_EDITOR
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using UnityEditor;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public static class PackageExporter
|
|
||||||
{
|
|
||||||
[MenuItem("Tools/Export Unitypackage")]
|
|
||||||
public static void Export()
|
|
||||||
{
|
|
||||||
var roots = new[] { "Plugins/ObservableCollections" };
|
|
||||||
|
|
||||||
foreach (var root in roots)
|
|
||||||
{
|
|
||||||
var version = GetVersion(root);
|
|
||||||
var fn = root.Split('/').Last();
|
|
||||||
|
|
||||||
var fileName = string.IsNullOrEmpty(version) ? $"{fn}.unitypackage" : $"{fn}.{version}.unitypackage";
|
|
||||||
var exportPath = "./" + fileName;
|
|
||||||
|
|
||||||
var path = Path.Combine(Application.dataPath, root);
|
|
||||||
var assets = Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)
|
|
||||||
.Where(x => Path.GetExtension(x) == ".cs" || Path.GetExtension(x) == ".asmdef" || Path.GetExtension(x) == ".json" || Path.GetExtension(x) == ".meta")
|
|
||||||
.Select(x => "Assets" + x.Replace(Application.dataPath, "").Replace(@"\", "/"))
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
UnityEngine.Debug.Log("Export below files" + Environment.NewLine + string.Join(Environment.NewLine, assets));
|
|
||||||
|
|
||||||
AssetDatabase.ExportPackage(
|
|
||||||
assets,
|
|
||||||
exportPath,
|
|
||||||
ExportPackageOptions.Default);
|
|
||||||
|
|
||||||
UnityEngine.Debug.Log("Export complete: " + Path.GetFullPath(exportPath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static string GetVersion(string root)
|
|
||||||
{
|
|
||||||
var version = Environment.GetEnvironmentVariable("UNITY_PACKAGE_VERSION");
|
|
||||||
var versionJson = Path.Combine(Application.dataPath, root, "package.json");
|
|
||||||
|
|
||||||
if (File.Exists(versionJson))
|
|
||||||
{
|
|
||||||
var v = JsonUtility.FromJson<Version>(File.ReadAllText(versionJson));
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(version))
|
|
||||||
{
|
|
||||||
if (v.version != version)
|
|
||||||
{
|
|
||||||
var msg = $"package.json and env version are mismatched. UNITY_PACKAGE_VERSION:{version}, package.json:{v.version}";
|
|
||||||
|
|
||||||
if (Application.isBatchMode)
|
|
||||||
{
|
|
||||||
Console.WriteLine(msg);
|
|
||||||
Application.Quit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Exception("package.json and env version are mismatched.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
version = v.version;
|
|
||||||
}
|
|
||||||
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Version
|
|
||||||
{
|
|
||||||
public string version;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 34885e00b06e4c847b8e2958ebb2d26b
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 58b896faeb4c95c4a939b19f8dbf74ab
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 791bdc9996d0f5c42bea2aa68c95dced
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: a2ca402f41ce60d4c95ee34b6715ee8a
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,59 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
using ObservableCollections.Internal;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
public sealed class FreezedDictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue>, IFreezedCollection<KeyValuePair<TKey, TValue>>
|
|
||||||
|
|
||||||
{
|
|
||||||
readonly IReadOnlyDictionary<TKey, TValue> dictionary;
|
|
||||||
|
|
||||||
public FreezedDictionary(IReadOnlyDictionary<TKey, TValue> dictionary)
|
|
||||||
{
|
|
||||||
this.dictionary = dictionary;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TValue this[TKey key] => dictionary[key];
|
|
||||||
|
|
||||||
public IEnumerable<TKey> Keys => dictionary.Keys;
|
|
||||||
|
|
||||||
public IEnumerable<TValue> Values => dictionary.Values;
|
|
||||||
|
|
||||||
public int Count => dictionary.Count;
|
|
||||||
|
|
||||||
public bool ContainsKey(TKey key)
|
|
||||||
{
|
|
||||||
return dictionary.ContainsKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
|
||||||
{
|
|
||||||
return dictionary.GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
|
|
||||||
{
|
|
||||||
return dictionary.TryGetValue(key, out value);
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return ((IEnumerable)dictionary).GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ISynchronizedView<KeyValuePair<TKey, TValue>, TView> CreateView<TView>(Func<KeyValuePair<TKey, TValue>, TView> transform, bool reverse = false)
|
|
||||||
{
|
|
||||||
return new FreezedView<KeyValuePair<TKey, TValue>, TView>(dictionary, transform, reverse);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ISortableSynchronizedView<KeyValuePair<TKey, TValue>, TView> CreateSortableView<TView>(Func<KeyValuePair<TKey, TValue>, TView> transform)
|
|
||||||
{
|
|
||||||
return new FreezedSortableView<KeyValuePair<TKey, TValue>, TView>(dictionary, transform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 1470201cf9f7db249b7f441e515b77b0
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,61 +0,0 @@
|
|||||||
using ObservableCollections.Internal;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
public sealed class FreezedList<T> : IReadOnlyList<T>, IFreezedCollection<T>
|
|
||||||
{
|
|
||||||
readonly IReadOnlyList<T> list;
|
|
||||||
|
|
||||||
public T this[int index]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return list[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return list.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsReadOnly => true;
|
|
||||||
|
|
||||||
public FreezedList(IReadOnlyList<T> list)
|
|
||||||
{
|
|
||||||
this.list = list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false)
|
|
||||||
{
|
|
||||||
return new FreezedView<T, TView>(list, transform, reverse);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ISortableSynchronizedView<T, TView> CreateSortableView<TView>(Func<T, TView> transform)
|
|
||||||
{
|
|
||||||
return new FreezedSortableView<T, TView>(list, transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains(T item)
|
|
||||||
{
|
|
||||||
return list.Contains(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator()
|
|
||||||
{
|
|
||||||
return list.GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 3207eb016a325514b8f137b4cf17df40
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,118 +0,0 @@
|
|||||||
using ObservableCollections.Internal;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.ComponentModel;
|
|
||||||
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
public delegate void NotifyCollectionChangedEventHandler<T>(in NotifyCollectionChangedEventArgs<T> e);
|
|
||||||
|
|
||||||
public interface IObservableCollection<T> : IReadOnlyCollection<T>
|
|
||||||
{
|
|
||||||
event NotifyCollectionChangedEventHandler<T> CollectionChanged;
|
|
||||||
object SyncRoot { get; }
|
|
||||||
ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IFreezedCollection<T>
|
|
||||||
{
|
|
||||||
ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false);
|
|
||||||
ISortableSynchronizedView<T, TView> CreateSortableView<TView>(Func<T, TView> transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface ISynchronizedView<T, TView> : IReadOnlyCollection<(T Value, TView View)>, IDisposable
|
|
||||||
{
|
|
||||||
object SyncRoot { get; }
|
|
||||||
|
|
||||||
event NotifyCollectionChangedEventHandler<T> RoutingCollectionChanged;
|
|
||||||
event Action<NotifyCollectionChangedAction> CollectionStateChanged;
|
|
||||||
|
|
||||||
void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForInitialElements = false);
|
|
||||||
void ResetFilter(Action<T, TView> resetAction);
|
|
||||||
INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface ISortableSynchronizedView<T, TView> : ISynchronizedView<T, TView>
|
|
||||||
{
|
|
||||||
void Sort(IComparer<T> comparer);
|
|
||||||
void Sort(IComparer<TView> viewComparer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// will be implemented in the future?
|
|
||||||
//public interface IGroupedSynchoronizedView<T, TKey, TView> : ILookup<TKey, (T, TView)>, ISynchronizedView<T, TView>
|
|
||||||
//{
|
|
||||||
//}
|
|
||||||
|
|
||||||
public interface INotifyCollectionChangedSynchronizedView<T, TView> : ISynchronizedView<T, TView>, INotifyCollectionChanged, INotifyPropertyChanged
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ObservableCollectionsExtensions
|
|
||||||
{
|
|
||||||
public static ISynchronizedView<T, TView> CreateSortedView<T, TKey, TView>(this IObservableCollection<T> source, Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<T> comparer)
|
|
||||||
|
|
||||||
{
|
|
||||||
return new SortedView<T, TKey, TView>(source, identitySelector, transform, comparer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ISynchronizedView<T, TView> CreateSortedView<T, TKey, TView>(this IObservableCollection<T> source, Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<TView> viewComparer)
|
|
||||||
|
|
||||||
{
|
|
||||||
return new SortedViewViewComparer<T, TKey, TView>(source, identitySelector, transform, viewComparer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ISynchronizedView<T, TView> CreateSortedView<T, TKey, TView, TCompare>(this IObservableCollection<T> source, Func<T, TKey> identitySelector, Func<T, TView> transform, Func<T, TCompare> compareSelector, bool ascending = true)
|
|
||||||
|
|
||||||
{
|
|
||||||
return source.CreateSortedView(identitySelector, transform, new AnonymousComparer<T, TCompare>(compareSelector, ascending));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ISortableSynchronizedView<T, TView> CreateSortableView<T, TView>(this IFreezedCollection<T> source, Func<T, TView> transform, IComparer<T> initialSort)
|
|
||||||
{
|
|
||||||
var view = source.CreateSortableView(transform);
|
|
||||||
view.Sort(initialSort);
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ISortableSynchronizedView<T, TView> CreateSortableView<T, TView>(this IFreezedCollection<T> source, Func<T, TView> transform, IComparer<TView> initialViewSort)
|
|
||||||
{
|
|
||||||
var view = source.CreateSortableView(transform);
|
|
||||||
view.Sort(initialViewSort);
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ISortableSynchronizedView<T, TView> CreateSortableView<T, TView, TCompare>(this IFreezedCollection<T> source, Func<T, TView> transform, Func<T, TCompare> initialCompareSelector, bool ascending = true)
|
|
||||||
{
|
|
||||||
var view = source.CreateSortableView(transform);
|
|
||||||
view.Sort(initialCompareSelector, ascending);
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Sort<T, TView, TCompare>(this ISortableSynchronizedView<T, TView> source, Func<T, TCompare> compareSelector, bool ascending = true)
|
|
||||||
{
|
|
||||||
source.Sort(new AnonymousComparer<T, TCompare>(compareSelector, ascending));
|
|
||||||
}
|
|
||||||
|
|
||||||
class AnonymousComparer<T, TCompare> : IComparer<T>
|
|
||||||
{
|
|
||||||
readonly Func<T, TCompare> selector;
|
|
||||||
readonly int f;
|
|
||||||
|
|
||||||
public AnonymousComparer(Func<T, TCompare> selector, bool ascending)
|
|
||||||
{
|
|
||||||
this.selector = selector;
|
|
||||||
this.f = ascending ? 1 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Compare(T x, T y)
|
|
||||||
{
|
|
||||||
if (x == null && y == null) return 0;
|
|
||||||
if (x == null) return 1 * f;
|
|
||||||
if (y == null) return -1 * f;
|
|
||||||
|
|
||||||
return Comparer<TCompare>.Default.Compare(selector(x), selector(y)) * f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: bdb4cc0f6a8b396418c8250eeaf2d2c8
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,121 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
public interface ISynchronizedViewFilter<T, TView>
|
|
||||||
{
|
|
||||||
bool IsMatch(T value, TView view);
|
|
||||||
void WhenTrue(T value, TView view);
|
|
||||||
void WhenFalse(T value, TView view);
|
|
||||||
void OnCollectionChanged(ChangedKind changedKind, T value, TView view, in NotifyCollectionChangedEventArgs<T> eventArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ChangedKind
|
|
||||||
{
|
|
||||||
Add, Remove, Move
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SynchronizedViewFilter<T, TView> : ISynchronizedViewFilter<T, TView>
|
|
||||||
{
|
|
||||||
public static readonly ISynchronizedViewFilter<T, TView> Null = new NullViewFilter();
|
|
||||||
|
|
||||||
readonly Func<T, TView, bool> isMatch;
|
|
||||||
readonly Action<T, TView> whenTrue;
|
|
||||||
readonly Action<T, TView> whenFalse;
|
|
||||||
readonly Action<ChangedKind, T, TView> onCollectionChanged;
|
|
||||||
|
|
||||||
public SynchronizedViewFilter(Func<T, TView, bool> isMatch, Action<T, TView> whenTrue, Action<T, TView> whenFalse, Action<ChangedKind, T, TView> onCollectionChanged)
|
|
||||||
{
|
|
||||||
this.isMatch = isMatch;
|
|
||||||
this.whenTrue = whenTrue;
|
|
||||||
this.whenFalse = whenFalse;
|
|
||||||
this.onCollectionChanged = onCollectionChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsMatch(T value, TView view) => isMatch(value, view);
|
|
||||||
public void WhenFalse(T value, TView view) => whenFalse?.Invoke(value, view);
|
|
||||||
public void WhenTrue(T value, TView view) => whenTrue?.Invoke(value, view);
|
|
||||||
public void OnCollectionChanged(ChangedKind changedKind, T value, TView view, in NotifyCollectionChangedEventArgs<T> eventArgs) => onCollectionChanged?.Invoke(changedKind, value, view);
|
|
||||||
|
|
||||||
class NullViewFilter : ISynchronizedViewFilter<T, TView>
|
|
||||||
{
|
|
||||||
public bool IsMatch(T value, TView view) => true;
|
|
||||||
public void WhenFalse(T value, TView view) { }
|
|
||||||
public void WhenTrue(T value, TView view) { }
|
|
||||||
public void OnCollectionChanged(ChangedKind changedKind, T value, TView view, in NotifyCollectionChangedEventArgs<T> eventArgs) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class SynchronizedViewFilterExtensions
|
|
||||||
{
|
|
||||||
public static void AttachFilter<T, TView>(this ISynchronizedView<T, TView> source, Func<T, TView, bool> filter)
|
|
||||||
{
|
|
||||||
source.AttachFilter(new SynchronizedViewFilter<T, TView>(filter, null, null, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void AttachFilter<T, TView>(this ISynchronizedView<T, TView> source, Func<T, TView, bool> isMatch, Action<T, TView> whenTrue, Action<T, TView> whenFalse)
|
|
||||||
{
|
|
||||||
source.AttachFilter(new SynchronizedViewFilter<T, TView>(isMatch, whenTrue, whenFalse, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void AttachFilter<T, TView>(this ISynchronizedView<T, TView> source, Func<T, TView, bool> isMatch, Action<T, TView> whenTrue, Action<T, TView> whenFalse, Action<ChangedKind, T, TView> onCollectionChanged)
|
|
||||||
{
|
|
||||||
source.AttachFilter(new SynchronizedViewFilter<T, TView>(isMatch, whenTrue, whenFalse, onCollectionChanged));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsNullFilter<T, TView>(this ISynchronizedViewFilter<T, TView> filter)
|
|
||||||
{
|
|
||||||
return filter == SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void InvokeOnAdd<T, TView>(this ISynchronizedViewFilter<T, TView> filter, (T value, TView view) value, in NotifyCollectionChangedEventArgs<T> eventArgs)
|
|
||||||
{
|
|
||||||
InvokeOnAdd(filter, value.value, value.view, eventArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void InvokeOnAdd<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view, in NotifyCollectionChangedEventArgs<T> eventArgs)
|
|
||||||
{
|
|
||||||
if (filter.IsMatch(value, view))
|
|
||||||
{
|
|
||||||
filter.WhenTrue(value, view);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
filter.WhenFalse(value, view);
|
|
||||||
}
|
|
||||||
filter.OnCollectionChanged(ChangedKind.Add, value, view, eventArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void InvokeOnRemove<T, TView>(this ISynchronizedViewFilter<T, TView> filter, (T value, TView view) value, in NotifyCollectionChangedEventArgs<T> eventArgs)
|
|
||||||
{
|
|
||||||
InvokeOnRemove(filter, value.value, value.view, eventArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void InvokeOnRemove<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view, in NotifyCollectionChangedEventArgs<T> eventArgs)
|
|
||||||
{
|
|
||||||
filter.OnCollectionChanged(ChangedKind.Remove, value, view, eventArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void InvokeOnMove<T, TView>(this ISynchronizedViewFilter<T, TView> filter, (T value, TView view) value, in NotifyCollectionChangedEventArgs<T> eventArgs)
|
|
||||||
{
|
|
||||||
InvokeOnMove(filter, value.value, value.view, eventArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void InvokeOnMove<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view, in NotifyCollectionChangedEventArgs<T> eventArgs)
|
|
||||||
{
|
|
||||||
filter.OnCollectionChanged(ChangedKind.Move, value, view, eventArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void InvokeOnAttach<T, TView>(this ISynchronizedViewFilter<T, TView> filter, T value, TView view)
|
|
||||||
{
|
|
||||||
if (filter.IsMatch(value, view))
|
|
||||||
{
|
|
||||||
filter.WhenTrue(value, view);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
filter.WhenFalse(value, view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 0ffdcef914adf8848a485ac600cc41c4
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 0b3e01975c6d488409ce0ac753c89870
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,132 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Buffers;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace ObservableCollections.Internal
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// ReadOnly cloned collection.
|
|
||||||
/// </summary>
|
|
||||||
internal struct CloneCollection<T> : IDisposable
|
|
||||||
{
|
|
||||||
T[] array;
|
|
||||||
int length;
|
|
||||||
|
|
||||||
public ReadOnlySpan<T> Span => array.AsSpan(0, length);
|
|
||||||
|
|
||||||
public IEnumerable<T> AsEnumerable() => new EnumerableCollection(array, length);
|
|
||||||
|
|
||||||
public CloneCollection(T item)
|
|
||||||
{
|
|
||||||
this.array = ArrayPool<T>.Shared.Rent(1);
|
|
||||||
this.length = 1;
|
|
||||||
this.array[0] = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CloneCollection(IEnumerable<T> source)
|
|
||||||
{
|
|
||||||
if (source.TryGetNonEnumeratedCount(out var count))
|
|
||||||
{
|
|
||||||
var array = ArrayPool<T>.Shared.Rent(count);
|
|
||||||
|
|
||||||
if (source is ICollection<T> c)
|
|
||||||
{
|
|
||||||
c.CopyTo(array, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var i = 0;
|
|
||||||
foreach (var item in source)
|
|
||||||
{
|
|
||||||
array[i++] = item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.array = array;
|
|
||||||
this.length = count;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var array = ArrayPool<T>.Shared.Rent(16);
|
|
||||||
|
|
||||||
var i = 0;
|
|
||||||
foreach (var item in source)
|
|
||||||
{
|
|
||||||
TryEnsureCapacity(ref array, i);
|
|
||||||
array[i++] = item;
|
|
||||||
}
|
|
||||||
this.array = array;
|
|
||||||
this.length = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public CloneCollection(ReadOnlySpan<T> source)
|
|
||||||
{
|
|
||||||
var array = ArrayPool<T>.Shared.Rent(source.Length);
|
|
||||||
source.CopyTo(array);
|
|
||||||
this.array = array;
|
|
||||||
this.length = source.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void TryEnsureCapacity(ref T[] array, int index)
|
|
||||||
{
|
|
||||||
if (array.Length == index)
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(array, RuntimeHelpersEx.IsReferenceOrContainsReferences<T>());
|
|
||||||
array = ArrayPool<T>.Shared.Rent(index * 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (array != null)
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(array, RuntimeHelpersEx.IsReferenceOrContainsReferences<T>());
|
|
||||||
array = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimize to use Count and CopyTo
|
|
||||||
class EnumerableCollection : ICollection<T>
|
|
||||||
{
|
|
||||||
readonly T[] array;
|
|
||||||
readonly int count;
|
|
||||||
|
|
||||||
public EnumerableCollection(T[] array, int count)
|
|
||||||
{
|
|
||||||
if (array == null)
|
|
||||||
{
|
|
||||||
this.array = Array.Empty<T>();
|
|
||||||
this.count = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.array = array;
|
|
||||||
this.count = count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count => count;
|
|
||||||
|
|
||||||
public bool IsReadOnly => true;
|
|
||||||
|
|
||||||
public void Add(T item) => throw new NotSupportedException();
|
|
||||||
public void Clear() => throw new NotSupportedException();
|
|
||||||
public bool Contains(T item) => throw new NotSupportedException();
|
|
||||||
public void CopyTo(T[] dest, int destIndex) => Array.Copy(array, 0, dest, destIndex, count);
|
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
yield return array[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Remove(T item) => throw new NotSupportedException();
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 7b9643f0fa1bf7447961693f16cb557b
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,244 +0,0 @@
|
|||||||
#pragma warning disable CS0067
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace ObservableCollections.Internal
|
|
||||||
{
|
|
||||||
internal sealed class FreezedView<T, TView> : ISynchronizedView<T, TView>
|
|
||||||
{
|
|
||||||
readonly bool reverse;
|
|
||||||
readonly List<(T, TView)> list;
|
|
||||||
|
|
||||||
ISynchronizedViewFilter<T, TView> filter;
|
|
||||||
|
|
||||||
public event Action<NotifyCollectionChangedAction> CollectionStateChanged;
|
|
||||||
public event NotifyCollectionChangedEventHandler<T> RoutingCollectionChanged;
|
|
||||||
|
|
||||||
public object SyncRoot { get; } = new object();
|
|
||||||
|
|
||||||
public FreezedView(IEnumerable<T> source, Func<T, TView> selector, bool reverse)
|
|
||||||
{
|
|
||||||
this.reverse = reverse;
|
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
this.list = source.Select(x => (x, selector(x))).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return list.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = filter;
|
|
||||||
for (var i = 0; i < list.Count; i++)
|
|
||||||
{
|
|
||||||
var (value, view) = list[i];
|
|
||||||
if (invokeAddEventForCurrentElements)
|
|
||||||
{
|
|
||||||
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, i));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
filter.InvokeOnAttach(value, view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResetFilter(Action<T, TView> resetAction)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
if (resetAction != null)
|
|
||||||
{
|
|
||||||
foreach (var (item, view) in list)
|
|
||||||
{
|
|
||||||
resetAction(item, view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<(T, TView)> GetEnumerator()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (!reverse)
|
|
||||||
{
|
|
||||||
foreach (var item in list)
|
|
||||||
{
|
|
||||||
if (filter.IsMatch(item.Item1, item.Item2))
|
|
||||||
{
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var item in list.AsEnumerable().Reverse())
|
|
||||||
{
|
|
||||||
if (filter.IsMatch(item.Item1, item.Item2))
|
|
||||||
{
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedSynchronizedView<T, TView>(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal sealed class FreezedSortableView<T, TView> : ISortableSynchronizedView<T, TView>
|
|
||||||
{
|
|
||||||
readonly (T, TView)[] array;
|
|
||||||
|
|
||||||
ISynchronizedViewFilter<T, TView> filter;
|
|
||||||
|
|
||||||
public event Action<NotifyCollectionChangedAction> CollectionStateChanged;
|
|
||||||
public event NotifyCollectionChangedEventHandler<T> RoutingCollectionChanged;
|
|
||||||
|
|
||||||
public object SyncRoot { get; } = new object();
|
|
||||||
|
|
||||||
public FreezedSortableView(IEnumerable<T> source, Func<T, TView> selector)
|
|
||||||
{
|
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
this.array = source.Select(x => (x, selector(x))).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return array.Length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = filter;
|
|
||||||
for (var i = 0; i < array.Length; i++)
|
|
||||||
{
|
|
||||||
var (value, view) = array[i];
|
|
||||||
if (invokeAddEventForCurrentElements)
|
|
||||||
{
|
|
||||||
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, i));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
filter.InvokeOnAttach(value, view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResetFilter(Action<T, TView> resetAction)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
if (resetAction != null)
|
|
||||||
{
|
|
||||||
foreach (var (item, view) in array)
|
|
||||||
{
|
|
||||||
resetAction(item, view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<(T, TView)> GetEnumerator()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
foreach (var item in array)
|
|
||||||
{
|
|
||||||
if (filter.IsMatch(item.Item1, item.Item2))
|
|
||||||
{
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Sort(IComparer<T> comparer)
|
|
||||||
{
|
|
||||||
Array.Sort(array, new TComparer(comparer));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Sort(IComparer<TView> viewComparer)
|
|
||||||
{
|
|
||||||
Array.Sort(array, new TViewComparer(viewComparer));
|
|
||||||
}
|
|
||||||
|
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedSynchronizedView<T, TView>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
class TComparer : IComparer<(T, TView)>
|
|
||||||
{
|
|
||||||
readonly IComparer<T> comparer;
|
|
||||||
|
|
||||||
public TComparer(IComparer<T> comparer)
|
|
||||||
{
|
|
||||||
this.comparer = comparer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Compare((T, TView) x, (T, TView) y)
|
|
||||||
{
|
|
||||||
return comparer.Compare(x.Item1, y.Item1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TViewComparer : IComparer<(T, TView)>
|
|
||||||
{
|
|
||||||
readonly IComparer<TView> comparer;
|
|
||||||
|
|
||||||
public TViewComparer(IComparer<TView> comparer)
|
|
||||||
{
|
|
||||||
this.comparer = comparer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Compare((T, TView) x, (T, TView) y)
|
|
||||||
{
|
|
||||||
return comparer.Compare(x.Item2, y.Item2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: a768cdaf951b40345b6d5b21ade3e282
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,70 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.ComponentModel;
|
|
||||||
|
|
||||||
namespace ObservableCollections.Internal
|
|
||||||
{
|
|
||||||
internal class NotifyCollectionChangedSynchronizedView<T, TView> : INotifyCollectionChangedSynchronizedView<T, TView>
|
|
||||||
{
|
|
||||||
readonly ISynchronizedView<T, TView> parent;
|
|
||||||
static readonly PropertyChangedEventArgs CountPropertyChangedEventArgs = new PropertyChangedEventArgs("Count");
|
|
||||||
|
|
||||||
public NotifyCollectionChangedSynchronizedView(ISynchronizedView<T, TView> parent)
|
|
||||||
{
|
|
||||||
this.parent = parent;
|
|
||||||
this.parent.RoutingCollectionChanged += Parent_RoutingCollectionChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Parent_RoutingCollectionChanged(in NotifyCollectionChangedEventArgs<T> e)
|
|
||||||
{
|
|
||||||
CollectionChanged?.Invoke(this, e.ToStandardEventArgs());
|
|
||||||
|
|
||||||
switch (e.Action)
|
|
||||||
{
|
|
||||||
// add, remove, reset will change the count.
|
|
||||||
case NotifyCollectionChangedAction.Add:
|
|
||||||
case NotifyCollectionChangedAction.Remove:
|
|
||||||
case NotifyCollectionChangedAction.Reset:
|
|
||||||
PropertyChanged?.Invoke(this, CountPropertyChangedEventArgs);
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Replace:
|
|
||||||
case NotifyCollectionChangedAction.Move:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public object SyncRoot => parent.SyncRoot;
|
|
||||||
|
|
||||||
public int Count => parent.Count;
|
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler CollectionChanged;
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
|
||||||
|
|
||||||
public event Action<NotifyCollectionChangedAction> CollectionStateChanged
|
|
||||||
{
|
|
||||||
add { parent.CollectionStateChanged += value; }
|
|
||||||
remove { parent.CollectionStateChanged -= value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler<T> RoutingCollectionChanged
|
|
||||||
{
|
|
||||||
add { parent.RoutingCollectionChanged += value; }
|
|
||||||
remove { parent.RoutingCollectionChanged -= value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false) => parent.AttachFilter(filter, invokeAddEventForCurrentElements);
|
|
||||||
public void ResetFilter(Action<T, TView> resetAction) => parent.ResetFilter(resetAction);
|
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged() => this;
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
this.parent.RoutingCollectionChanged -= Parent_RoutingCollectionChanged;
|
|
||||||
parent.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<(T, TView)> GetEnumerator() => parent.GetEnumerator();
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => parent.GetEnumerator();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: b0e2d983b8f809a45b60f610d0542761
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,56 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Buffers;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace ObservableCollections.Internal
|
|
||||||
{
|
|
||||||
// internal ref struct ResizableArray<T>
|
|
||||||
internal struct ResizableArray<T> : IDisposable
|
|
||||||
{
|
|
||||||
T[] array;
|
|
||||||
int count;
|
|
||||||
|
|
||||||
public ReadOnlySpan<T> Span => array.AsSpan(0, count);
|
|
||||||
|
|
||||||
public ResizableArray(int initialCapacity)
|
|
||||||
{
|
|
||||||
array = ArrayPool<T>.Shared.Rent(initialCapacity);
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Add(T item)
|
|
||||||
{
|
|
||||||
if (array == null) Throw();
|
|
||||||
if (array.Length == count)
|
|
||||||
{
|
|
||||||
EnsureCapacity();
|
|
||||||
}
|
|
||||||
array[count++] = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
||||||
void EnsureCapacity()
|
|
||||||
{
|
|
||||||
var newArray = array.AsSpan().ToArray();
|
|
||||||
ArrayPool<T>.Shared.Return(array, RuntimeHelpersEx.IsReferenceOrContainsReferences<T>());
|
|
||||||
array = newArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (array != null)
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(array, RuntimeHelpersEx.IsReferenceOrContainsReferences<T>());
|
|
||||||
array = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[DoesNotReturn]
|
|
||||||
void Throw()
|
|
||||||
{
|
|
||||||
throw new ObjectDisposedException("ResizableArray");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: b1477839cc1e36a4187e91e4fd001dd5
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,250 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace ObservableCollections.Internal
|
|
||||||
{
|
|
||||||
internal class SortedView<T, TKey, TView> : ISynchronizedView<T, TView>
|
|
||||||
|
|
||||||
{
|
|
||||||
readonly IObservableCollection<T> source;
|
|
||||||
readonly Func<T, TView> transform;
|
|
||||||
readonly Func<T, TKey> identitySelector;
|
|
||||||
readonly SortedList<(T Value, TKey Key), (T Value, TView View)> list;
|
|
||||||
|
|
||||||
ISynchronizedViewFilter<T, TView> filter;
|
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler<T> RoutingCollectionChanged;
|
|
||||||
public event Action<NotifyCollectionChangedAction> CollectionStateChanged;
|
|
||||||
|
|
||||||
public object SyncRoot { get; } = new object();
|
|
||||||
|
|
||||||
public SortedView(IObservableCollection<T> source, Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<T> comparer)
|
|
||||||
{
|
|
||||||
this.source = source;
|
|
||||||
this.identitySelector = identitySelector;
|
|
||||||
this.transform = transform;
|
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
lock (source.SyncRoot)
|
|
||||||
{
|
|
||||||
var dict = new Dictionary<(T, TKey), (T, TView)>(source.Count);
|
|
||||||
foreach (var v in source)
|
|
||||||
{
|
|
||||||
dict.Add((v, identitySelector(v)), (v, transform(v)));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.list = new SortedList<(T Value, TKey Key), (T Value, TView View)>(dict, new Comparer(comparer));
|
|
||||||
this.source.CollectionChanged += SourceCollectionChanged;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return list.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = filter;
|
|
||||||
foreach (var (_, (value, view)) in list)
|
|
||||||
{
|
|
||||||
if (invokeAddEventForCurrentElements)
|
|
||||||
{
|
|
||||||
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, -1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
filter.InvokeOnAttach(value, view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResetFilter(Action<T, TView> resetAction)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
if (resetAction != null)
|
|
||||||
{
|
|
||||||
foreach (var (_, (value, view)) in list)
|
|
||||||
{
|
|
||||||
resetAction(value, view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedSynchronizedView<T, TView>(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<(T, TView)> GetEnumerator()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
foreach (var item in list)
|
|
||||||
{
|
|
||||||
if (filter.IsMatch(item.Value.Value, item.Value.View))
|
|
||||||
{
|
|
||||||
yield return item.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
this.source.CollectionChanged -= SourceCollectionChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SourceCollectionChanged(in NotifyCollectionChangedEventArgs<T> e)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
switch (e.Action)
|
|
||||||
{
|
|
||||||
case NotifyCollectionChangedAction.Add:
|
|
||||||
{
|
|
||||||
// Add, Insert
|
|
||||||
if (e.IsSingleItem)
|
|
||||||
{
|
|
||||||
var value = e.NewItem;
|
|
||||||
var view = transform(value);
|
|
||||||
var id = identitySelector(value);
|
|
||||||
list.Add((value, id), (value, view));
|
|
||||||
var index = list.IndexOfKey((value, id));
|
|
||||||
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, index));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var value in e.NewItems)
|
|
||||||
{
|
|
||||||
var view = transform(value);
|
|
||||||
var id = identitySelector(value);
|
|
||||||
list.Add((value, id), (value, view));
|
|
||||||
var index = list.IndexOfKey((value, id));
|
|
||||||
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Remove:
|
|
||||||
{
|
|
||||||
if (e.IsSingleItem)
|
|
||||||
{
|
|
||||||
var value = e.OldItem;
|
|
||||||
var id = identitySelector(value);
|
|
||||||
var key = (value, id);
|
|
||||||
if (list.TryGetValue(key, out var v))
|
|
||||||
{
|
|
||||||
var index = list.IndexOfKey(key);
|
|
||||||
list.RemoveAt(index);
|
|
||||||
filter.InvokeOnRemove(v.Value, v.View, NotifyCollectionChangedEventArgs<T>.Remove(v.Value, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var value in e.OldItems)
|
|
||||||
{
|
|
||||||
var id = identitySelector(value);
|
|
||||||
var key = (value, id);
|
|
||||||
if (list.TryGetValue(key, out var v))
|
|
||||||
{
|
|
||||||
var index = list.IndexOfKey((value, id));
|
|
||||||
list.RemoveAt(index);
|
|
||||||
filter.InvokeOnRemove(v.Value, v.View, NotifyCollectionChangedEventArgs<T>.Remove(v.Value, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Replace:
|
|
||||||
// ReplaceRange is not supported in all ObservableCollections collections
|
|
||||||
// Replace is remove old item and insert new item.
|
|
||||||
{
|
|
||||||
var oldValue = e.OldItem;
|
|
||||||
var oldKey = (oldValue, identitySelector(oldValue));
|
|
||||||
if (list.TryGetValue(oldKey, out var o))
|
|
||||||
{
|
|
||||||
var oldIndex = list.IndexOfKey(oldKey);
|
|
||||||
list.RemoveAt(oldIndex);
|
|
||||||
filter.InvokeOnRemove(o, NotifyCollectionChangedEventArgs<T>.Remove(oldValue, oldIndex));
|
|
||||||
}
|
|
||||||
|
|
||||||
var value = e.NewItem;
|
|
||||||
var view = transform(value);
|
|
||||||
var id = identitySelector(value);
|
|
||||||
list.Add((value, id), (value, view));
|
|
||||||
var newIndex = list.IndexOfKey((value, id));
|
|
||||||
|
|
||||||
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, newIndex));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Move:
|
|
||||||
{
|
|
||||||
// Move(index change) does not affect sorted list.
|
|
||||||
var oldValue = e.OldItem;
|
|
||||||
if (list.TryGetValue((oldValue, identitySelector(oldValue)), out var view))
|
|
||||||
{
|
|
||||||
filter.InvokeOnMove(view, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Reset:
|
|
||||||
if (!filter.IsNullFilter())
|
|
||||||
{
|
|
||||||
foreach (var item in list)
|
|
||||||
{
|
|
||||||
filter.InvokeOnRemove(item.Value, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list.Clear();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
RoutingCollectionChanged?.Invoke(e);
|
|
||||||
CollectionStateChanged?.Invoke(e.Action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class Comparer : IComparer<(T value, TKey id)>
|
|
||||||
{
|
|
||||||
readonly IComparer<T> comparer;
|
|
||||||
|
|
||||||
public Comparer(IComparer<T> comparer)
|
|
||||||
{
|
|
||||||
this.comparer = comparer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Compare((T value, TKey id) x, (T value, TKey id) y)
|
|
||||||
{
|
|
||||||
var compare = comparer.Compare(x.value, y.value);
|
|
||||||
if (compare == 0)
|
|
||||||
{
|
|
||||||
compare = Comparer<TKey>.Default.Compare(x.id, y.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return compare;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 768c43ec998d9754d8cc13398ed69d39
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,269 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace ObservableCollections.Internal
|
|
||||||
{
|
|
||||||
internal class SortedViewViewComparer<T, TKey, TView> : ISynchronizedView<T, TView>
|
|
||||||
|
|
||||||
{
|
|
||||||
readonly IObservableCollection<T> source;
|
|
||||||
readonly Func<T, TView> transform;
|
|
||||||
readonly Func<T, TKey> identitySelector;
|
|
||||||
readonly Dictionary<TKey, TView> viewMap; // view-map needs to use in remove.
|
|
||||||
readonly SortedList<(TView View, TKey Key), (T Value, TView View)> list;
|
|
||||||
|
|
||||||
ISynchronizedViewFilter<T, TView> filter;
|
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler<T> RoutingCollectionChanged;
|
|
||||||
public event Action<NotifyCollectionChangedAction> CollectionStateChanged;
|
|
||||||
|
|
||||||
public object SyncRoot { get; } = new object();
|
|
||||||
|
|
||||||
public SortedViewViewComparer(IObservableCollection<T> source, Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<TView> comparer)
|
|
||||||
{
|
|
||||||
this.source = source;
|
|
||||||
this.identitySelector = identitySelector;
|
|
||||||
this.transform = transform;
|
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
lock (source.SyncRoot)
|
|
||||||
{
|
|
||||||
var dict = new Dictionary<(TView, TKey), (T, TView)>(source.Count);
|
|
||||||
this.viewMap = new Dictionary<TKey, TView>();
|
|
||||||
foreach (var value in source)
|
|
||||||
{
|
|
||||||
var view = transform(value);
|
|
||||||
var id = identitySelector(value);
|
|
||||||
dict.Add((view, id), (value, view));
|
|
||||||
viewMap.Add(id, view);
|
|
||||||
}
|
|
||||||
this.list = new SortedList<(TView View, TKey Key), (T Value, TView View)>(dict, new Comparer(comparer));
|
|
||||||
this.source.CollectionChanged += SourceCollectionChanged;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return list.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = filter;
|
|
||||||
foreach (var (_, (value, view)) in list)
|
|
||||||
{
|
|
||||||
if (invokeAddEventForCurrentElements)
|
|
||||||
{
|
|
||||||
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, -1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
filter.InvokeOnAttach(value, view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResetFilter(Action<T, TView> resetAction)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
if (resetAction != null)
|
|
||||||
{
|
|
||||||
foreach (var (_, (value, view)) in list)
|
|
||||||
{
|
|
||||||
resetAction(value, view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedSynchronizedView<T, TView>(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<(T, TView)> GetEnumerator()
|
|
||||||
{
|
|
||||||
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
foreach (var item in list)
|
|
||||||
{
|
|
||||||
if (filter.IsMatch(item.Value.Value, item.Value.View))
|
|
||||||
{
|
|
||||||
yield return item.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
this.source.CollectionChanged -= SourceCollectionChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SourceCollectionChanged(in NotifyCollectionChangedEventArgs<T> e)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
switch (e.Action)
|
|
||||||
{
|
|
||||||
case NotifyCollectionChangedAction.Add:
|
|
||||||
{
|
|
||||||
// Add, Insert
|
|
||||||
if (e.IsSingleItem)
|
|
||||||
{
|
|
||||||
var value = e.NewItem;
|
|
||||||
var view = transform(value);
|
|
||||||
var id = identitySelector(value);
|
|
||||||
list.Add((view, id), (value, view));
|
|
||||||
viewMap.Add(id, view);
|
|
||||||
var index = list.IndexOfKey((view, id));
|
|
||||||
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, index));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var value in e.NewItems)
|
|
||||||
{
|
|
||||||
var view = transform(value);
|
|
||||||
var id = identitySelector(value);
|
|
||||||
list.Add((view, id), (value, view));
|
|
||||||
viewMap.Add(id, view);
|
|
||||||
var index = list.IndexOfKey((view, id));
|
|
||||||
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NotifyCollectionChangedAction.Remove:
|
|
||||||
{
|
|
||||||
if (e.IsSingleItem)
|
|
||||||
{
|
|
||||||
var value = e.OldItem;
|
|
||||||
var id = identitySelector(value);
|
|
||||||
if (viewMap.Remove(id, out var view))
|
|
||||||
{
|
|
||||||
var key = (view, id);
|
|
||||||
if (list.TryGetValue(key, out var v))
|
|
||||||
{
|
|
||||||
var index = list.IndexOfKey(key);
|
|
||||||
list.RemoveAt(index);
|
|
||||||
filter.InvokeOnRemove(v, NotifyCollectionChangedEventArgs<T>.Remove(v.Value, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var value in e.OldItems)
|
|
||||||
{
|
|
||||||
var id = identitySelector(value);
|
|
||||||
if (viewMap.Remove(id, out var view))
|
|
||||||
{
|
|
||||||
var key = (view, id);
|
|
||||||
if (list.TryGetValue(key, out var v))
|
|
||||||
{
|
|
||||||
var index = list.IndexOfKey((view, id));
|
|
||||||
list.RemoveAt(index);
|
|
||||||
filter.InvokeOnRemove(v, NotifyCollectionChangedEventArgs<T>.Remove(v.Value, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NotifyCollectionChangedAction.Replace:
|
|
||||||
// Replace is remove old item and insert new item.
|
|
||||||
{
|
|
||||||
var oldValue = e.OldItem;
|
|
||||||
var oldId = identitySelector(oldValue);
|
|
||||||
if (viewMap.Remove(oldId, out var oldView))
|
|
||||||
{
|
|
||||||
var oldKey = (oldView, oldId);
|
|
||||||
if (list.TryGetValue(oldKey, out var v))
|
|
||||||
{
|
|
||||||
var oldIndex = list.IndexOfKey(oldKey);
|
|
||||||
list.RemoveAt(oldIndex);
|
|
||||||
filter.InvokeOnRemove(oldValue, oldView, NotifyCollectionChangedEventArgs<T>.Remove(v.Value, oldIndex));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var value = e.NewItem;
|
|
||||||
var view = transform(value);
|
|
||||||
var id = identitySelector(value);
|
|
||||||
list.Add((view, id), (value, view));
|
|
||||||
viewMap.Add(id, view);
|
|
||||||
|
|
||||||
var index = list.IndexOfKey((view, id));
|
|
||||||
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, index));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NotifyCollectionChangedAction.Move:
|
|
||||||
// Move(index change) does not affect soreted dict.
|
|
||||||
{
|
|
||||||
var value = e.OldItem;
|
|
||||||
var key = identitySelector(value);
|
|
||||||
if (viewMap.TryGetValue(key, out var view))
|
|
||||||
{
|
|
||||||
filter.InvokeOnMove(value, view, e);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NotifyCollectionChangedAction.Reset:
|
|
||||||
if (!filter.IsNullFilter())
|
|
||||||
{
|
|
||||||
foreach (var item in list)
|
|
||||||
{
|
|
||||||
filter.InvokeOnRemove(item.Value, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list.Clear();
|
|
||||||
viewMap.Clear();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
RoutingCollectionChanged?.Invoke(e);
|
|
||||||
CollectionStateChanged?.Invoke(e.Action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class Comparer : IComparer<(TView view, TKey id)>
|
|
||||||
{
|
|
||||||
readonly IComparer<TView> comparer;
|
|
||||||
|
|
||||||
public Comparer(IComparer<TView> comparer)
|
|
||||||
{
|
|
||||||
this.comparer = comparer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Compare((TView view, TKey id) x, (TView view, TKey id) y)
|
|
||||||
{
|
|
||||||
var compare = comparer.Compare(x.view, y.view);
|
|
||||||
if (compare == 0)
|
|
||||||
{
|
|
||||||
compare = Comparer<TKey>.Default.Compare(x.id, y.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return compare;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 08e8703f31991094aa9216bf7166a549
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,127 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Contract:
|
|
||||||
/// IsSingleItem ? (NewItem, OldItem) : (NewItems, OldItems)
|
|
||||||
/// Action.Add
|
|
||||||
/// NewItem, NewItems, NewStartingIndex
|
|
||||||
/// Action.Remove
|
|
||||||
/// OldItem, OldItems, OldStartingIndex
|
|
||||||
/// Action.Replace
|
|
||||||
/// NewItem, NewItems, OldItem, OldItems, (NewStartingIndex, OldStartingIndex = samevalue)
|
|
||||||
/// Action.Move
|
|
||||||
/// NewStartingIndex, OldStartingIndex
|
|
||||||
/// Action.Reset
|
|
||||||
/// -
|
|
||||||
/// </summary>
|
|
||||||
[StructLayout(LayoutKind.Auto)]
|
|
||||||
public readonly ref struct NotifyCollectionChangedEventArgs<T>
|
|
||||||
{
|
|
||||||
public readonly NotifyCollectionChangedAction Action;
|
|
||||||
public readonly bool IsSingleItem;
|
|
||||||
public readonly T NewItem;
|
|
||||||
public readonly T OldItem;
|
|
||||||
public readonly ReadOnlySpan<T> NewItems;
|
|
||||||
public readonly ReadOnlySpan<T> OldItems;
|
|
||||||
public readonly int NewStartingIndex;
|
|
||||||
public readonly int OldStartingIndex;
|
|
||||||
|
|
||||||
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, bool isSingleItem, T newItem = default, T oldItem = default, ReadOnlySpan<T> newItems = default, ReadOnlySpan<T> oldItems = default, int newStartingIndex = -1, int oldStartingIndex = -1)
|
|
||||||
{
|
|
||||||
Action = action;
|
|
||||||
IsSingleItem = isSingleItem;
|
|
||||||
NewItem = newItem;
|
|
||||||
OldItem = oldItem;
|
|
||||||
NewItems = newItems;
|
|
||||||
OldItems = oldItems;
|
|
||||||
NewStartingIndex = newStartingIndex;
|
|
||||||
OldStartingIndex = oldStartingIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public NotifyCollectionChangedEventArgs ToStandardEventArgs()
|
|
||||||
{
|
|
||||||
switch (Action)
|
|
||||||
{
|
|
||||||
case NotifyCollectionChangedAction.Add:
|
|
||||||
if (IsSingleItem)
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedEventArgs(Action, NewItem, NewStartingIndex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedEventArgs(Action, NewItems.ToArray(), NewStartingIndex);
|
|
||||||
}
|
|
||||||
case NotifyCollectionChangedAction.Remove:
|
|
||||||
if (IsSingleItem)
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedEventArgs(Action, OldItem, OldStartingIndex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedEventArgs(Action, OldItems.ToArray(), OldStartingIndex);
|
|
||||||
}
|
|
||||||
case NotifyCollectionChangedAction.Replace:
|
|
||||||
if (IsSingleItem)
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedEventArgs(Action, NewItem, OldItem, NewStartingIndex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedEventArgs(Action, NewItems.ToArray(), OldItems.ToArray(), NewStartingIndex);
|
|
||||||
}
|
|
||||||
case NotifyCollectionChangedAction.Move:
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedEventArgs(Action, OldItem, NewStartingIndex, OldStartingIndex);
|
|
||||||
}
|
|
||||||
case NotifyCollectionChangedAction.Reset:
|
|
||||||
return new NotifyCollectionChangedEventArgs(Action);
|
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static NotifyCollectionChangedEventArgs<T> Add(T newItem, int newStartingIndex)
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedEventArgs<T>(NotifyCollectionChangedAction.Add, true, newItem: newItem, newStartingIndex: newStartingIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static NotifyCollectionChangedEventArgs<T> Add(ReadOnlySpan<T> newItems, int newStartingIndex)
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedEventArgs<T>(NotifyCollectionChangedAction.Add, false, newItems: newItems, newStartingIndex: newStartingIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static NotifyCollectionChangedEventArgs<T> Remove(T oldItem, int oldStartingIndex)
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedEventArgs<T>(NotifyCollectionChangedAction.Remove, true, oldItem: oldItem, oldStartingIndex: oldStartingIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static NotifyCollectionChangedEventArgs<T> Remove(ReadOnlySpan<T> oldItems, int oldStartingIndex)
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedEventArgs<T>(NotifyCollectionChangedAction.Remove, false, oldItems: oldItems, oldStartingIndex: oldStartingIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static NotifyCollectionChangedEventArgs<T> Replace(T newItem, T oldItem, int startingIndex)
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedEventArgs<T>(NotifyCollectionChangedAction.Replace, true, newItem: newItem, oldItem: oldItem, newStartingIndex: startingIndex, oldStartingIndex: startingIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static NotifyCollectionChangedEventArgs<T> Replace(ReadOnlySpan<T> newItems, ReadOnlySpan<T> oldItems, int startingIndex)
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedEventArgs<T>(NotifyCollectionChangedAction.Replace, false, newItems: newItems, oldItems: oldItems, newStartingIndex: startingIndex, oldStartingIndex: startingIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static NotifyCollectionChangedEventArgs<T> Move(T changedItem, int newStartingIndex, int oldStartingIndex)
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedEventArgs<T>(NotifyCollectionChangedAction.Move, true, oldItem: changedItem, newItem: changedItem, newStartingIndex: newStartingIndex, oldStartingIndex: oldStartingIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static NotifyCollectionChangedEventArgs<T> Reset()
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedEventArgs<T>(NotifyCollectionChangedAction.Reset, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 70f96ba473572df4d91f125c2663b868
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "ObservableCollections",
|
|
||||||
"rootNamespace": "ObservableCollections",
|
|
||||||
"references": [],
|
|
||||||
"includePlatforms": [],
|
|
||||||
"excludePlatforms": [],
|
|
||||||
"allowUnsafeCode": false,
|
|
||||||
"overrideReferences": true,
|
|
||||||
"precompiledReferences": [
|
|
||||||
"System.Memory.dll",
|
|
||||||
"System.Buffers.dll",
|
|
||||||
"System.Runtime.CompilerServices.Unsafe.dll"
|
|
||||||
],
|
|
||||||
"autoReferenced": true,
|
|
||||||
"defineConstraints": [],
|
|
||||||
"versionDefines": [],
|
|
||||||
"noEngineReferences": true
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: a25f8e99c4faa4b4a8c38f41a406f5d3
|
|
||||||
AssemblyDefinitionImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,180 +0,0 @@
|
|||||||
using ObservableCollections.Internal;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
public sealed partial class ObservableDictionary<TKey, TValue>
|
|
||||||
{
|
|
||||||
public ISynchronizedView<KeyValuePair<TKey, TValue>, TView> CreateView<TView>(Func<KeyValuePair<TKey, TValue>, TView> transform, bool _ = false)
|
|
||||||
{
|
|
||||||
// reverse is no used.
|
|
||||||
return new View<TView>(this, transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
class View<TView> : ISynchronizedView<KeyValuePair<TKey, TValue>, TView>
|
|
||||||
{
|
|
||||||
readonly ObservableDictionary<TKey, TValue> source;
|
|
||||||
readonly Func<KeyValuePair<TKey, TValue>, TView> selector;
|
|
||||||
ISynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView> filter;
|
|
||||||
readonly Dictionary<TKey, (TValue, TView)> dict;
|
|
||||||
|
|
||||||
public View(ObservableDictionary<TKey, TValue> source, Func<KeyValuePair<TKey, TValue>, TView> selector)
|
|
||||||
{
|
|
||||||
this.source = source;
|
|
||||||
this.selector = selector;
|
|
||||||
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.Null;
|
|
||||||
this.SyncRoot = new object();
|
|
||||||
lock (source.SyncRoot)
|
|
||||||
{
|
|
||||||
this.dict = source.dictionary.ToDictionary(x => x.Key, x => (x.Value, selector(x)));
|
|
||||||
this.source.CollectionChanged += SourceCollectionChanged;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public object SyncRoot { get; }
|
|
||||||
public event NotifyCollectionChangedEventHandler<KeyValuePair<TKey, TValue>> RoutingCollectionChanged;
|
|
||||||
public event Action<NotifyCollectionChangedAction> CollectionStateChanged;
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return dict.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
this.source.CollectionChanged -= SourceCollectionChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView> filter, bool invokeAddEventForCurrentElements = false)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = filter;
|
|
||||||
foreach (var v in dict)
|
|
||||||
{
|
|
||||||
var value = new KeyValuePair<TKey, TValue>(v.Key, v.Value.Item1);
|
|
||||||
var view = v.Value.Item2;
|
|
||||||
if (invokeAddEventForCurrentElements)
|
|
||||||
{
|
|
||||||
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<KeyValuePair<TKey, TValue>>.Add(value, -1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
filter.InvokeOnAttach(value, view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResetFilter(Action<KeyValuePair<TKey, TValue>, TView> resetAction)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.Null;
|
|
||||||
if (resetAction != null)
|
|
||||||
{
|
|
||||||
foreach (var v in dict)
|
|
||||||
{
|
|
||||||
resetAction(new KeyValuePair<TKey, TValue>(v.Key, v.Value.Item1), v.Value.Item2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public INotifyCollectionChangedSynchronizedView<KeyValuePair<TKey, TValue>, TView> WithINotifyCollectionChanged()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedSynchronizedView<KeyValuePair<TKey, TValue>, TView>(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<(KeyValuePair<TKey, TValue>, TView)> GetEnumerator()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
foreach (var item in dict)
|
|
||||||
{
|
|
||||||
var v = (new KeyValuePair<TKey, TValue>(item.Key, item.Value.Item1), item.Value.Item2);
|
|
||||||
if (filter.IsMatch(v.Item1, v.Item2))
|
|
||||||
{
|
|
||||||
yield return v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SourceCollectionChanged(in NotifyCollectionChangedEventArgs<KeyValuePair<TKey, TValue>> e)
|
|
||||||
{
|
|
||||||
// ObservableDictionary only provides single item operation and does not use int index.
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
switch (e.Action)
|
|
||||||
{
|
|
||||||
case NotifyCollectionChangedAction.Add:
|
|
||||||
{
|
|
||||||
var v = selector(e.NewItem);
|
|
||||||
dict.Add(e.NewItem.Key, (e.NewItem.Value, v));
|
|
||||||
filter.InvokeOnAdd(new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value), v, e);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Remove:
|
|
||||||
{
|
|
||||||
if (dict.Remove(e.OldItem.Key, out var v))
|
|
||||||
{
|
|
||||||
filter.InvokeOnRemove((new KeyValuePair<TKey, TValue>(e.OldItem.Key, v.Item1), v.Item2), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Replace:
|
|
||||||
{
|
|
||||||
if (dict.Remove(e.OldItem.Key, out var oldView))
|
|
||||||
{
|
|
||||||
filter.InvokeOnRemove((new KeyValuePair<TKey, TValue>(e.OldItem.Key, oldView.Item1), oldView.Item2), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
var v = selector(e.NewItem);
|
|
||||||
dict[e.NewItem.Key] = (e.NewItem.Value, v);
|
|
||||||
filter.InvokeOnAdd(new KeyValuePair<TKey, TValue>(e.NewItem.Key, e.NewItem.Value), v, e);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Reset:
|
|
||||||
{
|
|
||||||
if (!filter.IsNullFilter())
|
|
||||||
{
|
|
||||||
foreach (var item in dict)
|
|
||||||
{
|
|
||||||
filter.InvokeOnRemove((new KeyValuePair<TKey, TValue>(item.Key, item.Value.Item1), item.Value.Item2), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dict.Clear();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Move: // ObservableDictionary have no Move operation.
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
RoutingCollectionChanged?.Invoke(e);
|
|
||||||
CollectionStateChanged?.Invoke(e.Action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: f512d4ba320de58428976eb614bfa06d
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,228 +0,0 @@
|
|||||||
using ObservableCollections.Internal;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
public sealed partial class ObservableDictionary<TKey, TValue>
|
|
||||||
: IDictionary<TKey, TValue>, IReadOnlyDictionary<TKey, TValue>, IObservableCollection<KeyValuePair<TKey, TValue>>
|
|
||||||
|
|
||||||
{
|
|
||||||
readonly Dictionary<TKey, TValue> dictionary;
|
|
||||||
public object SyncRoot { get; } = new object();
|
|
||||||
|
|
||||||
public ObservableDictionary()
|
|
||||||
{
|
|
||||||
this.dictionary = new Dictionary<TKey, TValue>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection)
|
|
||||||
{
|
|
||||||
#if NET6_0_OR_GREATER
|
|
||||||
this.dictionary = new Dictionary<TKey, TValue>(collection);
|
|
||||||
#else
|
|
||||||
this.dictionary = new Dictionary<TKey, TValue>();
|
|
||||||
foreach (var item in collection)
|
|
||||||
{
|
|
||||||
dictionary.Add(item.Key, item.Value);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler<KeyValuePair<TKey, TValue>> CollectionChanged;
|
|
||||||
|
|
||||||
public TValue this[TKey key]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return dictionary[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (dictionary.TryGetValue(key, out var oldValue))
|
|
||||||
{
|
|
||||||
dictionary[key] = value;
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<KeyValuePair<TKey, TValue>>.Replace(
|
|
||||||
new KeyValuePair<TKey, TValue>(key, value),
|
|
||||||
new KeyValuePair<TKey, TValue>(key, oldValue),
|
|
||||||
-1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Add(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// for lock synchronization, hide keys and values.
|
|
||||||
ICollection<TKey> IDictionary<TKey, TValue>.Keys
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return dictionary.Keys;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ICollection<TValue> IDictionary<TKey, TValue>.Values
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return dictionary.Values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return dictionary.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsReadOnly => false;
|
|
||||||
|
|
||||||
IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return dictionary.Keys;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return dictionary.Values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(TKey key, TValue value)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
dictionary.Add(key, value);
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<KeyValuePair<TKey, TValue>>.Add(new KeyValuePair<TKey, TValue>(key, value), -1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(KeyValuePair<TKey, TValue> item)
|
|
||||||
{
|
|
||||||
Add(item.Key, item.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
dictionary.Clear();
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<KeyValuePair<TKey, TValue>>.Reset());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains(KeyValuePair<TKey, TValue> item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return ((ICollection<KeyValuePair<TKey, TValue>>)dictionary).Contains(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ContainsKey(TKey key)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return ((IDictionary<TKey, TValue>)dictionary).ContainsKey(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
((ICollection<KeyValuePair<TKey, TValue>>)dictionary).CopyTo(array, arrayIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Remove(TKey key)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (dictionary.Remove(key, out var value))
|
|
||||||
{
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<KeyValuePair<TKey, TValue>>.Remove(new KeyValuePair<TKey, TValue>(key, value), -1));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Remove(KeyValuePair<TKey, TValue> item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (dictionary.TryGetValue(item.Key, out var value))
|
|
||||||
{
|
|
||||||
if (EqualityComparer<TValue>.Default.Equals(value, item.Value))
|
|
||||||
{
|
|
||||||
if (dictionary.Remove(item.Key, out var value2))
|
|
||||||
{
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<KeyValuePair<TKey, TValue>>.Remove(new KeyValuePair<TKey, TValue>(item.Key, value2), -1));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma warning disable CS8767
|
|
||||||
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
|
|
||||||
#pragma warning restore CS8767
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return dictionary.TryGetValue(key, out value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
foreach (var item in dictionary)
|
|
||||||
{
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: b4dc0886473cf8c49947c9081454c614
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,326 +0,0 @@
|
|||||||
using ObservableCollections.Internal;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
public sealed partial class ObservableFixedSizeRingBuffer<T> : IList<T>, IReadOnlyList<T>, IObservableCollection<T>
|
|
||||||
{
|
|
||||||
readonly RingBuffer<T> buffer;
|
|
||||||
readonly int capacity;
|
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler<T> CollectionChanged;
|
|
||||||
|
|
||||||
public ObservableFixedSizeRingBuffer(int capacity)
|
|
||||||
{
|
|
||||||
this.capacity = capacity;
|
|
||||||
this.buffer = new RingBuffer<T>(capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableFixedSizeRingBuffer(int capacity, IEnumerable<T> collection)
|
|
||||||
{
|
|
||||||
this.capacity = capacity;
|
|
||||||
this.buffer = new RingBuffer<T>(capacity);
|
|
||||||
foreach (var item in collection)
|
|
||||||
{
|
|
||||||
if (capacity == buffer.Count)
|
|
||||||
{
|
|
||||||
buffer.RemoveFirst();
|
|
||||||
}
|
|
||||||
buffer.AddLast(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsReadOnly => false;
|
|
||||||
|
|
||||||
public object SyncRoot { get; } = new object();
|
|
||||||
|
|
||||||
public T this[int index]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return this.buffer[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var oldValue = buffer[index];
|
|
||||||
buffer[index] = value;
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Replace(value, oldValue, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return buffer.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddFirst(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (capacity == buffer.Count)
|
|
||||||
{
|
|
||||||
var remItem = buffer.RemoveLast();
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(remItem, capacity - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.AddFirst(item);
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(item, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddLast(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (capacity == buffer.Count)
|
|
||||||
{
|
|
||||||
var remItem = buffer.RemoveFirst();
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(remItem, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.AddLast(item);
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(item, buffer.Count - 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T RemoveFirst()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var item = buffer.RemoveFirst();
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(item, 0));
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T RemoveLast()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var index = buffer.Count - 1;
|
|
||||||
var item = buffer.RemoveLast();
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(item, index));
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddFirstRange is not exists.
|
|
||||||
|
|
||||||
public void AddLastRange(IEnumerable<T> items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
using (var xs = new CloneCollection<T>(items))
|
|
||||||
{
|
|
||||||
if (capacity <= buffer.Count + xs.Span.Length)
|
|
||||||
{
|
|
||||||
// calc remove count
|
|
||||||
var remCount = Math.Min(buffer.Count, buffer.Count + xs.Span.Length - capacity);
|
|
||||||
using (var ys = new ResizableArray<T>(remCount))
|
|
||||||
{
|
|
||||||
for (int i = 0; i < remCount; i++)
|
|
||||||
{
|
|
||||||
ys.Add(buffer.RemoveFirst());
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(ys.Span, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var index = buffer.Count;
|
|
||||||
var span = xs.Span;
|
|
||||||
if (span.Length > capacity)
|
|
||||||
{
|
|
||||||
span = span.Slice(span.Length - capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var item in span)
|
|
||||||
{
|
|
||||||
buffer.AddLast(item);
|
|
||||||
}
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(span, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddLastRange(T[] items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (capacity <= buffer.Count + items.Length)
|
|
||||||
{
|
|
||||||
// calc remove count
|
|
||||||
var remCount = Math.Min(buffer.Count, buffer.Count + items.Length - capacity);
|
|
||||||
using (var ys = new ResizableArray<T>(remCount))
|
|
||||||
{
|
|
||||||
for (int i = 0; i < remCount; i++)
|
|
||||||
{
|
|
||||||
ys.Add(buffer.RemoveFirst());
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(ys.Span, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var index = buffer.Count;
|
|
||||||
var span = items.AsSpan();
|
|
||||||
if (span.Length > capacity)
|
|
||||||
{
|
|
||||||
span = span.Slice(span.Length - capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var item in span)
|
|
||||||
{
|
|
||||||
buffer.AddLast(item);
|
|
||||||
}
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(span, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddLastRange(ReadOnlySpan<T> items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (capacity <= buffer.Count + items.Length)
|
|
||||||
{
|
|
||||||
// calc remove count
|
|
||||||
var remCount = Math.Min(buffer.Count, buffer.Count + items.Length - capacity);
|
|
||||||
using (var ys = new ResizableArray<T>(remCount))
|
|
||||||
{
|
|
||||||
for (int i = 0; i < remCount; i++)
|
|
||||||
{
|
|
||||||
ys.Add(buffer.RemoveFirst());
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(ys.Span, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var index = buffer.Count;
|
|
||||||
var span = items;
|
|
||||||
if (span.Length > capacity)
|
|
||||||
{
|
|
||||||
span = span.Slice(span.Length - capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var item in span)
|
|
||||||
{
|
|
||||||
buffer.AddLast(item);
|
|
||||||
}
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(span, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int IndexOf(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return buffer.IndexOf(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IList<T>.Insert(int index, T item)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ICollection<T>.Remove(T item)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IList<T>.RemoveAt(int index)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ICollection<T>.Add(T item)
|
|
||||||
{
|
|
||||||
AddLast(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
buffer.Clear();
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Reset());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return buffer.Contains(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CopyTo(T[] array, int arrayIndex)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
buffer.CopyTo(array, arrayIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T[] ToArray()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return buffer.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int BinarySearch(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return buffer.BinarySearch(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int BinarySearch(T item, IComparer<T> comparer)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return buffer.BinarySearch(item, comparer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
foreach (var item in buffer)
|
|
||||||
{
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false)
|
|
||||||
{
|
|
||||||
return new ObservableRingBuffer<T>.View<TView>(this, transform, reverse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 81d799cc7eb02954d89c7ee52b7c9148
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,181 +0,0 @@
|
|||||||
using ObservableCollections.Internal;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
public sealed partial class ObservableHashSet<T> : IReadOnlyCollection<T>, IObservableCollection<T>
|
|
||||||
{
|
|
||||||
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool _ = false)
|
|
||||||
{
|
|
||||||
return new View<TView>(this, transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class View<TView> : ISynchronizedView<T, TView>
|
|
||||||
{
|
|
||||||
readonly ObservableHashSet<T> source;
|
|
||||||
readonly Func<T, TView> selector;
|
|
||||||
readonly Dictionary<T, (T, TView)> dict;
|
|
||||||
|
|
||||||
ISynchronizedViewFilter<T, TView> filter;
|
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler<T> RoutingCollectionChanged;
|
|
||||||
public event Action<NotifyCollectionChangedAction> CollectionStateChanged;
|
|
||||||
|
|
||||||
public object SyncRoot { get; }
|
|
||||||
|
|
||||||
public View(ObservableHashSet<T> source, Func<T, TView> selector)
|
|
||||||
{
|
|
||||||
this.source = source;
|
|
||||||
this.selector = selector;
|
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
this.SyncRoot = new object();
|
|
||||||
lock (source.SyncRoot)
|
|
||||||
{
|
|
||||||
this.dict = source.set.ToDictionary(x => x, x => (x, selector(x)));
|
|
||||||
this.source.CollectionChanged += SourceCollectionChanged;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return dict.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = filter;
|
|
||||||
foreach (var (_, (value, view)) in dict)
|
|
||||||
{
|
|
||||||
if (invokeAddEventForCurrentElements)
|
|
||||||
{
|
|
||||||
filter.InvokeOnAdd((value, view), NotifyCollectionChangedEventArgs<T>.Add(value, -1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
filter.InvokeOnAttach(value, view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResetFilter(Action<T, TView> resetAction)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
if (resetAction != null)
|
|
||||||
{
|
|
||||||
foreach (var (_, (value, view)) in dict)
|
|
||||||
{
|
|
||||||
resetAction(value, view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedSynchronizedView<T, TView>(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<(T, TView)> GetEnumerator()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
foreach (var item in dict)
|
|
||||||
{
|
|
||||||
if (filter.IsMatch(item.Value.Item1, item.Value.Item2))
|
|
||||||
{
|
|
||||||
yield return item.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
this.source.CollectionChanged -= SourceCollectionChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SourceCollectionChanged(in NotifyCollectionChangedEventArgs<T> e)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
switch (e.Action)
|
|
||||||
{
|
|
||||||
case NotifyCollectionChangedAction.Add:
|
|
||||||
if (e.IsSingleItem)
|
|
||||||
{
|
|
||||||
var v = (e.NewItem, selector(e.NewItem));
|
|
||||||
dict.Add(e.NewItem, v);
|
|
||||||
filter.InvokeOnAdd(v, e);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var item in e.NewItems)
|
|
||||||
{
|
|
||||||
var v = (item, selector(item));
|
|
||||||
dict.Add(item, v);
|
|
||||||
filter.InvokeOnAdd(v, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Remove:
|
|
||||||
if (e.IsSingleItem)
|
|
||||||
{
|
|
||||||
if (dict.Remove(e.OldItem, out var value))
|
|
||||||
{
|
|
||||||
filter.InvokeOnRemove(value.Item1, value.Item2, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var item in e.OldItems)
|
|
||||||
{
|
|
||||||
if (dict.Remove(item, out var value))
|
|
||||||
{
|
|
||||||
filter.InvokeOnRemove(value.Item1, value.Item2, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Reset:
|
|
||||||
if (!filter.IsNullFilter())
|
|
||||||
{
|
|
||||||
foreach (var item in dict)
|
|
||||||
{
|
|
||||||
filter.InvokeOnRemove(item.Value, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dict.Clear();
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Replace:
|
|
||||||
case NotifyCollectionChangedAction.Move:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
RoutingCollectionChanged?.Invoke(e);
|
|
||||||
CollectionStateChanged?.Invoke(e.Action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: a7b9e5ab06e68b242a4a722866654fd7
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,265 +0,0 @@
|
|||||||
using ObservableCollections.Internal;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
// can not implements ISet<T> because set operation can not get added/removed values.
|
|
||||||
public sealed partial class ObservableHashSet<T> : IReadOnlySet<T>, IReadOnlyCollection<T>, IObservableCollection<T>
|
|
||||||
|
|
||||||
{
|
|
||||||
readonly HashSet<T> set;
|
|
||||||
public object SyncRoot { get; } = new object();
|
|
||||||
|
|
||||||
public ObservableHashSet()
|
|
||||||
{
|
|
||||||
this.set = new HashSet<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
#if NETSTANDARD2_1_OR_GREATER || NET5_0_OR_GREATER
|
|
||||||
|
|
||||||
public ObservableHashSet(int capacity)
|
|
||||||
{
|
|
||||||
this.set = new HashSet<T>(capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public ObservableHashSet(IEnumerable<T> collection)
|
|
||||||
{
|
|
||||||
this.set = new HashSet<T>(collection);
|
|
||||||
}
|
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler<T> CollectionChanged;
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return set.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsReadOnly => false;
|
|
||||||
|
|
||||||
public bool Add(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (set.Add(item))
|
|
||||||
{
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(item, -1));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddRange(IEnumerable<T> items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (!items.TryGetNonEnumeratedCount(out var capacity))
|
|
||||||
{
|
|
||||||
capacity = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var list = new ResizableArray<T>(capacity))
|
|
||||||
{
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
if (set.Add(item))
|
|
||||||
{
|
|
||||||
list.Add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(list.Span, -1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddRange(T[] items)
|
|
||||||
{
|
|
||||||
AddRange(items.AsSpan());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddRange(ReadOnlySpan<T> items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
using (var list = new ResizableArray<T>(items.Length))
|
|
||||||
{
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
if (set.Add(item))
|
|
||||||
{
|
|
||||||
list.Add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(list.Span, -1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Remove(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (set.Remove(item))
|
|
||||||
{
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(item, -1));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveRange(IEnumerable<T> items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (!items.TryGetNonEnumeratedCount(out var capacity))
|
|
||||||
{
|
|
||||||
capacity = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var list = new ResizableArray<T>(capacity))
|
|
||||||
{
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
if (set.Remove(item))
|
|
||||||
{
|
|
||||||
list.Add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(list.Span, -1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveRange(T[] items)
|
|
||||||
{
|
|
||||||
RemoveRange(items.AsSpan());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveRange(ReadOnlySpan<T> items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
using (var list = new ResizableArray<T>(items.Length))
|
|
||||||
{
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
if (set.Remove(item))
|
|
||||||
{
|
|
||||||
list.Add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(list.Span, -1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
set.Clear();
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Reset());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !NETSTANDARD2_0 && !NET_STANDARD_2_0 && !NET_4_6
|
|
||||||
|
|
||||||
public bool TryGetValue(T equalValue, [MaybeNullWhen(false)] out T actualValue)
|
|
||||||
{
|
|
||||||
return set.TryGetValue(equalValue, out actualValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public bool Contains(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return set.Contains(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsProperSubsetOf(IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return set.IsProperSubsetOf(other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsProperSupersetOf(IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return set.IsProperSupersetOf(other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsSubsetOf(IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return set.IsSubsetOf(other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsSupersetOf(IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return set.IsSupersetOf(other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Overlaps(IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return set.Overlaps(other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetEquals(IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return set.SetEquals(other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
foreach (var item in set)
|
|
||||||
{
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 38d982a9907bb0047b158794a1cf35e7
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,244 +0,0 @@
|
|||||||
using ObservableCollections.Internal;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
public sealed partial class ObservableList<T> : IList<T>, IReadOnlyList<T>, IObservableCollection<T>
|
|
||||||
{
|
|
||||||
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false)
|
|
||||||
{
|
|
||||||
return new View<TView>(this, transform, reverse);
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class View<TView> : ISynchronizedView<T, TView>
|
|
||||||
{
|
|
||||||
readonly ObservableList<T> source;
|
|
||||||
readonly Func<T, TView> selector;
|
|
||||||
readonly bool reverse;
|
|
||||||
readonly List<(T, TView)> list;
|
|
||||||
|
|
||||||
ISynchronizedViewFilter<T, TView> filter;
|
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler<T> RoutingCollectionChanged;
|
|
||||||
public event Action<NotifyCollectionChangedAction> CollectionStateChanged;
|
|
||||||
|
|
||||||
public object SyncRoot { get; }
|
|
||||||
|
|
||||||
public View(ObservableList<T> source, Func<T, TView> selector, bool reverse)
|
|
||||||
{
|
|
||||||
this.source = source;
|
|
||||||
this.selector = selector;
|
|
||||||
this.reverse = reverse;
|
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
this.SyncRoot = new object();
|
|
||||||
lock (source.SyncRoot)
|
|
||||||
{
|
|
||||||
this.list = source.list.Select(x => (x, selector(x))).ToList();
|
|
||||||
this.source.CollectionChanged += SourceCollectionChanged;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return list.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = filter;
|
|
||||||
for (var i = 0; i < list.Count; i++)
|
|
||||||
{
|
|
||||||
var (value, view) = list[i];
|
|
||||||
if (invokeAddEventForCurrentElements)
|
|
||||||
{
|
|
||||||
var eventArgs = NotifyCollectionChangedEventArgs<T>.Add(value, i);
|
|
||||||
filter.InvokeOnAdd(value, view, eventArgs);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
filter.InvokeOnAttach(value, view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResetFilter(Action<T, TView> resetAction)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
if (resetAction != null)
|
|
||||||
{
|
|
||||||
foreach (var (item, view) in list)
|
|
||||||
{
|
|
||||||
resetAction(item, view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedSynchronizedView<T, TView>(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<(T, TView)> GetEnumerator()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (!reverse)
|
|
||||||
{
|
|
||||||
foreach (var item in list)
|
|
||||||
{
|
|
||||||
if (filter.IsMatch(item.Item1, item.Item2))
|
|
||||||
{
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var item in list.AsEnumerable().Reverse())
|
|
||||||
{
|
|
||||||
if (filter.IsMatch(item.Item1, item.Item2))
|
|
||||||
{
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
this.source.CollectionChanged -= SourceCollectionChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SourceCollectionChanged(in NotifyCollectionChangedEventArgs<T> e)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
switch (e.Action)
|
|
||||||
{
|
|
||||||
case NotifyCollectionChangedAction.Add:
|
|
||||||
// Add
|
|
||||||
if (e.NewStartingIndex == list.Count)
|
|
||||||
{
|
|
||||||
if (e.IsSingleItem)
|
|
||||||
{
|
|
||||||
var v = (e.NewItem, selector(e.NewItem));
|
|
||||||
list.Add(v);
|
|
||||||
filter.InvokeOnAdd(v, e);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var item in e.NewItems)
|
|
||||||
{
|
|
||||||
var v = (item, selector(item));
|
|
||||||
list.Add(v);
|
|
||||||
filter.InvokeOnAdd(v, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Insert
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (e.IsSingleItem)
|
|
||||||
{
|
|
||||||
var v = (e.NewItem, selector(e.NewItem));
|
|
||||||
list.Insert(e.NewStartingIndex, v);
|
|
||||||
filter.InvokeOnAdd(v, e);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// inefficient copy, need refactoring
|
|
||||||
var newArray = new (T, TView)[e.NewItems.Length];
|
|
||||||
var span = e.NewItems;
|
|
||||||
for (int i = 0; i < span.Length; i++)
|
|
||||||
{
|
|
||||||
var v = (span[i], selector(span[i]));
|
|
||||||
newArray[i] = v;
|
|
||||||
filter.InvokeOnAdd(v, e);
|
|
||||||
}
|
|
||||||
list.InsertRange(e.NewStartingIndex, newArray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Remove:
|
|
||||||
if (e.IsSingleItem)
|
|
||||||
{
|
|
||||||
var v = list[e.OldStartingIndex];
|
|
||||||
list.RemoveAt(e.OldStartingIndex);
|
|
||||||
filter.InvokeOnRemove(v.Item1, v.Item2, e);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var len = e.OldStartingIndex + e.OldItems.Length;
|
|
||||||
for (int i = e.OldStartingIndex; i < len; i++)
|
|
||||||
{
|
|
||||||
var v = list[i];
|
|
||||||
filter.InvokeOnRemove(v.Item1, v.Item2, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
list.RemoveRange(e.OldStartingIndex, e.OldItems.Length);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Replace:
|
|
||||||
// ObservableList does not support replace range
|
|
||||||
{
|
|
||||||
var v = (e.NewItem, selector(e.NewItem));
|
|
||||||
|
|
||||||
var oldItem = list[e.NewStartingIndex];
|
|
||||||
list[e.NewStartingIndex] = v;
|
|
||||||
|
|
||||||
filter.InvokeOnRemove(oldItem, e);
|
|
||||||
filter.InvokeOnAdd(v, e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NotifyCollectionChangedAction.Move:
|
|
||||||
{
|
|
||||||
var removeItem = list[e.OldStartingIndex];
|
|
||||||
list.RemoveAt(e.OldStartingIndex);
|
|
||||||
list.Insert(e.NewStartingIndex, removeItem);
|
|
||||||
|
|
||||||
filter.InvokeOnMove(removeItem, e);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Reset:
|
|
||||||
if (!filter.IsNullFilter())
|
|
||||||
{
|
|
||||||
foreach (var item in list)
|
|
||||||
{
|
|
||||||
filter.InvokeOnRemove(item, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list.Clear();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
RoutingCollectionChanged?.Invoke(e);
|
|
||||||
CollectionStateChanged?.Invoke(e.Action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: b98cf9d4d5426ad478ede70c5ac637d2
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,276 +0,0 @@
|
|||||||
using ObservableCollections.Internal;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
public sealed partial class ObservableList<T> : IList<T>, IReadOnlyList<T>, IObservableCollection<T>
|
|
||||||
{
|
|
||||||
readonly List<T> list;
|
|
||||||
public object SyncRoot { get; } = new object();
|
|
||||||
|
|
||||||
public ObservableList()
|
|
||||||
{
|
|
||||||
list = new List<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableList(int capacity)
|
|
||||||
{
|
|
||||||
list = new List<T>(capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableList(IEnumerable<T> collection)
|
|
||||||
{
|
|
||||||
list = collection.ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public T this[int index]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return list[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var oldValue = list[index];
|
|
||||||
list[index] = value;
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Replace(value, oldValue, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return list.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsReadOnly => false;
|
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler<T> CollectionChanged;
|
|
||||||
|
|
||||||
|
|
||||||
public void Add(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var index = list.Count;
|
|
||||||
list.Add(item);
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(item, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddRange(IEnumerable<T> items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var index = list.Count;
|
|
||||||
using (var xs = new CloneCollection<T>(items))
|
|
||||||
{
|
|
||||||
// to avoid iterate twice, require copy before insert.
|
|
||||||
list.AddRange(xs.AsEnumerable());
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(xs.Span, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddRange(T[] items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var index = list.Count;
|
|
||||||
list.AddRange(items);
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(items, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddRange(ReadOnlySpan<T> items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var index = list.Count;
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
list.Add(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(items, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
var l = new List<int>();
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
list.Clear();
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Reset());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return list.Contains(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CopyTo(T[] array, int arrayIndex)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
list.CopyTo(array, arrayIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
foreach (var item in list)
|
|
||||||
{
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ForEach(Action<T> action)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
foreach (var item in list)
|
|
||||||
{
|
|
||||||
action(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int IndexOf(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return list.IndexOf(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Insert(int index, T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
list.Insert(index, item);
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(item, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void InsertRange(int index, T[] items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
list.InsertRange(index, items);
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(items, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void InsertRange(int index, IEnumerable<T> items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
using (var xs = new CloneCollection<T>(items))
|
|
||||||
{
|
|
||||||
list.InsertRange(index, xs.AsEnumerable());
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(xs.Span, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void InsertRange(int index, ReadOnlySpan<T> items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
using (var xs = new CloneCollection<T>(items))
|
|
||||||
{
|
|
||||||
list.InsertRange(index, xs.AsEnumerable());
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(xs.Span, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Remove(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var index = list.IndexOf(item);
|
|
||||||
|
|
||||||
if (index >= 0)
|
|
||||||
{
|
|
||||||
list.RemoveAt(index);
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(item, index));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveAt(int index)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var item = list[index];
|
|
||||||
list.RemoveAt(index);
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(item, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveRange(int index, int count)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
#if NET5_0_OR_GREATER
|
|
||||||
var range = CollectionsMarshal.AsSpan(list).Slice(index, count);
|
|
||||||
#else
|
|
||||||
var range = list.GetRange(index, count);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// require copy before remove
|
|
||||||
using (var xs = new CloneCollection<T>(range))
|
|
||||||
{
|
|
||||||
list.RemoveRange(index, count);
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(xs.Span, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Move(int oldIndex, int newIndex)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var removedItem = list[oldIndex];
|
|
||||||
list.RemoveAt(oldIndex);
|
|
||||||
list.Insert(newIndex, removedItem);
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Move(removedItem, newIndex, oldIndex));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 963681d5debafe6448e09cd9a4029cec
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,197 +0,0 @@
|
|||||||
using ObservableCollections.Internal;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
public sealed partial class ObservableQueue<T> : IReadOnlyCollection<T>, IObservableCollection<T>
|
|
||||||
{
|
|
||||||
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false)
|
|
||||||
{
|
|
||||||
return new View<TView>(this, transform, reverse);
|
|
||||||
}
|
|
||||||
|
|
||||||
class View<TView> : ISynchronizedView<T, TView>
|
|
||||||
{
|
|
||||||
readonly ObservableQueue<T> source;
|
|
||||||
readonly Func<T, TView> selector;
|
|
||||||
readonly bool reverse;
|
|
||||||
protected readonly Queue<(T, TView)> queue;
|
|
||||||
|
|
||||||
ISynchronizedViewFilter<T, TView> filter;
|
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler<T> RoutingCollectionChanged;
|
|
||||||
public event Action<NotifyCollectionChangedAction> CollectionStateChanged;
|
|
||||||
|
|
||||||
public object SyncRoot { get; }
|
|
||||||
|
|
||||||
public View(ObservableQueue<T> source, Func<T, TView> selector, bool reverse)
|
|
||||||
{
|
|
||||||
this.source = source;
|
|
||||||
this.selector = selector;
|
|
||||||
this.reverse = reverse;
|
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
this.SyncRoot = new object();
|
|
||||||
lock (source.SyncRoot)
|
|
||||||
{
|
|
||||||
this.queue = new Queue<(T, TView)>(source.queue.Select(x => (x, selector(x))));
|
|
||||||
this.source.CollectionChanged += SourceCollectionChanged;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return queue.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = filter;
|
|
||||||
var i = 0;
|
|
||||||
foreach (var (value, view) in queue)
|
|
||||||
{
|
|
||||||
if (invokeAddEventForCurrentElements)
|
|
||||||
{
|
|
||||||
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, i));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
filter.InvokeOnAttach(value, view);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResetFilter(Action<T, TView> resetAction)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
if (resetAction != null)
|
|
||||||
{
|
|
||||||
foreach (var (item, view) in queue)
|
|
||||||
{
|
|
||||||
resetAction(item, view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedSynchronizedView<T, TView>(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<(T, TView)> GetEnumerator()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (!reverse)
|
|
||||||
{
|
|
||||||
foreach (var item in queue)
|
|
||||||
{
|
|
||||||
if (filter.IsMatch(item.Item1, item.Item2))
|
|
||||||
{
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var item in queue.AsEnumerable().Reverse())
|
|
||||||
{
|
|
||||||
if (filter.IsMatch(item.Item1, item.Item2))
|
|
||||||
{
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
this.source.CollectionChanged -= SourceCollectionChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SourceCollectionChanged(in NotifyCollectionChangedEventArgs<T> e)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
switch (e.Action)
|
|
||||||
{
|
|
||||||
case NotifyCollectionChangedAction.Add:
|
|
||||||
// Add(Enqueue, EnqueueRange)
|
|
||||||
if (e.IsSingleItem)
|
|
||||||
{
|
|
||||||
var v = (e.NewItem, selector(e.NewItem));
|
|
||||||
queue.Enqueue(v);
|
|
||||||
filter.InvokeOnAdd(v, e);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var item in e.NewItems)
|
|
||||||
{
|
|
||||||
var v = (item, selector(item));
|
|
||||||
queue.Enqueue(v);
|
|
||||||
filter.InvokeOnAdd(v, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Remove:
|
|
||||||
// Dequeue, DequeuRange
|
|
||||||
if (e.IsSingleItem)
|
|
||||||
{
|
|
||||||
var v = queue.Dequeue();
|
|
||||||
filter.InvokeOnRemove(v.Item1, v.Item2, e);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var len = e.OldItems.Length;
|
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
var v = queue.Dequeue();
|
|
||||||
filter.InvokeOnRemove(v.Item1, v.Item2, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Reset:
|
|
||||||
if (!filter.IsNullFilter())
|
|
||||||
{
|
|
||||||
foreach (var item in queue)
|
|
||||||
{
|
|
||||||
filter.InvokeOnRemove(item, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
queue.Clear();
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Replace:
|
|
||||||
case NotifyCollectionChangedAction.Move:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
RoutingCollectionChanged?.Invoke(e);
|
|
||||||
CollectionStateChanged?.Invoke(e.Action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 3fea76167e2a69749931bf01b5b5ed92
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,220 +0,0 @@
|
|||||||
using ObservableCollections.Internal;
|
|
||||||
using System.Buffers;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
public sealed partial class ObservableQueue<T> : IReadOnlyCollection<T>, IObservableCollection<T>
|
|
||||||
{
|
|
||||||
readonly Queue<T> queue;
|
|
||||||
public object SyncRoot { get; } = new object();
|
|
||||||
|
|
||||||
public ObservableQueue()
|
|
||||||
{
|
|
||||||
this.queue = new Queue<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableQueue(int capacity)
|
|
||||||
{
|
|
||||||
this.queue = new Queue<T>(capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableQueue(IEnumerable<T> collection)
|
|
||||||
{
|
|
||||||
this.queue = new Queue<T>(collection);
|
|
||||||
}
|
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler<T> CollectionChanged;
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return queue.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Enqueue(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var index = queue.Count;
|
|
||||||
queue.Enqueue(item);
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(item, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void EnqueueRange(IEnumerable<T> items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var index = queue.Count;
|
|
||||||
using (var xs = new CloneCollection<T>(items))
|
|
||||||
{
|
|
||||||
foreach (var item in xs.Span)
|
|
||||||
{
|
|
||||||
queue.Enqueue(item);
|
|
||||||
}
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(xs.Span, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void EnqueueRange(T[] items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var index = queue.Count;
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
queue.Enqueue(item);
|
|
||||||
}
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(items, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void EnqueueRange(ReadOnlySpan<T> items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var index = queue.Count;
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
queue.Enqueue(item);
|
|
||||||
}
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(items, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Dequeue()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var v = queue.Dequeue();
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(v, 0));
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryDequeue([MaybeNullWhen(false)] out T result)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (queue.Count != 0)
|
|
||||||
{
|
|
||||||
result = queue.Dequeue();
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(result, 0));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
result = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DequeueRange(int count)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var dest = ArrayPool<T>.Shared.Rent(count);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
dest[i] = queue.Dequeue();
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(dest.AsSpan(0, count), 0));
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(dest, RuntimeHelpersEx.IsReferenceOrContainsReferences<T>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DequeueRange(Span<T> dest)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < dest.Length; i++)
|
|
||||||
{
|
|
||||||
dest[i] = queue.Dequeue();
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(dest, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
queue.Clear();
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Reset());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Peek()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return queue.Peek();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryPeek([MaybeNullWhen(false)] T result)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (queue.Count != 0)
|
|
||||||
{
|
|
||||||
result = queue.Peek();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
result = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T[] ToArray()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return queue.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void TrimExcess()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
queue.TrimExcess();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
foreach (var item in queue)
|
|
||||||
{
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: eb4558e36aaf5c84597551bb9a0d42e9
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,254 +0,0 @@
|
|||||||
using ObservableCollections.Internal;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
public sealed partial class ObservableRingBuffer<T>
|
|
||||||
{
|
|
||||||
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false)
|
|
||||||
{
|
|
||||||
return new View<TView>(this, transform, reverse);
|
|
||||||
}
|
|
||||||
|
|
||||||
// used with ObservableFixedSizeRingBuffer
|
|
||||||
internal sealed class View<TView> : ISynchronizedView<T, TView>
|
|
||||||
{
|
|
||||||
readonly IObservableCollection<T> source;
|
|
||||||
readonly Func<T, TView> selector;
|
|
||||||
readonly bool reverse;
|
|
||||||
readonly RingBuffer<(T, TView)> ringBuffer;
|
|
||||||
|
|
||||||
ISynchronizedViewFilter<T, TView> filter;
|
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler<T> RoutingCollectionChanged;
|
|
||||||
public event Action<NotifyCollectionChangedAction> CollectionStateChanged;
|
|
||||||
|
|
||||||
public object SyncRoot { get; }
|
|
||||||
|
|
||||||
public View(IObservableCollection<T> source, Func<T, TView> selector, bool reverse)
|
|
||||||
{
|
|
||||||
this.source = source;
|
|
||||||
this.selector = selector;
|
|
||||||
this.reverse = reverse;
|
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
this.SyncRoot = new object();
|
|
||||||
lock (source.SyncRoot)
|
|
||||||
{
|
|
||||||
this.ringBuffer = new RingBuffer<(T, TView)>(source.Select(x => (x, selector(x))));
|
|
||||||
this.source.CollectionChanged += SourceCollectionChanged;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return ringBuffer.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = filter;
|
|
||||||
for (var i = 0; i < ringBuffer.Count; i++)
|
|
||||||
{
|
|
||||||
var (value, view) = ringBuffer[i];
|
|
||||||
if (invokeAddEventForCurrentElements)
|
|
||||||
{
|
|
||||||
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, i));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
filter.InvokeOnAttach(value, view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResetFilter(Action<T, TView> resetAction)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
if (resetAction != null)
|
|
||||||
{
|
|
||||||
foreach (var (item, view) in ringBuffer)
|
|
||||||
{
|
|
||||||
resetAction(item, view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedSynchronizedView<T, TView>(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<(T, TView)> GetEnumerator()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (!reverse)
|
|
||||||
{
|
|
||||||
foreach (var item in ringBuffer)
|
|
||||||
{
|
|
||||||
if (filter.IsMatch(item.Item1, item.Item2))
|
|
||||||
{
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var item in ringBuffer.AsEnumerable().Reverse())
|
|
||||||
{
|
|
||||||
if (filter.IsMatch(item.Item1, item.Item2))
|
|
||||||
{
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
this.source.CollectionChanged -= SourceCollectionChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SourceCollectionChanged(in NotifyCollectionChangedEventArgs<T> e)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
switch (e.Action)
|
|
||||||
{
|
|
||||||
case NotifyCollectionChangedAction.Add:
|
|
||||||
// can not distinguish AddFirst and AddLast when collection count is 0.
|
|
||||||
// So, in that case, use AddLast.
|
|
||||||
// The internal structure may be different from the parent, but the result is same.
|
|
||||||
// RangeOperation is only exists AddLastRange because we can not distinguish FirstRange or LastRange.
|
|
||||||
if (e.NewStartingIndex == 0 && ringBuffer.Count != 0)
|
|
||||||
{
|
|
||||||
// AddFirst
|
|
||||||
if (e.IsSingleItem)
|
|
||||||
{
|
|
||||||
var v = (e.NewItem, selector(e.NewItem));
|
|
||||||
ringBuffer.AddFirst(v);
|
|
||||||
filter.InvokeOnAdd(v, e);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var item in e.NewItems)
|
|
||||||
{
|
|
||||||
var v = (item, selector(item));
|
|
||||||
ringBuffer.AddFirst(v);
|
|
||||||
filter.InvokeOnAdd(v, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// AddLast
|
|
||||||
if (e.IsSingleItem)
|
|
||||||
{
|
|
||||||
var v = (e.NewItem, selector(e.NewItem));
|
|
||||||
ringBuffer.AddLast(v);
|
|
||||||
filter.InvokeOnAdd(v, e);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var item in e.NewItems)
|
|
||||||
{
|
|
||||||
var v = (item, selector(item));
|
|
||||||
ringBuffer.AddLast(v);
|
|
||||||
filter.InvokeOnAdd(v, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Remove:
|
|
||||||
// starting from 0 is RemoveFirst
|
|
||||||
if (e.OldStartingIndex == 0)
|
|
||||||
{
|
|
||||||
// RemoveFirst
|
|
||||||
if (e.IsSingleItem)
|
|
||||||
{
|
|
||||||
var v = ringBuffer.RemoveFirst();
|
|
||||||
filter.InvokeOnRemove(v, e);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < e.OldItems.Length; i++)
|
|
||||||
{
|
|
||||||
var v = ringBuffer.RemoveFirst();
|
|
||||||
filter.InvokeOnRemove(v, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// RemoveLast
|
|
||||||
if (e.IsSingleItem)
|
|
||||||
{
|
|
||||||
var v = ringBuffer.RemoveLast();
|
|
||||||
filter.InvokeOnRemove(v, e);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < e.OldItems.Length; i++)
|
|
||||||
{
|
|
||||||
var v = ringBuffer.RemoveLast();
|
|
||||||
filter.InvokeOnRemove(v, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Reset:
|
|
||||||
if (!filter.IsNullFilter())
|
|
||||||
{
|
|
||||||
foreach (var item in ringBuffer)
|
|
||||||
{
|
|
||||||
filter.InvokeOnRemove(item, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ringBuffer.Clear();
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Replace:
|
|
||||||
// range is not supported
|
|
||||||
{
|
|
||||||
var v = (e.NewItem, selector(e.NewItem));
|
|
||||||
|
|
||||||
var oldItem = ringBuffer[e.NewStartingIndex];
|
|
||||||
ringBuffer[e.NewStartingIndex] = v;
|
|
||||||
|
|
||||||
filter.InvokeOnRemove(oldItem, e);
|
|
||||||
filter.InvokeOnAdd(v, e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NotifyCollectionChangedAction.Move:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
RoutingCollectionChanged?.Invoke(e);
|
|
||||||
CollectionStateChanged?.Invoke(e.Action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 9a4b3308e0d0c4c4bafd65b41e7d66cd
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,236 +0,0 @@
|
|||||||
using ObservableCollections.Internal;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections;
|
|
||||||
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
public sealed partial class ObservableRingBuffer<T> : IList<T>, IReadOnlyList<T>, IObservableCollection<T>
|
|
||||||
{
|
|
||||||
readonly RingBuffer<T> buffer;
|
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler<T> CollectionChanged;
|
|
||||||
|
|
||||||
public ObservableRingBuffer()
|
|
||||||
{
|
|
||||||
this.buffer = new RingBuffer<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableRingBuffer(IEnumerable<T> collection)
|
|
||||||
{
|
|
||||||
this.buffer = new RingBuffer<T>(collection);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsReadOnly => false;
|
|
||||||
|
|
||||||
public object SyncRoot { get; } = new object();
|
|
||||||
|
|
||||||
public T this[int index]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return this.buffer[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var oldValue = buffer[index];
|
|
||||||
buffer[index] = value;
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Replace(value, oldValue, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return buffer.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddFirst(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
buffer.AddFirst(item);
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(item, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddLast(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
buffer.AddLast(item);
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(item, buffer.Count - 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T RemoveFirst()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var item = buffer.RemoveFirst();
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(item, 0));
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T RemoveLast()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var index = buffer.Count - 1;
|
|
||||||
var item = buffer.RemoveLast();
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(item, index));
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddFirstRange is not exists.
|
|
||||||
|
|
||||||
public void AddLastRange(IEnumerable<T> items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var index = buffer.Count;
|
|
||||||
using (var xs = new CloneCollection<T>(items))
|
|
||||||
{
|
|
||||||
foreach (var item in xs.Span)
|
|
||||||
{
|
|
||||||
buffer.AddLast(item);
|
|
||||||
}
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(xs.Span, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddLastRange(T[] items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var index = buffer.Count;
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
buffer.AddLast(item);
|
|
||||||
}
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(items, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddLastRange(ReadOnlySpan<T> items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var index = buffer.Count;
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
buffer.AddLast(item);
|
|
||||||
}
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(items, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int IndexOf(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return buffer.IndexOf(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IList<T>.Insert(int index, T item)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ICollection<T>.Remove(T item)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IList<T>.RemoveAt(int index)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ICollection<T>.Add(T item)
|
|
||||||
{
|
|
||||||
AddLast(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
buffer.Clear();
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Reset());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return buffer.Contains(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CopyTo(T[] array, int arrayIndex)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
buffer.CopyTo(array, arrayIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T[] ToArray()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return buffer.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int BinarySearch(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return buffer.BinarySearch(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int BinarySearch(T item, IComparer<T> comparer)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return buffer.BinarySearch(item, comparer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
foreach (var item in buffer)
|
|
||||||
{
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: c858015a9e82dc84487b3e627916a7ff
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,197 +0,0 @@
|
|||||||
using ObservableCollections.Internal;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
public sealed partial class ObservableStack<T> : IReadOnlyCollection<T>, IObservableCollection<T>
|
|
||||||
{
|
|
||||||
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false)
|
|
||||||
{
|
|
||||||
return new View<TView>(this, transform, reverse);
|
|
||||||
}
|
|
||||||
|
|
||||||
class View<TView> : ISynchronizedView<T, TView>
|
|
||||||
{
|
|
||||||
readonly ObservableStack<T> source;
|
|
||||||
readonly Func<T, TView> selector;
|
|
||||||
readonly bool reverse;
|
|
||||||
protected readonly Stack<(T, TView)> stack;
|
|
||||||
|
|
||||||
ISynchronizedViewFilter<T, TView> filter;
|
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler<T> RoutingCollectionChanged;
|
|
||||||
public event Action<NotifyCollectionChangedAction> CollectionStateChanged;
|
|
||||||
|
|
||||||
public object SyncRoot { get; }
|
|
||||||
|
|
||||||
public View(ObservableStack<T> source, Func<T, TView> selector, bool reverse)
|
|
||||||
{
|
|
||||||
this.source = source;
|
|
||||||
this.selector = selector;
|
|
||||||
this.reverse = reverse;
|
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
this.SyncRoot = new object();
|
|
||||||
lock (source.SyncRoot)
|
|
||||||
{
|
|
||||||
this.stack = new Stack<(T, TView)>(source.stack.Select(x => (x, selector(x))));
|
|
||||||
this.source.CollectionChanged += SourceCollectionChanged;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return stack.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = filter;
|
|
||||||
var i = 0;
|
|
||||||
foreach (var (value, view) in stack)
|
|
||||||
{
|
|
||||||
if (invokeAddEventForCurrentElements)
|
|
||||||
{
|
|
||||||
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, i));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
filter.InvokeOnAttach(value, view);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResetFilter(Action<T, TView> resetAction)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
|
||||||
if (resetAction != null)
|
|
||||||
{
|
|
||||||
foreach (var (item, view) in stack)
|
|
||||||
{
|
|
||||||
resetAction(item, view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return new NotifyCollectionChangedSynchronizedView<T, TView>(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<(T, TView)> GetEnumerator()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (!reverse)
|
|
||||||
{
|
|
||||||
foreach (var item in stack)
|
|
||||||
{
|
|
||||||
if (filter.IsMatch(item.Item1, item.Item2))
|
|
||||||
{
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var item in stack.AsEnumerable().Reverse())
|
|
||||||
{
|
|
||||||
if (filter.IsMatch(item.Item1, item.Item2))
|
|
||||||
{
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
this.source.CollectionChanged -= SourceCollectionChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SourceCollectionChanged(in NotifyCollectionChangedEventArgs<T> e)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
switch (e.Action)
|
|
||||||
{
|
|
||||||
case NotifyCollectionChangedAction.Add:
|
|
||||||
// Add(Push, PushRange)
|
|
||||||
if (e.IsSingleItem)
|
|
||||||
{
|
|
||||||
var v = (e.NewItem, selector(e.NewItem));
|
|
||||||
stack.Push(v);
|
|
||||||
filter.InvokeOnAdd(v, e);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var item in e.NewItems)
|
|
||||||
{
|
|
||||||
var v = (item, selector(item));
|
|
||||||
stack.Push(v);
|
|
||||||
filter.InvokeOnAdd(v, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Remove:
|
|
||||||
// Pop, PopRange
|
|
||||||
if (e.IsSingleItem)
|
|
||||||
{
|
|
||||||
var v = stack.Pop();
|
|
||||||
filter.InvokeOnRemove(v.Item1, v.Item2, e);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var len = e.OldItems.Length;
|
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
var v = stack.Pop();
|
|
||||||
filter.InvokeOnRemove(v.Item1, v.Item2, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Reset:
|
|
||||||
if (!filter.IsNullFilter())
|
|
||||||
{
|
|
||||||
foreach (var item in stack)
|
|
||||||
{
|
|
||||||
filter.InvokeOnRemove(item, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stack.Clear();
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Replace:
|
|
||||||
case NotifyCollectionChangedAction.Move:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
RoutingCollectionChanged?.Invoke(e);
|
|
||||||
CollectionStateChanged?.Invoke(e.Action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: bfc46ddd0f9e1e246931d87579f595b0
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,216 +0,0 @@
|
|||||||
using ObservableCollections.Internal;
|
|
||||||
using System;
|
|
||||||
using System.Buffers;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
public sealed partial class ObservableStack<T> : IReadOnlyCollection<T>, IObservableCollection<T>
|
|
||||||
{
|
|
||||||
readonly Stack<T> stack;
|
|
||||||
public object SyncRoot { get; } = new object();
|
|
||||||
|
|
||||||
public ObservableStack()
|
|
||||||
{
|
|
||||||
this.stack = new Stack<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableStack(int capacity)
|
|
||||||
{
|
|
||||||
this.stack = new Stack<T>(capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableStack(IEnumerable<T> collection)
|
|
||||||
{
|
|
||||||
this.stack = new Stack<T>(collection);
|
|
||||||
}
|
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler<T> CollectionChanged;
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return stack.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Push(T item)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var index = stack.Count;
|
|
||||||
stack.Push(item);
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(item, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PushRange(IEnumerable<T> items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
using (var xs = new CloneCollection<T>(items))
|
|
||||||
{
|
|
||||||
foreach (var item in xs.Span)
|
|
||||||
{
|
|
||||||
stack.Push(item);
|
|
||||||
}
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(xs.Span, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PushRange(T[] items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
stack.Push(item);
|
|
||||||
}
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(items, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PushRange(ReadOnlySpan<T> items)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
stack.Push(item);
|
|
||||||
}
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(items, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Pop()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var v = stack.Pop();
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(v, 0));
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryPop([MaybeNullWhen(false)] out T result)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (stack.Count != 0)
|
|
||||||
{
|
|
||||||
result = stack.Pop();
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(result, 0));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PopRange(int count)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
var dest = ArrayPool<T>.Shared.Rent(count);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
dest[i] = stack.Pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(dest.AsSpan(0, count), 0));
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(dest, RuntimeHelpersEx.IsReferenceOrContainsReferences<T>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PopRange(Span<T> dest)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < dest.Length; i++)
|
|
||||||
{
|
|
||||||
dest[i] = stack.Pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(dest, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
stack.Clear();
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Reset());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Peek()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return stack.Peek();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryPeek([MaybeNullWhen(false)] T result)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (stack.Count != 0)
|
|
||||||
{
|
|
||||||
result = stack.Peek();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
result = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T[] ToArray()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
return stack.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void TrimExcess()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
stack.TrimExcess();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator()
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
foreach (var item in stack)
|
|
||||||
{
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: e89128583a1ffee4babe861213e14be2
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,405 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace ObservableCollections
|
|
||||||
{
|
|
||||||
public sealed class RingBuffer<T> : IList<T>, IReadOnlyList<T>
|
|
||||||
{
|
|
||||||
T[] buffer;
|
|
||||||
int head;
|
|
||||||
int count;
|
|
||||||
int mask;
|
|
||||||
|
|
||||||
public RingBuffer()
|
|
||||||
{
|
|
||||||
this.buffer = new T[8];
|
|
||||||
this.head = 0;
|
|
||||||
this.count = 0;
|
|
||||||
this.mask = buffer.Length - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RingBuffer(int capacity)
|
|
||||||
{
|
|
||||||
this.buffer = new T[CalculateCapacity(capacity)];
|
|
||||||
this.head = 0;
|
|
||||||
this.count = 0;
|
|
||||||
this.mask = buffer.Length - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RingBuffer(IEnumerable<T> collection)
|
|
||||||
{
|
|
||||||
var array = collection.TryGetNonEnumeratedCount(out var count)
|
|
||||||
? new T[CalculateCapacity(count)]
|
|
||||||
: new T[8];
|
|
||||||
var i = 0;
|
|
||||||
foreach (var item in collection)
|
|
||||||
{
|
|
||||||
if (i == array.Length)
|
|
||||||
{
|
|
||||||
Array.Resize(ref array, i * 2);
|
|
||||||
}
|
|
||||||
array[i++] = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.buffer = array;
|
|
||||||
this.head = 0;
|
|
||||||
this.count = i;
|
|
||||||
this.mask = buffer.Length - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int CalculateCapacity(int size)
|
|
||||||
{
|
|
||||||
size--;
|
|
||||||
size |= size >> 1;
|
|
||||||
size |= size >> 2;
|
|
||||||
size |= size >> 4;
|
|
||||||
size |= size >> 8;
|
|
||||||
size |= size >> 16;
|
|
||||||
size += 1;
|
|
||||||
|
|
||||||
if (size < 8)
|
|
||||||
{
|
|
||||||
size = 8;
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T this[int index]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var i = (head + index) & mask;
|
|
||||||
return buffer[i];
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
var i = (head + index) & mask;
|
|
||||||
buffer[i] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count => count;
|
|
||||||
|
|
||||||
public bool IsReadOnly => false;
|
|
||||||
|
|
||||||
public void AddLast(T item)
|
|
||||||
{
|
|
||||||
if (count == buffer.Length) EnsureCapacity();
|
|
||||||
|
|
||||||
var index = (head + count) & mask;
|
|
||||||
buffer[index] = item;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddFirst(T item)
|
|
||||||
{
|
|
||||||
if (count == buffer.Length) EnsureCapacity();
|
|
||||||
|
|
||||||
head = (head - 1) & mask;
|
|
||||||
buffer[head] = item;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T RemoveLast()
|
|
||||||
{
|
|
||||||
if (count == 0) ThrowForEmpty();
|
|
||||||
|
|
||||||
var index = (head + count - 1) & mask;
|
|
||||||
var v = buffer[index];
|
|
||||||
buffer[index] = default;
|
|
||||||
count--;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T RemoveFirst()
|
|
||||||
{
|
|
||||||
if (count == 0) ThrowForEmpty();
|
|
||||||
|
|
||||||
var index = head & mask;
|
|
||||||
var v = buffer[index];
|
|
||||||
buffer[index] = default;
|
|
||||||
head = head + 1;
|
|
||||||
count--;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EnsureCapacity()
|
|
||||||
{
|
|
||||||
var newBuffer = new T[buffer.Length * 2];
|
|
||||||
|
|
||||||
var i = head & mask;
|
|
||||||
buffer.AsSpan(i).CopyTo(newBuffer);
|
|
||||||
|
|
||||||
if (i != 0)
|
|
||||||
{
|
|
||||||
buffer.AsSpan(0, i).CopyTo(newBuffer.AsSpan(buffer.Length - i));
|
|
||||||
}
|
|
||||||
|
|
||||||
head = 0;
|
|
||||||
buffer = newBuffer;
|
|
||||||
mask = newBuffer.Length - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ICollection<T>.Add(T item)
|
|
||||||
{
|
|
||||||
AddLast(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
Array.Clear(buffer, 0, buffer.Length);
|
|
||||||
head = 0;
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RingBufferSpan<T> GetSpan()
|
|
||||||
{
|
|
||||||
if (count == 0)
|
|
||||||
{
|
|
||||||
return new RingBufferSpan<T>(Array.Empty<T>(), Array.Empty<T>(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
var start = head & mask;
|
|
||||||
var end = (head + count) & mask;
|
|
||||||
|
|
||||||
if (end > start)
|
|
||||||
{
|
|
||||||
var first = buffer.AsSpan(start, count);
|
|
||||||
var second = Array.Empty<T>().AsSpan();
|
|
||||||
return new RingBufferSpan<T>(first, second, count);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var first = buffer.AsSpan(start, buffer.Length - start);
|
|
||||||
var second = buffer.AsSpan(0, end);
|
|
||||||
return new RingBufferSpan<T>(first, second, count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator()
|
|
||||||
{
|
|
||||||
if (count == 0) yield break;
|
|
||||||
|
|
||||||
var start = head & mask;
|
|
||||||
var end = (head + count) & mask;
|
|
||||||
|
|
||||||
if (end > start)
|
|
||||||
{
|
|
||||||
// start...end
|
|
||||||
for (int i = start; i < end; i++)
|
|
||||||
{
|
|
||||||
yield return buffer[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// start...
|
|
||||||
for (int i = start; i < buffer.Length; i++)
|
|
||||||
{
|
|
||||||
yield return buffer[i];
|
|
||||||
}
|
|
||||||
// 0...end
|
|
||||||
for (int i = 0; i < end; i++)
|
|
||||||
{
|
|
||||||
yield return buffer[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<T> Reverse()
|
|
||||||
{
|
|
||||||
if (count == 0) yield break;
|
|
||||||
|
|
||||||
var start = head & mask;
|
|
||||||
var end = (head + count) & mask;
|
|
||||||
|
|
||||||
if (end > start)
|
|
||||||
{
|
|
||||||
// end...start
|
|
||||||
for (int i = end - 1; i >= start; i--)
|
|
||||||
{
|
|
||||||
yield return buffer[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// end...0
|
|
||||||
for (int i = end - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
yield return buffer[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// ...start
|
|
||||||
for (int i = buffer.Length - 1; i >= start; i--)
|
|
||||||
{
|
|
||||||
yield return buffer[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains(T item)
|
|
||||||
{
|
|
||||||
return IndexOf(item) != -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CopyTo(T[] array, int arrayIndex)
|
|
||||||
{
|
|
||||||
var span = GetSpan();
|
|
||||||
var dest = array.AsSpan(arrayIndex);
|
|
||||||
span.First.CopyTo(dest);
|
|
||||||
span.Second.CopyTo(dest.Slice(span.First.Length));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int IndexOf(T item)
|
|
||||||
{
|
|
||||||
var i = 0;
|
|
||||||
foreach (var v in GetSpan())
|
|
||||||
{
|
|
||||||
if (EqualityComparer<T>.Default.Equals(item, v))
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T[] ToArray()
|
|
||||||
{
|
|
||||||
var result = new T[count];
|
|
||||||
var i = 0;
|
|
||||||
foreach (var item in GetSpan())
|
|
||||||
{
|
|
||||||
result[i++] = item;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int BinarySearch(T item)
|
|
||||||
{
|
|
||||||
return BinarySearch(item, Comparer<T>.Default);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int BinarySearch(T item, IComparer<T> comparer)
|
|
||||||
{
|
|
||||||
var lo = 0;
|
|
||||||
var hi = count - 1;
|
|
||||||
|
|
||||||
while (lo <= hi)
|
|
||||||
{
|
|
||||||
var mid = (int)(((uint)hi + (uint)lo) >> 1);
|
|
||||||
var found = comparer.Compare(this[mid], item);
|
|
||||||
|
|
||||||
if (found == 0) return mid;
|
|
||||||
if (found < 0)
|
|
||||||
{
|
|
||||||
lo = mid + 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hi = mid - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ~lo;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IList<T>.Insert(int index, T item)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ICollection<T>.Remove(T item)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IList<T>.RemoveAt(int index)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return ((IEnumerable<T>)this).GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
[DoesNotReturn]
|
|
||||||
static void ThrowForEmpty()
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("RingBuffer is empty.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ref struct RingBufferSpan<T>
|
|
||||||
{
|
|
||||||
public readonly ReadOnlySpan<T> First;
|
|
||||||
public readonly ReadOnlySpan<T> Second;
|
|
||||||
public readonly int Count;
|
|
||||||
|
|
||||||
internal RingBufferSpan(ReadOnlySpan<T> first, ReadOnlySpan<T> second, int count)
|
|
||||||
{
|
|
||||||
First = first;
|
|
||||||
Second = second;
|
|
||||||
Count = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Enumerator GetEnumerator()
|
|
||||||
{
|
|
||||||
return new Enumerator(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ref struct Enumerator
|
|
||||||
{
|
|
||||||
ReadOnlySpan<T>.Enumerator firstEnumerator;
|
|
||||||
ReadOnlySpan<T>.Enumerator secondEnumerator;
|
|
||||||
bool useFirst;
|
|
||||||
|
|
||||||
public Enumerator(RingBufferSpan<T> span)
|
|
||||||
{
|
|
||||||
this.firstEnumerator = span.First.GetEnumerator();
|
|
||||||
this.secondEnumerator = span.Second.GetEnumerator();
|
|
||||||
this.useFirst = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool MoveNext()
|
|
||||||
{
|
|
||||||
if (useFirst)
|
|
||||||
{
|
|
||||||
if (firstEnumerator.MoveNext())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
useFirst = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (secondEnumerator.MoveNext())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Current
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (useFirst)
|
|
||||||
{
|
|
||||||
return firstEnumerator.Current;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return secondEnumerator.Current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 090e1b8528f51164695f1ed11c685465
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 8c8f516891f9df44a847a0bb51a064f0
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,64 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace System.Collections.Generic
|
|
||||||
{
|
|
||||||
internal static class CollectionExtensions
|
|
||||||
{
|
|
||||||
public static void Deconstruct<TKey, TValue>(this KeyValuePair<TKey, TValue> kvp, out TKey key, out TValue value)
|
|
||||||
{
|
|
||||||
key = kvp.Key;
|
|
||||||
value = kvp.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool Remove<TKey, TValue>(this SortedDictionary<TKey, TValue> dict, TKey key, out TValue value)
|
|
||||||
{
|
|
||||||
if (dict.TryGetValue(key, out value))
|
|
||||||
{
|
|
||||||
return dict.Remove(key);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool Remove<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, out TValue value)
|
|
||||||
{
|
|
||||||
if (dict.TryGetValue(key, out value))
|
|
||||||
{
|
|
||||||
return dict.Remove(key);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !NET6_0_OR_GREATER
|
|
||||||
|
|
||||||
public static bool TryGetNonEnumeratedCount<T>(this IEnumerable<T> source, out int count)
|
|
||||||
{
|
|
||||||
if (source is ICollection<T> collection)
|
|
||||||
{
|
|
||||||
count = collection.Count;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (source is IReadOnlyCollection<T> rCollection)
|
|
||||||
{
|
|
||||||
count = rCollection.Count;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
count = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !NET5_0_OR_GREATER
|
|
||||||
|
|
||||||
internal interface IReadOnlySet<T> : System.Collections.Generic.IEnumerable<T>, System.Collections.Generic.IReadOnlyCollection<T>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 02ab78c5678c3bd4ebb45ca99fa0eaea
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,18 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace System.Runtime.CompilerServices
|
|
||||||
{
|
|
||||||
internal static class RuntimeHelpersEx
|
|
||||||
{
|
|
||||||
internal static bool IsReferenceOrContainsReferences<T>()
|
|
||||||
{
|
|
||||||
#if NETSTANDARD2_0 || NET_STANDARD_2_0 || NET_4_6
|
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
return RuntimeHelpers.IsReferenceOrContainsReferences<T>();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 90c6c97d9daed56458c4b0f69217c442
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,24 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
#if NETSTANDARD2_0 || NET_STANDARD_2_0 || NET_4_6
|
|
||||||
|
|
||||||
namespace System.Diagnostics.CodeAnalysis
|
|
||||||
{
|
|
||||||
internal sealed class MaybeNullWhenAttribute : Attribute
|
|
||||||
{
|
|
||||||
public MaybeNullWhenAttribute(bool returnValue)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal sealed class DoesNotReturnAttribute : Attribute
|
|
||||||
{
|
|
||||||
public DoesNotReturnAttribute()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 2b96ddbca917d2749a613d7dff847f37
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "com.cysharp.observablecollections",
|
|
||||||
"displayName": "ObservableCollections",
|
|
||||||
"author": { "name": "Cysharp, Inc.", "url": "https://cysharp.co.jp/en/" },
|
|
||||||
"version": "1.1.3",
|
|
||||||
"unity": "2018.4",
|
|
||||||
"description": "High performance observable collections and synchronized views.",
|
|
||||||
"keywords": [ "Scripting", "DI" ],
|
|
||||||
"license": "MIT",
|
|
||||||
"category": "Scripting",
|
|
||||||
"dependencies": {}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 142803aeb06678d4faef8b76468c110b
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
Binary file not shown.
@ -1,33 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 80babde185fa5f5f58e1c7c451054bf5
|
|
||||||
PluginImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
iconMap: {}
|
|
||||||
executionOrder: {}
|
|
||||||
defineConstraints: []
|
|
||||||
isPreloaded: 0
|
|
||||||
isOverridable: 0
|
|
||||||
isExplicitlyReferenced: 0
|
|
||||||
validateReferences: 1
|
|
||||||
platformData:
|
|
||||||
- first:
|
|
||||||
Any:
|
|
||||||
second:
|
|
||||||
enabled: 1
|
|
||||||
settings: {}
|
|
||||||
- first:
|
|
||||||
Editor: Editor
|
|
||||||
second:
|
|
||||||
enabled: 0
|
|
||||||
settings:
|
|
||||||
DefaultValueInitialized: true
|
|
||||||
- first:
|
|
||||||
Windows Store Apps: WindowsStoreApps
|
|
||||||
second:
|
|
||||||
enabled: 0
|
|
||||||
settings:
|
|
||||||
CPU: AnyCPU
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
Binary file not shown.
@ -1,33 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 00334fc99a0c324ce9667086377aec59
|
|
||||||
PluginImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
iconMap: {}
|
|
||||||
executionOrder: {}
|
|
||||||
defineConstraints: []
|
|
||||||
isPreloaded: 0
|
|
||||||
isOverridable: 0
|
|
||||||
isExplicitlyReferenced: 0
|
|
||||||
validateReferences: 1
|
|
||||||
platformData:
|
|
||||||
- first:
|
|
||||||
Any:
|
|
||||||
second:
|
|
||||||
enabled: 1
|
|
||||||
settings: {}
|
|
||||||
- first:
|
|
||||||
Editor: Editor
|
|
||||||
second:
|
|
||||||
enabled: 0
|
|
||||||
settings:
|
|
||||||
DefaultValueInitialized: true
|
|
||||||
- first:
|
|
||||||
Windows Store Apps: WindowsStoreApps
|
|
||||||
second:
|
|
||||||
enabled: 0
|
|
||||||
settings:
|
|
||||||
CPU: AnyCPU
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
Binary file not shown.
@ -1,33 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 9faef98abc153627f8af30123e43611c
|
|
||||||
PluginImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
iconMap: {}
|
|
||||||
executionOrder: {}
|
|
||||||
defineConstraints: []
|
|
||||||
isPreloaded: 0
|
|
||||||
isOverridable: 0
|
|
||||||
isExplicitlyReferenced: 0
|
|
||||||
validateReferences: 1
|
|
||||||
platformData:
|
|
||||||
- first:
|
|
||||||
Any:
|
|
||||||
second:
|
|
||||||
enabled: 1
|
|
||||||
settings: {}
|
|
||||||
- first:
|
|
||||||
Editor: Editor
|
|
||||||
second:
|
|
||||||
enabled: 0
|
|
||||||
settings:
|
|
||||||
DefaultValueInitialized: true
|
|
||||||
- first:
|
|
||||||
Windows Store Apps: WindowsStoreApps
|
|
||||||
second:
|
|
||||||
enabled: 0
|
|
||||||
settings:
|
|
||||||
CPU: AnyCPU
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 0bc06841af72151429ea8e5bff9677a0
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,197 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!1 &1956618470265689906
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 618331874408718809}
|
|
||||||
- component: {fileID: 7969674051040476341}
|
|
||||||
- component: {fileID: 3304697755884386642}
|
|
||||||
m_Layer: 5
|
|
||||||
m_Name: Text
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!224 &618331874408718809
|
|
||||||
RectTransform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 1956618470265689906}
|
|
||||||
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_Children: []
|
|
||||||
m_Father: {fileID: 5255390928395226544}
|
|
||||||
m_RootOrder: 0
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
m_AnchorMin: {x: 0, y: 0}
|
|
||||||
m_AnchorMax: {x: 1, y: 1}
|
|
||||||
m_AnchoredPosition: {x: 0, y: 0}
|
|
||||||
m_SizeDelta: {x: 0, y: 0}
|
|
||||||
m_Pivot: {x: 0.5, y: 0.5}
|
|
||||||
--- !u!222 &7969674051040476341
|
|
||||||
CanvasRenderer:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 1956618470265689906}
|
|
||||||
m_CullTransparentMesh: 0
|
|
||||||
--- !u!114 &3304697755884386642
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 1956618470265689906}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
m_Material: {fileID: 0}
|
|
||||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
|
||||||
m_RaycastTarget: 1
|
|
||||||
m_OnCullStateChanged:
|
|
||||||
m_PersistentCalls:
|
|
||||||
m_Calls: []
|
|
||||||
m_FontData:
|
|
||||||
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
|
||||||
m_FontSize: 14
|
|
||||||
m_FontStyle: 0
|
|
||||||
m_BestFit: 0
|
|
||||||
m_MinSize: 10
|
|
||||||
m_MaxSize: 40
|
|
||||||
m_Alignment: 4
|
|
||||||
m_AlignByGeometry: 0
|
|
||||||
m_RichText: 1
|
|
||||||
m_HorizontalOverflow: 0
|
|
||||||
m_VerticalOverflow: 0
|
|
||||||
m_LineSpacing: 1
|
|
||||||
m_Text: Button
|
|
||||||
--- !u!1 &8295906003645589311
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 5255390928395226544}
|
|
||||||
- component: {fileID: 8560960181737511060}
|
|
||||||
- component: {fileID: 6330597562278295799}
|
|
||||||
- component: {fileID: 2332625603231720647}
|
|
||||||
m_Layer: 5
|
|
||||||
m_Name: Button
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!224 &5255390928395226544
|
|
||||||
RectTransform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 8295906003645589311}
|
|
||||||
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_Children:
|
|
||||||
- {fileID: 618331874408718809}
|
|
||||||
m_Father: {fileID: 0}
|
|
||||||
m_RootOrder: 0
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
m_AnchorMin: {x: 0, y: 0}
|
|
||||||
m_AnchorMax: {x: 0, y: 0}
|
|
||||||
m_AnchoredPosition: {x: 0, y: 0}
|
|
||||||
m_SizeDelta: {x: 160, y: 30}
|
|
||||||
m_Pivot: {x: 0.5, y: 0.5}
|
|
||||||
--- !u!222 &8560960181737511060
|
|
||||||
CanvasRenderer:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 8295906003645589311}
|
|
||||||
m_CullTransparentMesh: 0
|
|
||||||
--- !u!114 &6330597562278295799
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 8295906003645589311}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
m_Material: {fileID: 0}
|
|
||||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
|
||||||
m_RaycastTarget: 1
|
|
||||||
m_OnCullStateChanged:
|
|
||||||
m_PersistentCalls:
|
|
||||||
m_Calls: []
|
|
||||||
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
m_Type: 1
|
|
||||||
m_PreserveAspect: 0
|
|
||||||
m_FillCenter: 1
|
|
||||||
m_FillMethod: 4
|
|
||||||
m_FillAmount: 1
|
|
||||||
m_FillClockwise: 1
|
|
||||||
m_FillOrigin: 0
|
|
||||||
m_UseSpriteMesh: 0
|
|
||||||
m_PixelsPerUnitMultiplier: 1
|
|
||||||
--- !u!114 &2332625603231720647
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 8295906003645589311}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
m_Navigation:
|
|
||||||
m_Mode: 3
|
|
||||||
m_SelectOnUp: {fileID: 0}
|
|
||||||
m_SelectOnDown: {fileID: 0}
|
|
||||||
m_SelectOnLeft: {fileID: 0}
|
|
||||||
m_SelectOnRight: {fileID: 0}
|
|
||||||
m_Transition: 1
|
|
||||||
m_Colors:
|
|
||||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
|
||||||
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_ColorMultiplier: 1
|
|
||||||
m_FadeDuration: 0.1
|
|
||||||
m_SpriteState:
|
|
||||||
m_HighlightedSprite: {fileID: 0}
|
|
||||||
m_PressedSprite: {fileID: 0}
|
|
||||||
m_SelectedSprite: {fileID: 0}
|
|
||||||
m_DisabledSprite: {fileID: 0}
|
|
||||||
m_AnimationTriggers:
|
|
||||||
m_NormalTrigger: Normal
|
|
||||||
m_HighlightedTrigger: Highlighted
|
|
||||||
m_PressedTrigger: Pressed
|
|
||||||
m_SelectedTrigger: Selected
|
|
||||||
m_DisabledTrigger: Disabled
|
|
||||||
m_Interactable: 1
|
|
||||||
m_TargetGraphic: {fileID: 6330597562278295799}
|
|
||||||
m_OnClick:
|
|
||||||
m_PersistentCalls:
|
|
||||||
m_Calls: []
|
|
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 7a021aee34791a94f83af413a3ade50c
|
|
||||||
PrefabImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 2cda990e2423bbf4892e6590ba056729
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,78 +0,0 @@
|
|||||||
using ObservableCollections;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.UI;
|
|
||||||
|
|
||||||
public class SampleScript : MonoBehaviour
|
|
||||||
{
|
|
||||||
public Button prefab;
|
|
||||||
public GameObject root;
|
|
||||||
|
|
||||||
public Button add;
|
|
||||||
public Button remove;
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
void Start()
|
|
||||||
{
|
|
||||||
var oc = new ObservableRingBuffer<int>();
|
|
||||||
|
|
||||||
var view = oc.CreateView(x =>
|
|
||||||
{
|
|
||||||
var item = GameObject.Instantiate(prefab);
|
|
||||||
item.GetComponentInChildren<Text>().text = x.ToString();
|
|
||||||
return item.gameObject;
|
|
||||||
});
|
|
||||||
view.AttachFilter(new GameObjectFilter(root));
|
|
||||||
|
|
||||||
add.onClick.AddListener(() =>
|
|
||||||
{
|
|
||||||
oc.AddLast(i++);
|
|
||||||
});
|
|
||||||
|
|
||||||
remove.onClick.AddListener(() =>
|
|
||||||
{
|
|
||||||
oc.RemoveFirst();
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GameObjectFilter : ISynchronizedViewFilter<int, GameObject>
|
|
||||||
{
|
|
||||||
readonly GameObject root;
|
|
||||||
|
|
||||||
public GameObjectFilter(GameObject root)
|
|
||||||
{
|
|
||||||
this.root = root;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCollectionChanged(ChangedKind changedKind, int value, GameObject view, in NotifyCollectionChangedEventArgs<int> eventArgs)
|
|
||||||
{
|
|
||||||
if (changedKind == ChangedKind.Add)
|
|
||||||
{
|
|
||||||
view.transform.SetParent(root.transform);
|
|
||||||
}
|
|
||||||
else if (changedKind == ChangedKind.Remove)
|
|
||||||
{
|
|
||||||
GameObject.Destroy(view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsMatch(int value, GameObject view)
|
|
||||||
{
|
|
||||||
return value % 2 == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WhenTrue(int value, GameObject view)
|
|
||||||
{
|
|
||||||
view.SetActive(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WhenFalse(int value, GameObject view)
|
|
||||||
{
|
|
||||||
view.SetActive(false);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: e89d460dcf6b5db44a0e995732078819
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,43 +0,0 @@
|
|||||||
{
|
|
||||||
"dependencies": {
|
|
||||||
"com.unity.collab-proxy": "1.2.16",
|
|
||||||
"com.unity.ext.nunit": "1.0.0",
|
|
||||||
"com.unity.ide.rider": "1.1.0",
|
|
||||||
"com.unity.ide.vscode": "1.1.0",
|
|
||||||
"com.unity.test-framework": "1.1.1",
|
|
||||||
"com.unity.textmeshpro": "2.0.1",
|
|
||||||
"com.unity.timeline": "1.2.2",
|
|
||||||
"com.unity.ugui": "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.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"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!11 &1
|
|
||||||
AudioManager:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Volume: 1
|
|
||||||
Rolloff Scale: 1
|
|
||||||
Doppler Factor: 1
|
|
||||||
Default Speaker Mode: 2
|
|
||||||
m_SampleRate: 0
|
|
||||||
m_DSPBufferSize: 1024
|
|
||||||
m_VirtualVoiceCount: 512
|
|
||||||
m_RealVoiceCount: 32
|
|
||||||
m_SpatializerPlugin:
|
|
||||||
m_AmbisonicDecoderPlugin:
|
|
||||||
m_DisableAudio: 0
|
|
||||||
m_VirtualizeEffects: 1
|
|
||||||
m_RequestedDSPBufferSize: 0
|
|
@ -1,6 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!236 &1
|
|
||||||
ClusterInputManager:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_Inputs: []
|
|
@ -1,36 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!55 &1
|
|
||||||
PhysicsManager:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
serializedVersion: 13
|
|
||||||
m_Gravity: {x: 0, y: -9.81, z: 0}
|
|
||||||
m_DefaultMaterial: {fileID: 0}
|
|
||||||
m_BounceThreshold: 2
|
|
||||||
m_SleepThreshold: 0.005
|
|
||||||
m_DefaultContactOffset: 0.01
|
|
||||||
m_DefaultSolverIterations: 6
|
|
||||||
m_DefaultSolverVelocityIterations: 1
|
|
||||||
m_QueriesHitBackfaces: 0
|
|
||||||
m_QueriesHitTriggers: 1
|
|
||||||
m_EnableAdaptiveForce: 0
|
|
||||||
m_ClothInterCollisionDistance: 0.1
|
|
||||||
m_ClothInterCollisionStiffness: 0.2
|
|
||||||
m_ContactsGeneration: 1
|
|
||||||
m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
||||||
m_AutoSimulation: 1
|
|
||||||
m_AutoSyncTransforms: 0
|
|
||||||
m_ReuseCollisionCallbacks: 1
|
|
||||||
m_ClothInterCollisionSettingsToggle: 0
|
|
||||||
m_ClothGravity: {x: 0, y: -9.81, z: 0}
|
|
||||||
m_ContactPairsMode: 0
|
|
||||||
m_BroadphaseType: 0
|
|
||||||
m_WorldBounds:
|
|
||||||
m_Center: {x: 0, y: 0, z: 0}
|
|
||||||
m_Extent: {x: 250, y: 250, z: 250}
|
|
||||||
m_WorldSubdivisions: 8
|
|
||||||
m_FrictionType: 0
|
|
||||||
m_EnableEnhancedDeterminism: 0
|
|
||||||
m_EnableUnifiedHeightmaps: 1
|
|
||||||
m_SolverType: 0
|
|
||||||
m_DefaultMaxAngularSpeed: 50
|
|
@ -1,11 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!1045 &1
|
|
||||||
EditorBuildSettings:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Scenes:
|
|
||||||
- enabled: 1
|
|
||||||
path: Assets/Scenes/SampleScene.unity
|
|
||||||
guid: 2cda990e2423bbf4892e6590ba056729
|
|
||||||
m_configObjects: {}
|
|
@ -1,36 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!159 &1
|
|
||||||
EditorSettings:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
serializedVersion: 10
|
|
||||||
m_ExternalVersionControlSupport: Visible Meta Files
|
|
||||||
m_SerializationMode: 2
|
|
||||||
m_LineEndingsForNewScripts: 0
|
|
||||||
m_DefaultBehaviorMode: 1
|
|
||||||
m_PrefabRegularEnvironment: {fileID: 0}
|
|
||||||
m_PrefabUIEnvironment: {fileID: 0}
|
|
||||||
m_SpritePackerMode: 4
|
|
||||||
m_SpritePackerPaddingPower: 1
|
|
||||||
m_EtcTextureCompressorBehavior: 1
|
|
||||||
m_EtcTextureFastCompressor: 1
|
|
||||||
m_EtcTextureNormalCompressor: 2
|
|
||||||
m_EtcTextureBestCompressor: 4
|
|
||||||
m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;asmref;rsp
|
|
||||||
m_ProjectGenerationRootNamespace:
|
|
||||||
m_CollabEditorSettings:
|
|
||||||
inProgressEnabled: 1
|
|
||||||
m_EnableTextureStreamingInEditMode: 1
|
|
||||||
m_EnableTextureStreamingInPlayMode: 1
|
|
||||||
m_AsyncShaderCompilation: 1
|
|
||||||
m_EnterPlayModeOptionsEnabled: 0
|
|
||||||
m_EnterPlayModeOptions: 3
|
|
||||||
m_ShowLightmapResolutionOverlay: 1
|
|
||||||
m_UseLegacyProbeSampleCount: 0
|
|
||||||
m_SerializeInlineMappingsOnOneLine: 1
|
|
||||||
m_AssetPipelineMode: 1
|
|
||||||
m_CacheServerMode: 0
|
|
||||||
m_CacheServerEndpoint:
|
|
||||||
m_CacheServerNamespacePrefix: default
|
|
||||||
m_CacheServerEnableDownload: 1
|
|
||||||
m_CacheServerEnableUpload: 1
|
|
@ -1,63 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!30 &1
|
|
||||||
GraphicsSettings:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
serializedVersion: 13
|
|
||||||
m_Deferred:
|
|
||||||
m_Mode: 1
|
|
||||||
m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
m_DeferredReflections:
|
|
||||||
m_Mode: 1
|
|
||||||
m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
m_ScreenSpaceShadows:
|
|
||||||
m_Mode: 1
|
|
||||||
m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
m_LegacyDeferred:
|
|
||||||
m_Mode: 1
|
|
||||||
m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
m_DepthNormals:
|
|
||||||
m_Mode: 1
|
|
||||||
m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
m_MotionVectors:
|
|
||||||
m_Mode: 1
|
|
||||||
m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
m_LightHalo:
|
|
||||||
m_Mode: 1
|
|
||||||
m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
m_LensFlare:
|
|
||||||
m_Mode: 1
|
|
||||||
m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
m_VideoShadersIncludeMode: 2
|
|
||||||
m_AlwaysIncludedShaders:
|
|
||||||
- {fileID: 7, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
- {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
- {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
- {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
- {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
- {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
- {fileID: 10783, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
m_PreloadedShaders: []
|
|
||||||
m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
m_CustomRenderPipeline: {fileID: 0}
|
|
||||||
m_TransparencySortMode: 0
|
|
||||||
m_TransparencySortAxis: {x: 0, y: 0, z: 1}
|
|
||||||
m_DefaultRenderingPath: 1
|
|
||||||
m_DefaultMobileRenderingPath: 1
|
|
||||||
m_TierSettings: []
|
|
||||||
m_LightmapStripping: 0
|
|
||||||
m_FogStripping: 0
|
|
||||||
m_InstancingStripping: 0
|
|
||||||
m_LightmapKeepPlain: 1
|
|
||||||
m_LightmapKeepDirCombined: 1
|
|
||||||
m_LightmapKeepDynamicPlain: 1
|
|
||||||
m_LightmapKeepDynamicDirCombined: 1
|
|
||||||
m_LightmapKeepShadowMask: 1
|
|
||||||
m_LightmapKeepSubtractive: 1
|
|
||||||
m_FogKeepLinear: 1
|
|
||||||
m_FogKeepExp: 1
|
|
||||||
m_FogKeepExp2: 1
|
|
||||||
m_AlbedoSwatchInfos: []
|
|
||||||
m_LightsUseLinearIntensity: 0
|
|
||||||
m_LightsUseColorTemperature: 0
|
|
||||||
m_LogWhenShaderIsCompiled: 0
|
|
@ -1,487 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!13 &1
|
|
||||||
InputManager:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Axes:
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Horizontal
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton: left
|
|
||||||
positiveButton: right
|
|
||||||
altNegativeButton: a
|
|
||||||
altPositiveButton: d
|
|
||||||
gravity: 3
|
|
||||||
dead: 0.001
|
|
||||||
sensitivity: 3
|
|
||||||
snap: 1
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Vertical
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton: down
|
|
||||||
positiveButton: up
|
|
||||||
altNegativeButton: s
|
|
||||||
altPositiveButton: w
|
|
||||||
gravity: 3
|
|
||||||
dead: 0.001
|
|
||||||
sensitivity: 3
|
|
||||||
snap: 1
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Fire1
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton: left ctrl
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton: mouse 0
|
|
||||||
gravity: 1000
|
|
||||||
dead: 0.001
|
|
||||||
sensitivity: 1000
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Fire2
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton: left alt
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton: mouse 1
|
|
||||||
gravity: 1000
|
|
||||||
dead: 0.001
|
|
||||||
sensitivity: 1000
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Fire3
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton: left shift
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton: mouse 2
|
|
||||||
gravity: 1000
|
|
||||||
dead: 0.001
|
|
||||||
sensitivity: 1000
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Jump
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton: space
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton:
|
|
||||||
gravity: 1000
|
|
||||||
dead: 0.001
|
|
||||||
sensitivity: 1000
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Mouse X
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton:
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton:
|
|
||||||
gravity: 0
|
|
||||||
dead: 0
|
|
||||||
sensitivity: 0.1
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 1
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Mouse Y
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton:
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton:
|
|
||||||
gravity: 0
|
|
||||||
dead: 0
|
|
||||||
sensitivity: 0.1
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 1
|
|
||||||
axis: 1
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Mouse ScrollWheel
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton:
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton:
|
|
||||||
gravity: 0
|
|
||||||
dead: 0
|
|
||||||
sensitivity: 0.1
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 1
|
|
||||||
axis: 2
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Horizontal
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton:
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton:
|
|
||||||
gravity: 0
|
|
||||||
dead: 0.19
|
|
||||||
sensitivity: 1
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 2
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Vertical
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton:
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton:
|
|
||||||
gravity: 0
|
|
||||||
dead: 0.19
|
|
||||||
sensitivity: 1
|
|
||||||
snap: 0
|
|
||||||
invert: 1
|
|
||||||
type: 2
|
|
||||||
axis: 1
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Fire1
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton: joystick button 0
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton:
|
|
||||||
gravity: 1000
|
|
||||||
dead: 0.001
|
|
||||||
sensitivity: 1000
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Fire2
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton: joystick button 1
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton:
|
|
||||||
gravity: 1000
|
|
||||||
dead: 0.001
|
|
||||||
sensitivity: 1000
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Fire3
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton: joystick button 2
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton:
|
|
||||||
gravity: 1000
|
|
||||||
dead: 0.001
|
|
||||||
sensitivity: 1000
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Jump
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton: joystick button 3
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton:
|
|
||||||
gravity: 1000
|
|
||||||
dead: 0.001
|
|
||||||
sensitivity: 1000
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Submit
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton: return
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton: joystick button 0
|
|
||||||
gravity: 1000
|
|
||||||
dead: 0.001
|
|
||||||
sensitivity: 1000
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Submit
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton: enter
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton: space
|
|
||||||
gravity: 1000
|
|
||||||
dead: 0.001
|
|
||||||
sensitivity: 1000
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Cancel
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton: escape
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton: joystick button 1
|
|
||||||
gravity: 1000
|
|
||||||
dead: 0.001
|
|
||||||
sensitivity: 1000
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Enable Debug Button 1
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton: left ctrl
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton: joystick button 8
|
|
||||||
gravity: 0
|
|
||||||
dead: 0
|
|
||||||
sensitivity: 0
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Enable Debug Button 2
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton: backspace
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton: joystick button 9
|
|
||||||
gravity: 0
|
|
||||||
dead: 0
|
|
||||||
sensitivity: 0
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Debug Reset
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton: left alt
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton: joystick button 1
|
|
||||||
gravity: 0
|
|
||||||
dead: 0
|
|
||||||
sensitivity: 0
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Debug Next
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton: page down
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton: joystick button 5
|
|
||||||
gravity: 0
|
|
||||||
dead: 0
|
|
||||||
sensitivity: 0
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Debug Previous
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton: page up
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton: joystick button 4
|
|
||||||
gravity: 0
|
|
||||||
dead: 0
|
|
||||||
sensitivity: 0
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Debug Validate
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton: return
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton: joystick button 0
|
|
||||||
gravity: 0
|
|
||||||
dead: 0
|
|
||||||
sensitivity: 0
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Debug Persistent
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton: right shift
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton: joystick button 2
|
|
||||||
gravity: 0
|
|
||||||
dead: 0
|
|
||||||
sensitivity: 0
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Debug Multiplier
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton:
|
|
||||||
positiveButton: left shift
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton: joystick button 3
|
|
||||||
gravity: 0
|
|
||||||
dead: 0
|
|
||||||
sensitivity: 0
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Debug Horizontal
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton: left
|
|
||||||
positiveButton: right
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton:
|
|
||||||
gravity: 1000
|
|
||||||
dead: 0.001
|
|
||||||
sensitivity: 1000
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Debug Vertical
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton: down
|
|
||||||
positiveButton: up
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton:
|
|
||||||
gravity: 1000
|
|
||||||
dead: 0.001
|
|
||||||
sensitivity: 1000
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 0
|
|
||||||
axis: 0
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Debug Vertical
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton: down
|
|
||||||
positiveButton: up
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton:
|
|
||||||
gravity: 1000
|
|
||||||
dead: 0.001
|
|
||||||
sensitivity: 1000
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 2
|
|
||||||
axis: 6
|
|
||||||
joyNum: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
m_Name: Debug Horizontal
|
|
||||||
descriptiveName:
|
|
||||||
descriptiveNegativeName:
|
|
||||||
negativeButton: left
|
|
||||||
positiveButton: right
|
|
||||||
altNegativeButton:
|
|
||||||
altPositiveButton:
|
|
||||||
gravity: 1000
|
|
||||||
dead: 0.001
|
|
||||||
sensitivity: 1000
|
|
||||||
snap: 0
|
|
||||||
invert: 0
|
|
||||||
type: 2
|
|
||||||
axis: 5
|
|
||||||
joyNum: 0
|
|
@ -1,91 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!126 &1
|
|
||||||
NavMeshProjectSettings:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
serializedVersion: 2
|
|
||||||
areas:
|
|
||||||
- name: Walkable
|
|
||||||
cost: 1
|
|
||||||
- name: Not Walkable
|
|
||||||
cost: 1
|
|
||||||
- name: Jump
|
|
||||||
cost: 2
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
- name:
|
|
||||||
cost: 1
|
|
||||||
m_LastAgentTypeID: -887442657
|
|
||||||
m_Settings:
|
|
||||||
- serializedVersion: 2
|
|
||||||
agentTypeID: 0
|
|
||||||
agentRadius: 0.5
|
|
||||||
agentHeight: 2
|
|
||||||
agentSlope: 45
|
|
||||||
agentClimb: 0.75
|
|
||||||
ledgeDropHeight: 0
|
|
||||||
maxJumpAcrossDistance: 0
|
|
||||||
minRegionArea: 2
|
|
||||||
manualCellSize: 0
|
|
||||||
cellSize: 0.16666667
|
|
||||||
manualTileSize: 0
|
|
||||||
tileSize: 256
|
|
||||||
accuratePlacement: 0
|
|
||||||
debug:
|
|
||||||
m_Flags: 0
|
|
||||||
m_SettingNames:
|
|
||||||
- Humanoid
|
|
@ -1,8 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!149 &1
|
|
||||||
NetworkManager:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_DebugLevel: 0
|
|
||||||
m_Sendrate: 15
|
|
||||||
m_AssetToPrefab: {}
|
|
@ -1,43 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!114 &1
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 61
|
|
||||||
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: 13964, guid: 0000000000000000e000000000000000, type: 0}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
m_EnablePreviewPackages: 0
|
|
||||||
m_EnablePackageDependencies: 0
|
|
||||||
m_AdvancedSettingsExpanded: 1
|
|
||||||
m_ScopedRegistriesSettingsExpanded: 1
|
|
||||||
oneTimeWarningShown: 0
|
|
||||||
m_Registries:
|
|
||||||
- m_Id: main
|
|
||||||
m_Name:
|
|
||||||
m_Url: https://packages.unity.com
|
|
||||||
m_Scopes: []
|
|
||||||
m_IsDefault: 1
|
|
||||||
m_Capabilities: 7
|
|
||||||
m_UserSelectedRegistryName:
|
|
||||||
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
|
|
@ -1,56 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!19 &1
|
|
||||||
Physics2DSettings:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
serializedVersion: 5
|
|
||||||
m_Gravity: {x: 0, y: -9.81}
|
|
||||||
m_DefaultMaterial: {fileID: 0}
|
|
||||||
m_VelocityIterations: 8
|
|
||||||
m_PositionIterations: 3
|
|
||||||
m_VelocityThreshold: 1
|
|
||||||
m_MaxLinearCorrection: 0.2
|
|
||||||
m_MaxAngularCorrection: 8
|
|
||||||
m_MaxTranslationSpeed: 100
|
|
||||||
m_MaxRotationSpeed: 360
|
|
||||||
m_BaumgarteScale: 0.2
|
|
||||||
m_BaumgarteTimeOfImpactScale: 0.75
|
|
||||||
m_TimeToSleep: 0.5
|
|
||||||
m_LinearSleepTolerance: 0.01
|
|
||||||
m_AngularSleepTolerance: 2
|
|
||||||
m_DefaultContactOffset: 0.01
|
|
||||||
m_JobOptions:
|
|
||||||
serializedVersion: 2
|
|
||||||
useMultithreading: 0
|
|
||||||
useConsistencySorting: 0
|
|
||||||
m_InterpolationPosesPerJob: 100
|
|
||||||
m_NewContactsPerJob: 30
|
|
||||||
m_CollideContactsPerJob: 100
|
|
||||||
m_ClearFlagsPerJob: 200
|
|
||||||
m_ClearBodyForcesPerJob: 200
|
|
||||||
m_SyncDiscreteFixturesPerJob: 50
|
|
||||||
m_SyncContinuousFixturesPerJob: 50
|
|
||||||
m_FindNearestContactsPerJob: 100
|
|
||||||
m_UpdateTriggerContactsPerJob: 100
|
|
||||||
m_IslandSolverCostThreshold: 100
|
|
||||||
m_IslandSolverBodyCostScale: 1
|
|
||||||
m_IslandSolverContactCostScale: 10
|
|
||||||
m_IslandSolverJointCostScale: 10
|
|
||||||
m_IslandSolverBodiesPerJob: 50
|
|
||||||
m_IslandSolverContactsPerJob: 50
|
|
||||||
m_SimulationMode: 0
|
|
||||||
m_QueriesHitTriggers: 1
|
|
||||||
m_QueriesStartInColliders: 1
|
|
||||||
m_CallbacksOnDisable: 1
|
|
||||||
m_ReuseCollisionCallbacks: 1
|
|
||||||
m_AutoSyncTransforms: 0
|
|
||||||
m_AlwaysShowColliders: 0
|
|
||||||
m_ShowColliderSleep: 1
|
|
||||||
m_ShowColliderContacts: 0
|
|
||||||
m_ShowColliderAABB: 0
|
|
||||||
m_ContactArrowScale: 0.2
|
|
||||||
m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412}
|
|
||||||
m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432}
|
|
||||||
m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745}
|
|
||||||
m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804}
|
|
||||||
m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
@ -1,7 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!1386491679 &1
|
|
||||||
PresetManager:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
serializedVersion: 2
|
|
||||||
m_DefaultPresets: {}
|
|
@ -1,646 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!129 &1
|
|
||||||
PlayerSettings:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
serializedVersion: 22
|
|
||||||
productGUID: 4852b04bea0e36b428b29c34acc83ad9
|
|
||||||
AndroidProfiler: 0
|
|
||||||
AndroidFilterTouchesWhenObscured: 0
|
|
||||||
AndroidEnableSustainedPerformanceMode: 0
|
|
||||||
defaultScreenOrientation: 4
|
|
||||||
targetDevice: 2
|
|
||||||
useOnDemandResources: 0
|
|
||||||
accelerometerFrequency: 60
|
|
||||||
companyName: DefaultCompany
|
|
||||||
productName: ObservableCollections.Unity
|
|
||||||
defaultCursor: {fileID: 0}
|
|
||||||
cursorHotspot: {x: 0, y: 0}
|
|
||||||
m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1}
|
|
||||||
m_ShowUnitySplashScreen: 1
|
|
||||||
m_ShowUnitySplashLogo: 1
|
|
||||||
m_SplashScreenOverlayOpacity: 1
|
|
||||||
m_SplashScreenAnimation: 1
|
|
||||||
m_SplashScreenLogoStyle: 1
|
|
||||||
m_SplashScreenDrawMode: 0
|
|
||||||
m_SplashScreenBackgroundAnimationZoom: 1
|
|
||||||
m_SplashScreenLogoAnimationZoom: 1
|
|
||||||
m_SplashScreenBackgroundLandscapeAspect: 1
|
|
||||||
m_SplashScreenBackgroundPortraitAspect: 1
|
|
||||||
m_SplashScreenBackgroundLandscapeUvs:
|
|
||||||
serializedVersion: 2
|
|
||||||
x: 0
|
|
||||||
y: 0
|
|
||||||
width: 1
|
|
||||||
height: 1
|
|
||||||
m_SplashScreenBackgroundPortraitUvs:
|
|
||||||
serializedVersion: 2
|
|
||||||
x: 0
|
|
||||||
y: 0
|
|
||||||
width: 1
|
|
||||||
height: 1
|
|
||||||
m_SplashScreenLogos: []
|
|
||||||
m_VirtualRealitySplashScreen: {fileID: 0}
|
|
||||||
m_HolographicTrackingLossScreen: {fileID: 0}
|
|
||||||
defaultScreenWidth: 1920
|
|
||||||
defaultScreenHeight: 1080
|
|
||||||
defaultScreenWidthWeb: 960
|
|
||||||
defaultScreenHeightWeb: 600
|
|
||||||
m_StereoRenderingPath: 0
|
|
||||||
m_ActiveColorSpace: 0
|
|
||||||
m_MTRendering: 1
|
|
||||||
mipStripping: 0
|
|
||||||
numberOfMipsStripped: 0
|
|
||||||
m_StackTraceTypes: 010000000100000001000000010000000100000001000000
|
|
||||||
iosShowActivityIndicatorOnLoading: -1
|
|
||||||
androidShowActivityIndicatorOnLoading: -1
|
|
||||||
iosUseCustomAppBackgroundBehavior: 0
|
|
||||||
iosAllowHTTPDownload: 1
|
|
||||||
allowedAutorotateToPortrait: 1
|
|
||||||
allowedAutorotateToPortraitUpsideDown: 1
|
|
||||||
allowedAutorotateToLandscapeRight: 1
|
|
||||||
allowedAutorotateToLandscapeLeft: 1
|
|
||||||
useOSAutorotation: 1
|
|
||||||
use32BitDisplayBuffer: 1
|
|
||||||
preserveFramebufferAlpha: 0
|
|
||||||
disableDepthAndStencilBuffers: 0
|
|
||||||
androidStartInFullscreen: 1
|
|
||||||
androidRenderOutsideSafeArea: 1
|
|
||||||
androidUseSwappy: 1
|
|
||||||
androidBlitType: 0
|
|
||||||
defaultIsNativeResolution: 1
|
|
||||||
macRetinaSupport: 1
|
|
||||||
runInBackground: 0
|
|
||||||
captureSingleScreen: 0
|
|
||||||
muteOtherAudioSources: 0
|
|
||||||
Prepare IOS For Recording: 0
|
|
||||||
Force IOS Speakers When Recording: 0
|
|
||||||
deferSystemGesturesMode: 0
|
|
||||||
hideHomeButton: 0
|
|
||||||
submitAnalytics: 1
|
|
||||||
usePlayerLog: 1
|
|
||||||
bakeCollisionMeshes: 0
|
|
||||||
forceSingleInstance: 0
|
|
||||||
useFlipModelSwapchain: 1
|
|
||||||
resizableWindow: 0
|
|
||||||
useMacAppStoreValidation: 0
|
|
||||||
macAppStoreCategory: public.app-category.games
|
|
||||||
gpuSkinning: 0
|
|
||||||
xboxPIXTextureCapture: 0
|
|
||||||
xboxEnableAvatar: 0
|
|
||||||
xboxEnableKinect: 0
|
|
||||||
xboxEnableKinectAutoTracking: 0
|
|
||||||
xboxEnableFitness: 0
|
|
||||||
visibleInBackground: 1
|
|
||||||
allowFullscreenSwitch: 1
|
|
||||||
fullscreenMode: 1
|
|
||||||
xboxSpeechDB: 0
|
|
||||||
xboxEnableHeadOrientation: 0
|
|
||||||
xboxEnableGuest: 0
|
|
||||||
xboxEnablePIXSampling: 0
|
|
||||||
metalFramebufferOnly: 0
|
|
||||||
xboxOneResolution: 0
|
|
||||||
xboxOneSResolution: 0
|
|
||||||
xboxOneXResolution: 3
|
|
||||||
xboxOneMonoLoggingLevel: 0
|
|
||||||
xboxOneLoggingLevel: 1
|
|
||||||
xboxOneDisableEsram: 0
|
|
||||||
xboxOneEnableTypeOptimization: 0
|
|
||||||
xboxOnePresentImmediateThreshold: 0
|
|
||||||
switchQueueCommandMemory: 1048576
|
|
||||||
switchQueueControlMemory: 16384
|
|
||||||
switchQueueComputeMemory: 262144
|
|
||||||
switchNVNShaderPoolsGranularity: 33554432
|
|
||||||
switchNVNDefaultPoolsGranularity: 16777216
|
|
||||||
switchNVNOtherPoolsGranularity: 16777216
|
|
||||||
switchNVNMaxPublicTextureIDCount: 0
|
|
||||||
switchNVNMaxPublicSamplerIDCount: 0
|
|
||||||
stadiaPresentMode: 0
|
|
||||||
stadiaTargetFramerate: 0
|
|
||||||
vulkanNumSwapchainBuffers: 3
|
|
||||||
vulkanEnableSetSRGBWrite: 0
|
|
||||||
vulkanEnablePreTransform: 0
|
|
||||||
vulkanEnableLateAcquireNextImage: 0
|
|
||||||
m_SupportedAspectRatios:
|
|
||||||
4:3: 1
|
|
||||||
5:4: 1
|
|
||||||
16:10: 1
|
|
||||||
16:9: 1
|
|
||||||
Others: 1
|
|
||||||
bundleVersion: 1.0
|
|
||||||
preloadedAssets: []
|
|
||||||
metroInputSource: 0
|
|
||||||
wsaTransparentSwapchain: 0
|
|
||||||
m_HolographicPauseOnTrackingLoss: 1
|
|
||||||
xboxOneDisableKinectGpuReservation: 1
|
|
||||||
xboxOneEnable7thCore: 1
|
|
||||||
vrSettings:
|
|
||||||
enable360StereoCapture: 0
|
|
||||||
isWsaHolographicRemotingEnabled: 0
|
|
||||||
enableFrameTimingStats: 0
|
|
||||||
useHDRDisplay: 0
|
|
||||||
D3DHDRBitDepth: 0
|
|
||||||
m_ColorGamuts: 00000000
|
|
||||||
targetPixelDensity: 30
|
|
||||||
resolutionScalingMode: 0
|
|
||||||
androidSupportedAspectRatio: 1
|
|
||||||
androidMaxAspectRatio: 2.1
|
|
||||||
applicationIdentifier: {}
|
|
||||||
buildNumber:
|
|
||||||
Standalone: 0
|
|
||||||
iPhone: 0
|
|
||||||
tvOS: 0
|
|
||||||
overrideDefaultApplicationIdentifier: 0
|
|
||||||
AndroidBundleVersionCode: 1
|
|
||||||
AndroidMinSdkVersion: 19
|
|
||||||
AndroidTargetSdkVersion: 0
|
|
||||||
AndroidPreferredInstallLocation: 1
|
|
||||||
aotOptions:
|
|
||||||
stripEngineCode: 1
|
|
||||||
iPhoneStrippingLevel: 0
|
|
||||||
iPhoneScriptCallOptimization: 0
|
|
||||||
ForceInternetPermission: 0
|
|
||||||
ForceSDCardPermission: 0
|
|
||||||
CreateWallpaper: 0
|
|
||||||
APKExpansionFiles: 0
|
|
||||||
keepLoadedShadersAlive: 0
|
|
||||||
StripUnusedMeshComponents: 0
|
|
||||||
VertexChannelCompressionMask: 4054
|
|
||||||
iPhoneSdkVersion: 988
|
|
||||||
iOSTargetOSVersionString: 11.0
|
|
||||||
tvOSSdkVersion: 0
|
|
||||||
tvOSRequireExtendedGameController: 0
|
|
||||||
tvOSTargetOSVersionString: 11.0
|
|
||||||
uIPrerenderedIcon: 0
|
|
||||||
uIRequiresPersistentWiFi: 0
|
|
||||||
uIRequiresFullScreen: 1
|
|
||||||
uIStatusBarHidden: 1
|
|
||||||
uIExitOnSuspend: 0
|
|
||||||
uIStatusBarStyle: 0
|
|
||||||
appleTVSplashScreen: {fileID: 0}
|
|
||||||
appleTVSplashScreen2x: {fileID: 0}
|
|
||||||
tvOSSmallIconLayers: []
|
|
||||||
tvOSSmallIconLayers2x: []
|
|
||||||
tvOSLargeIconLayers: []
|
|
||||||
tvOSLargeIconLayers2x: []
|
|
||||||
tvOSTopShelfImageLayers: []
|
|
||||||
tvOSTopShelfImageLayers2x: []
|
|
||||||
tvOSTopShelfImageWideLayers: []
|
|
||||||
tvOSTopShelfImageWideLayers2x: []
|
|
||||||
iOSLaunchScreenType: 0
|
|
||||||
iOSLaunchScreenPortrait: {fileID: 0}
|
|
||||||
iOSLaunchScreenLandscape: {fileID: 0}
|
|
||||||
iOSLaunchScreenBackgroundColor:
|
|
||||||
serializedVersion: 2
|
|
||||||
rgba: 0
|
|
||||||
iOSLaunchScreenFillPct: 100
|
|
||||||
iOSLaunchScreenSize: 100
|
|
||||||
iOSLaunchScreenCustomXibPath:
|
|
||||||
iOSLaunchScreeniPadType: 0
|
|
||||||
iOSLaunchScreeniPadImage: {fileID: 0}
|
|
||||||
iOSLaunchScreeniPadBackgroundColor:
|
|
||||||
serializedVersion: 2
|
|
||||||
rgba: 0
|
|
||||||
iOSLaunchScreeniPadFillPct: 100
|
|
||||||
iOSLaunchScreeniPadSize: 100
|
|
||||||
iOSLaunchScreeniPadCustomXibPath:
|
|
||||||
iOSLaunchScreenCustomStoryboardPath:
|
|
||||||
iOSLaunchScreeniPadCustomStoryboardPath:
|
|
||||||
iOSDeviceRequirements: []
|
|
||||||
iOSURLSchemes: []
|
|
||||||
iOSBackgroundModes: 0
|
|
||||||
iOSMetalForceHardShadows: 0
|
|
||||||
metalEditorSupport: 1
|
|
||||||
metalAPIValidation: 1
|
|
||||||
iOSRenderExtraFrameOnPause: 0
|
|
||||||
iosCopyPluginsCodeInsteadOfSymlink: 0
|
|
||||||
appleDeveloperTeamID:
|
|
||||||
iOSManualSigningProvisioningProfileID:
|
|
||||||
tvOSManualSigningProvisioningProfileID:
|
|
||||||
iOSManualSigningProvisioningProfileType: 0
|
|
||||||
tvOSManualSigningProvisioningProfileType: 0
|
|
||||||
appleEnableAutomaticSigning: 0
|
|
||||||
iOSRequireARKit: 0
|
|
||||||
iOSAutomaticallyDetectAndAddCapabilities: 1
|
|
||||||
appleEnableProMotion: 0
|
|
||||||
shaderPrecisionModel: 0
|
|
||||||
clonedFromGUID: 10ad67313f4034357812315f3c407484
|
|
||||||
templatePackageId: com.unity.template.2d@5.0.0
|
|
||||||
templateDefaultScene: Assets/Scenes/SampleScene.unity
|
|
||||||
useCustomMainManifest: 0
|
|
||||||
useCustomLauncherManifest: 0
|
|
||||||
useCustomMainGradleTemplate: 0
|
|
||||||
useCustomLauncherGradleManifest: 0
|
|
||||||
useCustomBaseGradleTemplate: 0
|
|
||||||
useCustomGradlePropertiesTemplate: 0
|
|
||||||
useCustomProguardFile: 0
|
|
||||||
AndroidTargetArchitectures: 1
|
|
||||||
AndroidSplashScreenScale: 0
|
|
||||||
androidSplashScreen: {fileID: 0}
|
|
||||||
AndroidKeystoreName:
|
|
||||||
AndroidKeyaliasName:
|
|
||||||
AndroidBuildApkPerCpuArchitecture: 0
|
|
||||||
AndroidTVCompatibility: 0
|
|
||||||
AndroidIsGame: 1
|
|
||||||
AndroidEnableTango: 0
|
|
||||||
androidEnableBanner: 1
|
|
||||||
androidUseLowAccuracyLocation: 0
|
|
||||||
androidUseCustomKeystore: 0
|
|
||||||
m_AndroidBanners:
|
|
||||||
- width: 320
|
|
||||||
height: 180
|
|
||||||
banner: {fileID: 0}
|
|
||||||
androidGamepadSupportLevel: 0
|
|
||||||
AndroidMinifyWithR8: 0
|
|
||||||
AndroidMinifyRelease: 0
|
|
||||||
AndroidMinifyDebug: 0
|
|
||||||
AndroidValidateAppBundleSize: 1
|
|
||||||
AndroidAppBundleSizeToValidate: 150
|
|
||||||
m_BuildTargetIcons: []
|
|
||||||
m_BuildTargetPlatformIcons: []
|
|
||||||
m_BuildTargetBatching: []
|
|
||||||
m_BuildTargetGraphicsJobs:
|
|
||||||
- m_BuildTarget: MacStandaloneSupport
|
|
||||||
m_GraphicsJobs: 0
|
|
||||||
- m_BuildTarget: Switch
|
|
||||||
m_GraphicsJobs: 0
|
|
||||||
- m_BuildTarget: MetroSupport
|
|
||||||
m_GraphicsJobs: 0
|
|
||||||
- m_BuildTarget: AppleTVSupport
|
|
||||||
m_GraphicsJobs: 0
|
|
||||||
- m_BuildTarget: BJMSupport
|
|
||||||
m_GraphicsJobs: 0
|
|
||||||
- m_BuildTarget: LinuxStandaloneSupport
|
|
||||||
m_GraphicsJobs: 0
|
|
||||||
- m_BuildTarget: PS4Player
|
|
||||||
m_GraphicsJobs: 0
|
|
||||||
- m_BuildTarget: iOSSupport
|
|
||||||
m_GraphicsJobs: 0
|
|
||||||
- m_BuildTarget: WindowsStandaloneSupport
|
|
||||||
m_GraphicsJobs: 0
|
|
||||||
- m_BuildTarget: XboxOnePlayer
|
|
||||||
m_GraphicsJobs: 0
|
|
||||||
- m_BuildTarget: LuminSupport
|
|
||||||
m_GraphicsJobs: 0
|
|
||||||
- m_BuildTarget: AndroidPlayer
|
|
||||||
m_GraphicsJobs: 0
|
|
||||||
- m_BuildTarget: WebGLSupport
|
|
||||||
m_GraphicsJobs: 0
|
|
||||||
m_BuildTargetGraphicsJobMode: []
|
|
||||||
m_BuildTargetGraphicsAPIs:
|
|
||||||
- m_BuildTarget: AndroidPlayer
|
|
||||||
m_APIs: 150000000b000000
|
|
||||||
m_Automatic: 0
|
|
||||||
- m_BuildTarget: iOSSupport
|
|
||||||
m_APIs: 10000000
|
|
||||||
m_Automatic: 1
|
|
||||||
m_BuildTargetVRSettings: []
|
|
||||||
openGLRequireES31: 0
|
|
||||||
openGLRequireES31AEP: 0
|
|
||||||
openGLRequireES32: 0
|
|
||||||
m_TemplateCustomTags: {}
|
|
||||||
mobileMTRendering:
|
|
||||||
Android: 1
|
|
||||||
iPhone: 1
|
|
||||||
tvOS: 1
|
|
||||||
m_BuildTargetGroupLightmapEncodingQuality: []
|
|
||||||
m_BuildTargetGroupLightmapSettings: []
|
|
||||||
m_BuildTargetNormalMapEncoding: []
|
|
||||||
playModeTestRunnerEnabled: 0
|
|
||||||
runPlayModeTestAsEditModeTest: 0
|
|
||||||
actionOnDotNetUnhandledException: 1
|
|
||||||
enableInternalProfiler: 0
|
|
||||||
logObjCUncaughtExceptions: 1
|
|
||||||
enableCrashReportAPI: 0
|
|
||||||
cameraUsageDescription:
|
|
||||||
locationUsageDescription:
|
|
||||||
microphoneUsageDescription:
|
|
||||||
switchNMETAOverride:
|
|
||||||
switchNetLibKey:
|
|
||||||
switchSocketMemoryPoolSize: 6144
|
|
||||||
switchSocketAllocatorPoolSize: 128
|
|
||||||
switchSocketConcurrencyLimit: 14
|
|
||||||
switchScreenResolutionBehavior: 2
|
|
||||||
switchUseCPUProfiler: 0
|
|
||||||
switchUseGOLDLinker: 0
|
|
||||||
switchApplicationID: 0x01004b9000490000
|
|
||||||
switchNSODependencies:
|
|
||||||
switchTitleNames_0:
|
|
||||||
switchTitleNames_1:
|
|
||||||
switchTitleNames_2:
|
|
||||||
switchTitleNames_3:
|
|
||||||
switchTitleNames_4:
|
|
||||||
switchTitleNames_5:
|
|
||||||
switchTitleNames_6:
|
|
||||||
switchTitleNames_7:
|
|
||||||
switchTitleNames_8:
|
|
||||||
switchTitleNames_9:
|
|
||||||
switchTitleNames_10:
|
|
||||||
switchTitleNames_11:
|
|
||||||
switchTitleNames_12:
|
|
||||||
switchTitleNames_13:
|
|
||||||
switchTitleNames_14:
|
|
||||||
switchTitleNames_15:
|
|
||||||
switchPublisherNames_0:
|
|
||||||
switchPublisherNames_1:
|
|
||||||
switchPublisherNames_2:
|
|
||||||
switchPublisherNames_3:
|
|
||||||
switchPublisherNames_4:
|
|
||||||
switchPublisherNames_5:
|
|
||||||
switchPublisherNames_6:
|
|
||||||
switchPublisherNames_7:
|
|
||||||
switchPublisherNames_8:
|
|
||||||
switchPublisherNames_9:
|
|
||||||
switchPublisherNames_10:
|
|
||||||
switchPublisherNames_11:
|
|
||||||
switchPublisherNames_12:
|
|
||||||
switchPublisherNames_13:
|
|
||||||
switchPublisherNames_14:
|
|
||||||
switchPublisherNames_15:
|
|
||||||
switchIcons_0: {fileID: 0}
|
|
||||||
switchIcons_1: {fileID: 0}
|
|
||||||
switchIcons_2: {fileID: 0}
|
|
||||||
switchIcons_3: {fileID: 0}
|
|
||||||
switchIcons_4: {fileID: 0}
|
|
||||||
switchIcons_5: {fileID: 0}
|
|
||||||
switchIcons_6: {fileID: 0}
|
|
||||||
switchIcons_7: {fileID: 0}
|
|
||||||
switchIcons_8: {fileID: 0}
|
|
||||||
switchIcons_9: {fileID: 0}
|
|
||||||
switchIcons_10: {fileID: 0}
|
|
||||||
switchIcons_11: {fileID: 0}
|
|
||||||
switchIcons_12: {fileID: 0}
|
|
||||||
switchIcons_13: {fileID: 0}
|
|
||||||
switchIcons_14: {fileID: 0}
|
|
||||||
switchIcons_15: {fileID: 0}
|
|
||||||
switchSmallIcons_0: {fileID: 0}
|
|
||||||
switchSmallIcons_1: {fileID: 0}
|
|
||||||
switchSmallIcons_2: {fileID: 0}
|
|
||||||
switchSmallIcons_3: {fileID: 0}
|
|
||||||
switchSmallIcons_4: {fileID: 0}
|
|
||||||
switchSmallIcons_5: {fileID: 0}
|
|
||||||
switchSmallIcons_6: {fileID: 0}
|
|
||||||
switchSmallIcons_7: {fileID: 0}
|
|
||||||
switchSmallIcons_8: {fileID: 0}
|
|
||||||
switchSmallIcons_9: {fileID: 0}
|
|
||||||
switchSmallIcons_10: {fileID: 0}
|
|
||||||
switchSmallIcons_11: {fileID: 0}
|
|
||||||
switchSmallIcons_12: {fileID: 0}
|
|
||||||
switchSmallIcons_13: {fileID: 0}
|
|
||||||
switchSmallIcons_14: {fileID: 0}
|
|
||||||
switchSmallIcons_15: {fileID: 0}
|
|
||||||
switchManualHTML:
|
|
||||||
switchAccessibleURLs:
|
|
||||||
switchLegalInformation:
|
|
||||||
switchMainThreadStackSize: 1048576
|
|
||||||
switchPresenceGroupId:
|
|
||||||
switchLogoHandling: 0
|
|
||||||
switchReleaseVersion: 0
|
|
||||||
switchDisplayVersion: 1.0.0
|
|
||||||
switchStartupUserAccount: 0
|
|
||||||
switchTouchScreenUsage: 0
|
|
||||||
switchSupportedLanguagesMask: 0
|
|
||||||
switchLogoType: 0
|
|
||||||
switchApplicationErrorCodeCategory:
|
|
||||||
switchUserAccountSaveDataSize: 0
|
|
||||||
switchUserAccountSaveDataJournalSize: 0
|
|
||||||
switchApplicationAttribute: 0
|
|
||||||
switchCardSpecSize: -1
|
|
||||||
switchCardSpecClock: -1
|
|
||||||
switchRatingsMask: 0
|
|
||||||
switchRatingsInt_0: 0
|
|
||||||
switchRatingsInt_1: 0
|
|
||||||
switchRatingsInt_2: 0
|
|
||||||
switchRatingsInt_3: 0
|
|
||||||
switchRatingsInt_4: 0
|
|
||||||
switchRatingsInt_5: 0
|
|
||||||
switchRatingsInt_6: 0
|
|
||||||
switchRatingsInt_7: 0
|
|
||||||
switchRatingsInt_8: 0
|
|
||||||
switchRatingsInt_9: 0
|
|
||||||
switchRatingsInt_10: 0
|
|
||||||
switchRatingsInt_11: 0
|
|
||||||
switchRatingsInt_12: 0
|
|
||||||
switchLocalCommunicationIds_0:
|
|
||||||
switchLocalCommunicationIds_1:
|
|
||||||
switchLocalCommunicationIds_2:
|
|
||||||
switchLocalCommunicationIds_3:
|
|
||||||
switchLocalCommunicationIds_4:
|
|
||||||
switchLocalCommunicationIds_5:
|
|
||||||
switchLocalCommunicationIds_6:
|
|
||||||
switchLocalCommunicationIds_7:
|
|
||||||
switchParentalControl: 0
|
|
||||||
switchAllowsScreenshot: 1
|
|
||||||
switchAllowsVideoCapturing: 1
|
|
||||||
switchAllowsRuntimeAddOnContentInstall: 0
|
|
||||||
switchDataLossConfirmation: 0
|
|
||||||
switchUserAccountLockEnabled: 0
|
|
||||||
switchSystemResourceMemory: 16777216
|
|
||||||
switchSupportedNpadStyles: 22
|
|
||||||
switchNativeFsCacheSize: 32
|
|
||||||
switchIsHoldTypeHorizontal: 0
|
|
||||||
switchSupportedNpadCount: 8
|
|
||||||
switchSocketConfigEnabled: 0
|
|
||||||
switchTcpInitialSendBufferSize: 32
|
|
||||||
switchTcpInitialReceiveBufferSize: 64
|
|
||||||
switchTcpAutoSendBufferSizeMax: 256
|
|
||||||
switchTcpAutoReceiveBufferSizeMax: 256
|
|
||||||
switchUdpSendBufferSize: 9
|
|
||||||
switchUdpReceiveBufferSize: 42
|
|
||||||
switchSocketBufferEfficiency: 4
|
|
||||||
switchSocketInitializeEnabled: 1
|
|
||||||
switchNetworkInterfaceManagerInitializeEnabled: 1
|
|
||||||
switchPlayerConnectionEnabled: 1
|
|
||||||
switchUseNewStyleFilepaths: 0
|
|
||||||
switchUseMicroSleepForYield: 1
|
|
||||||
switchMicroSleepForYieldTime: 25
|
|
||||||
ps4NPAgeRating: 12
|
|
||||||
ps4NPTitleSecret:
|
|
||||||
ps4NPTrophyPackPath:
|
|
||||||
ps4ParentalLevel: 11
|
|
||||||
ps4ContentID: ED1633-NPXX51362_00-0000000000000000
|
|
||||||
ps4Category: 0
|
|
||||||
ps4MasterVersion: 01.00
|
|
||||||
ps4AppVersion: 01.00
|
|
||||||
ps4AppType: 0
|
|
||||||
ps4ParamSfxPath:
|
|
||||||
ps4VideoOutPixelFormat: 0
|
|
||||||
ps4VideoOutInitialWidth: 1920
|
|
||||||
ps4VideoOutBaseModeInitialWidth: 1920
|
|
||||||
ps4VideoOutReprojectionRate: 60
|
|
||||||
ps4PronunciationXMLPath:
|
|
||||||
ps4PronunciationSIGPath:
|
|
||||||
ps4BackgroundImagePath:
|
|
||||||
ps4StartupImagePath:
|
|
||||||
ps4StartupImagesFolder:
|
|
||||||
ps4IconImagesFolder:
|
|
||||||
ps4SaveDataImagePath:
|
|
||||||
ps4SdkOverride:
|
|
||||||
ps4BGMPath:
|
|
||||||
ps4ShareFilePath:
|
|
||||||
ps4ShareOverlayImagePath:
|
|
||||||
ps4PrivacyGuardImagePath:
|
|
||||||
ps4ExtraSceSysFile:
|
|
||||||
ps4NPtitleDatPath:
|
|
||||||
ps4RemotePlayKeyAssignment: -1
|
|
||||||
ps4RemotePlayKeyMappingDir:
|
|
||||||
ps4PlayTogetherPlayerCount: 0
|
|
||||||
ps4EnterButtonAssignment: 2
|
|
||||||
ps4ApplicationParam1: 0
|
|
||||||
ps4ApplicationParam2: 0
|
|
||||||
ps4ApplicationParam3: 0
|
|
||||||
ps4ApplicationParam4: 0
|
|
||||||
ps4DownloadDataSize: 0
|
|
||||||
ps4GarlicHeapSize: 2048
|
|
||||||
ps4ProGarlicHeapSize: 2560
|
|
||||||
playerPrefsMaxSize: 32768
|
|
||||||
ps4Passcode: bi9UOuSpM2Tlh01vOzwvSikHFswuzleh
|
|
||||||
ps4pnSessions: 1
|
|
||||||
ps4pnPresence: 1
|
|
||||||
ps4pnFriends: 1
|
|
||||||
ps4pnGameCustomData: 1
|
|
||||||
playerPrefsSupport: 0
|
|
||||||
enableApplicationExit: 0
|
|
||||||
resetTempFolder: 1
|
|
||||||
restrictedAudioUsageRights: 0
|
|
||||||
ps4UseResolutionFallback: 0
|
|
||||||
ps4ReprojectionSupport: 0
|
|
||||||
ps4UseAudio3dBackend: 0
|
|
||||||
ps4UseLowGarlicFragmentationMode: 1
|
|
||||||
ps4SocialScreenEnabled: 0
|
|
||||||
ps4ScriptOptimizationLevel: 2
|
|
||||||
ps4Audio3dVirtualSpeakerCount: 14
|
|
||||||
ps4attribCpuUsage: 0
|
|
||||||
ps4PatchPkgPath:
|
|
||||||
ps4PatchLatestPkgPath:
|
|
||||||
ps4PatchChangeinfoPath:
|
|
||||||
ps4PatchDayOne: 0
|
|
||||||
ps4attribUserManagement: 0
|
|
||||||
ps4attribMoveSupport: 0
|
|
||||||
ps4attrib3DSupport: 0
|
|
||||||
ps4attribShareSupport: 0
|
|
||||||
ps4attribExclusiveVR: 0
|
|
||||||
ps4disableAutoHideSplash: 0
|
|
||||||
ps4videoRecordingFeaturesUsed: 0
|
|
||||||
ps4contentSearchFeaturesUsed: 0
|
|
||||||
ps4CompatibilityPS5: 0
|
|
||||||
ps4GPU800MHz: 1
|
|
||||||
ps4attribEyeToEyeDistanceSettingVR: 0
|
|
||||||
ps4IncludedModules: []
|
|
||||||
ps4attribVROutputEnabled: 0
|
|
||||||
monoEnv:
|
|
||||||
splashScreenBackgroundSourceLandscape: {fileID: 0}
|
|
||||||
splashScreenBackgroundSourcePortrait: {fileID: 0}
|
|
||||||
blurSplashScreenBackground: 1
|
|
||||||
spritePackerPolicy:
|
|
||||||
webGLMemorySize: 32
|
|
||||||
webGLExceptionSupport: 1
|
|
||||||
webGLNameFilesAsHashes: 0
|
|
||||||
webGLDataCaching: 1
|
|
||||||
webGLDebugSymbols: 0
|
|
||||||
webGLEmscriptenArgs:
|
|
||||||
webGLModulesDirectory:
|
|
||||||
webGLTemplate: APPLICATION:Default
|
|
||||||
webGLAnalyzeBuildSize: 0
|
|
||||||
webGLUseEmbeddedResources: 0
|
|
||||||
webGLCompressionFormat: 0
|
|
||||||
webGLWasmArithmeticExceptions: 0
|
|
||||||
webGLLinkerTarget: 1
|
|
||||||
webGLThreadsSupport: 0
|
|
||||||
webGLDecompressionFallback: 0
|
|
||||||
scriptingDefineSymbols: {}
|
|
||||||
additionalCompilerArguments: {}
|
|
||||||
platformArchitecture: {}
|
|
||||||
scriptingBackend: {}
|
|
||||||
il2cppCompilerConfiguration: {}
|
|
||||||
managedStrippingLevel: {}
|
|
||||||
incrementalIl2cppBuild: {}
|
|
||||||
suppressCommonWarnings: 1
|
|
||||||
allowUnsafeCode: 0
|
|
||||||
useDeterministicCompilation: 1
|
|
||||||
useReferenceAssemblies: 1
|
|
||||||
enableRoslynAnalyzers: 1
|
|
||||||
additionalIl2CppArgs:
|
|
||||||
scriptingRuntimeVersion: 1
|
|
||||||
gcIncremental: 1
|
|
||||||
assemblyVersionValidation: 1
|
|
||||||
gcWBarrierValidation: 0
|
|
||||||
apiCompatibilityLevelPerPlatform: {}
|
|
||||||
m_RenderingPath: 1
|
|
||||||
m_MobileRenderingPath: 1
|
|
||||||
metroPackageName: 2D_BuiltInRenderer
|
|
||||||
metroPackageVersion:
|
|
||||||
metroCertificatePath:
|
|
||||||
metroCertificatePassword:
|
|
||||||
metroCertificateSubject:
|
|
||||||
metroCertificateIssuer:
|
|
||||||
metroCertificateNotAfter: 0000000000000000
|
|
||||||
metroApplicationDescription: 2D_BuiltInRenderer
|
|
||||||
wsaImages: {}
|
|
||||||
metroTileShortName:
|
|
||||||
metroTileShowName: 0
|
|
||||||
metroMediumTileShowName: 0
|
|
||||||
metroLargeTileShowName: 0
|
|
||||||
metroWideTileShowName: 0
|
|
||||||
metroSupportStreamingInstall: 0
|
|
||||||
metroLastRequiredScene: 0
|
|
||||||
metroDefaultTileSize: 1
|
|
||||||
metroTileForegroundText: 2
|
|
||||||
metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0}
|
|
||||||
metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, a: 1}
|
|
||||||
metroSplashScreenUseBackgroundColor: 0
|
|
||||||
platformCapabilities: {}
|
|
||||||
metroTargetDeviceFamilies: {}
|
|
||||||
metroFTAName:
|
|
||||||
metroFTAFileTypes: []
|
|
||||||
metroProtocolName:
|
|
||||||
XboxOneProductId:
|
|
||||||
XboxOneUpdateKey:
|
|
||||||
XboxOneSandboxId:
|
|
||||||
XboxOneContentId:
|
|
||||||
XboxOneTitleId:
|
|
||||||
XboxOneSCId:
|
|
||||||
XboxOneGameOsOverridePath:
|
|
||||||
XboxOnePackagingOverridePath:
|
|
||||||
XboxOneAppManifestOverridePath:
|
|
||||||
XboxOneVersion: 1.0.0.0
|
|
||||||
XboxOnePackageEncryption: 0
|
|
||||||
XboxOnePackageUpdateGranularity: 2
|
|
||||||
XboxOneDescription:
|
|
||||||
XboxOneLanguage:
|
|
||||||
- enus
|
|
||||||
XboxOneCapability: []
|
|
||||||
XboxOneGameRating: {}
|
|
||||||
XboxOneIsContentPackage: 0
|
|
||||||
XboxOneEnhancedXboxCompatibilityMode: 0
|
|
||||||
XboxOneEnableGPUVariability: 1
|
|
||||||
XboxOneSockets: {}
|
|
||||||
XboxOneSplashScreen: {fileID: 0}
|
|
||||||
XboxOneAllowedProductIds: []
|
|
||||||
XboxOnePersistentLocalStorageSize: 0
|
|
||||||
XboxOneXTitleMemory: 8
|
|
||||||
XboxOneOverrideIdentityName:
|
|
||||||
XboxOneOverrideIdentityPublisher:
|
|
||||||
vrEditorSettings: {}
|
|
||||||
cloudServicesEnabled: {}
|
|
||||||
luminIcon:
|
|
||||||
m_Name:
|
|
||||||
m_ModelFolderPath:
|
|
||||||
m_PortalFolderPath:
|
|
||||||
luminCert:
|
|
||||||
m_CertPath:
|
|
||||||
m_SignPackage: 1
|
|
||||||
luminIsChannelApp: 0
|
|
||||||
luminVersion:
|
|
||||||
m_VersionCode: 1
|
|
||||||
m_VersionName:
|
|
||||||
apiCompatibilityLevel: 6
|
|
||||||
activeInputHandler: 0
|
|
||||||
cloudProjectId:
|
|
||||||
framebufferDepthMemorylessMode: 0
|
|
||||||
qualitySettingsNames: []
|
|
||||||
projectName:
|
|
||||||
organizationId:
|
|
||||||
cloudEnabled: 0
|
|
||||||
legacyClampBlendShapeWeights: 0
|
|
||||||
virtualTexturingSupportEnabled: 0
|
|
@ -1,2 +0,0 @@
|
|||||||
m_EditorVersion: 2020.1.0a3
|
|
||||||
m_EditorVersionWithRevision: 2020.1.0a3 (a37e4d4d532f)
|
|
@ -1,236 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!47 &1
|
|
||||||
QualitySettings:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
serializedVersion: 5
|
|
||||||
m_CurrentQuality: 5
|
|
||||||
m_QualitySettings:
|
|
||||||
- serializedVersion: 2
|
|
||||||
name: Very Low
|
|
||||||
pixelLightCount: 0
|
|
||||||
shadows: 0
|
|
||||||
shadowResolution: 0
|
|
||||||
shadowProjection: 1
|
|
||||||
shadowCascades: 1
|
|
||||||
shadowDistance: 15
|
|
||||||
shadowNearPlaneOffset: 3
|
|
||||||
shadowCascade2Split: 0.33333334
|
|
||||||
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
|
|
||||||
shadowmaskMode: 0
|
|
||||||
skinWeights: 1
|
|
||||||
textureQuality: 1
|
|
||||||
anisotropicTextures: 0
|
|
||||||
antiAliasing: 0
|
|
||||||
softParticles: 0
|
|
||||||
softVegetation: 0
|
|
||||||
realtimeReflectionProbes: 0
|
|
||||||
billboardsFaceCameraPosition: 0
|
|
||||||
vSyncCount: 0
|
|
||||||
lodBias: 0.3
|
|
||||||
maximumLODLevel: 0
|
|
||||||
streamingMipmapsActive: 0
|
|
||||||
streamingMipmapsAddAllCameras: 1
|
|
||||||
streamingMipmapsMemoryBudget: 512
|
|
||||||
streamingMipmapsRenderersPerFrame: 512
|
|
||||||
streamingMipmapsMaxLevelReduction: 2
|
|
||||||
streamingMipmapsMaxFileIORequests: 1024
|
|
||||||
particleRaycastBudget: 4
|
|
||||||
asyncUploadTimeSlice: 2
|
|
||||||
asyncUploadBufferSize: 16
|
|
||||||
asyncUploadPersistentBuffer: 1
|
|
||||||
resolutionScalingFixedDPIFactor: 1
|
|
||||||
customRenderPipeline: {fileID: 0}
|
|
||||||
excludedTargetPlatforms: []
|
|
||||||
- serializedVersion: 2
|
|
||||||
name: Low
|
|
||||||
pixelLightCount: 0
|
|
||||||
shadows: 0
|
|
||||||
shadowResolution: 0
|
|
||||||
shadowProjection: 1
|
|
||||||
shadowCascades: 1
|
|
||||||
shadowDistance: 20
|
|
||||||
shadowNearPlaneOffset: 3
|
|
||||||
shadowCascade2Split: 0.33333334
|
|
||||||
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
|
|
||||||
shadowmaskMode: 0
|
|
||||||
skinWeights: 2
|
|
||||||
textureQuality: 0
|
|
||||||
anisotropicTextures: 0
|
|
||||||
antiAliasing: 0
|
|
||||||
softParticles: 0
|
|
||||||
softVegetation: 0
|
|
||||||
realtimeReflectionProbes: 0
|
|
||||||
billboardsFaceCameraPosition: 0
|
|
||||||
vSyncCount: 0
|
|
||||||
lodBias: 0.4
|
|
||||||
maximumLODLevel: 0
|
|
||||||
streamingMipmapsActive: 0
|
|
||||||
streamingMipmapsAddAllCameras: 1
|
|
||||||
streamingMipmapsMemoryBudget: 512
|
|
||||||
streamingMipmapsRenderersPerFrame: 512
|
|
||||||
streamingMipmapsMaxLevelReduction: 2
|
|
||||||
streamingMipmapsMaxFileIORequests: 1024
|
|
||||||
particleRaycastBudget: 16
|
|
||||||
asyncUploadTimeSlice: 2
|
|
||||||
asyncUploadBufferSize: 16
|
|
||||||
asyncUploadPersistentBuffer: 1
|
|
||||||
resolutionScalingFixedDPIFactor: 1
|
|
||||||
customRenderPipeline: {fileID: 0}
|
|
||||||
excludedTargetPlatforms: []
|
|
||||||
- serializedVersion: 2
|
|
||||||
name: Medium
|
|
||||||
pixelLightCount: 1
|
|
||||||
shadows: 1
|
|
||||||
shadowResolution: 0
|
|
||||||
shadowProjection: 1
|
|
||||||
shadowCascades: 1
|
|
||||||
shadowDistance: 20
|
|
||||||
shadowNearPlaneOffset: 3
|
|
||||||
shadowCascade2Split: 0.33333334
|
|
||||||
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
|
|
||||||
shadowmaskMode: 0
|
|
||||||
skinWeights: 2
|
|
||||||
textureQuality: 0
|
|
||||||
anisotropicTextures: 1
|
|
||||||
antiAliasing: 0
|
|
||||||
softParticles: 0
|
|
||||||
softVegetation: 0
|
|
||||||
realtimeReflectionProbes: 0
|
|
||||||
billboardsFaceCameraPosition: 0
|
|
||||||
vSyncCount: 1
|
|
||||||
lodBias: 0.7
|
|
||||||
maximumLODLevel: 0
|
|
||||||
streamingMipmapsActive: 0
|
|
||||||
streamingMipmapsAddAllCameras: 1
|
|
||||||
streamingMipmapsMemoryBudget: 512
|
|
||||||
streamingMipmapsRenderersPerFrame: 512
|
|
||||||
streamingMipmapsMaxLevelReduction: 2
|
|
||||||
streamingMipmapsMaxFileIORequests: 1024
|
|
||||||
particleRaycastBudget: 64
|
|
||||||
asyncUploadTimeSlice: 2
|
|
||||||
asyncUploadBufferSize: 16
|
|
||||||
asyncUploadPersistentBuffer: 1
|
|
||||||
resolutionScalingFixedDPIFactor: 1
|
|
||||||
customRenderPipeline: {fileID: 0}
|
|
||||||
excludedTargetPlatforms: []
|
|
||||||
- serializedVersion: 2
|
|
||||||
name: High
|
|
||||||
pixelLightCount: 2
|
|
||||||
shadows: 2
|
|
||||||
shadowResolution: 1
|
|
||||||
shadowProjection: 1
|
|
||||||
shadowCascades: 2
|
|
||||||
shadowDistance: 40
|
|
||||||
shadowNearPlaneOffset: 3
|
|
||||||
shadowCascade2Split: 0.33333334
|
|
||||||
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
|
|
||||||
shadowmaskMode: 1
|
|
||||||
skinWeights: 2
|
|
||||||
textureQuality: 0
|
|
||||||
anisotropicTextures: 1
|
|
||||||
antiAliasing: 0
|
|
||||||
softParticles: 0
|
|
||||||
softVegetation: 1
|
|
||||||
realtimeReflectionProbes: 1
|
|
||||||
billboardsFaceCameraPosition: 1
|
|
||||||
vSyncCount: 1
|
|
||||||
lodBias: 1
|
|
||||||
maximumLODLevel: 0
|
|
||||||
streamingMipmapsActive: 0
|
|
||||||
streamingMipmapsAddAllCameras: 1
|
|
||||||
streamingMipmapsMemoryBudget: 512
|
|
||||||
streamingMipmapsRenderersPerFrame: 512
|
|
||||||
streamingMipmapsMaxLevelReduction: 2
|
|
||||||
streamingMipmapsMaxFileIORequests: 1024
|
|
||||||
particleRaycastBudget: 256
|
|
||||||
asyncUploadTimeSlice: 2
|
|
||||||
asyncUploadBufferSize: 16
|
|
||||||
asyncUploadPersistentBuffer: 1
|
|
||||||
resolutionScalingFixedDPIFactor: 1
|
|
||||||
customRenderPipeline: {fileID: 0}
|
|
||||||
excludedTargetPlatforms: []
|
|
||||||
- serializedVersion: 2
|
|
||||||
name: Very High
|
|
||||||
pixelLightCount: 3
|
|
||||||
shadows: 2
|
|
||||||
shadowResolution: 2
|
|
||||||
shadowProjection: 1
|
|
||||||
shadowCascades: 2
|
|
||||||
shadowDistance: 70
|
|
||||||
shadowNearPlaneOffset: 3
|
|
||||||
shadowCascade2Split: 0.33333334
|
|
||||||
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
|
|
||||||
shadowmaskMode: 1
|
|
||||||
skinWeights: 4
|
|
||||||
textureQuality: 0
|
|
||||||
anisotropicTextures: 2
|
|
||||||
antiAliasing: 2
|
|
||||||
softParticles: 1
|
|
||||||
softVegetation: 1
|
|
||||||
realtimeReflectionProbes: 1
|
|
||||||
billboardsFaceCameraPosition: 1
|
|
||||||
vSyncCount: 1
|
|
||||||
lodBias: 1.5
|
|
||||||
maximumLODLevel: 0
|
|
||||||
streamingMipmapsActive: 0
|
|
||||||
streamingMipmapsAddAllCameras: 1
|
|
||||||
streamingMipmapsMemoryBudget: 512
|
|
||||||
streamingMipmapsRenderersPerFrame: 512
|
|
||||||
streamingMipmapsMaxLevelReduction: 2
|
|
||||||
streamingMipmapsMaxFileIORequests: 1024
|
|
||||||
particleRaycastBudget: 1024
|
|
||||||
asyncUploadTimeSlice: 2
|
|
||||||
asyncUploadBufferSize: 16
|
|
||||||
asyncUploadPersistentBuffer: 1
|
|
||||||
resolutionScalingFixedDPIFactor: 1
|
|
||||||
customRenderPipeline: {fileID: 0}
|
|
||||||
excludedTargetPlatforms: []
|
|
||||||
- serializedVersion: 2
|
|
||||||
name: Ultra
|
|
||||||
pixelLightCount: 4
|
|
||||||
shadows: 2
|
|
||||||
shadowResolution: 2
|
|
||||||
shadowProjection: 1
|
|
||||||
shadowCascades: 4
|
|
||||||
shadowDistance: 150
|
|
||||||
shadowNearPlaneOffset: 3
|
|
||||||
shadowCascade2Split: 0.33333334
|
|
||||||
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
|
|
||||||
shadowmaskMode: 1
|
|
||||||
skinWeights: 255
|
|
||||||
textureQuality: 0
|
|
||||||
anisotropicTextures: 2
|
|
||||||
antiAliasing: 2
|
|
||||||
softParticles: 1
|
|
||||||
softVegetation: 1
|
|
||||||
realtimeReflectionProbes: 1
|
|
||||||
billboardsFaceCameraPosition: 1
|
|
||||||
vSyncCount: 1
|
|
||||||
lodBias: 2
|
|
||||||
maximumLODLevel: 0
|
|
||||||
streamingMipmapsActive: 0
|
|
||||||
streamingMipmapsAddAllCameras: 1
|
|
||||||
streamingMipmapsMemoryBudget: 512
|
|
||||||
streamingMipmapsRenderersPerFrame: 512
|
|
||||||
streamingMipmapsMaxLevelReduction: 2
|
|
||||||
streamingMipmapsMaxFileIORequests: 1024
|
|
||||||
particleRaycastBudget: 4096
|
|
||||||
asyncUploadTimeSlice: 2
|
|
||||||
asyncUploadBufferSize: 16
|
|
||||||
asyncUploadPersistentBuffer: 1
|
|
||||||
resolutionScalingFixedDPIFactor: 1
|
|
||||||
customRenderPipeline: {fileID: 0}
|
|
||||||
excludedTargetPlatforms: []
|
|
||||||
m_PerPlatformDefaultQuality:
|
|
||||||
Android: 2
|
|
||||||
Lumin: 5
|
|
||||||
Nintendo Switch: 5
|
|
||||||
PS4: 5
|
|
||||||
Stadia: 5
|
|
||||||
Standalone: 5
|
|
||||||
WebGL: 3
|
|
||||||
Windows Store Apps: 5
|
|
||||||
XboxOne: 5
|
|
||||||
iPhone: 2
|
|
||||||
tvOS: 2
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user