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
|
||||
- run: dotnet build ObservableCollection.WithoutSandbox.slnf -c Debug
|
||||
- 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
|
||||
|
||||
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:
|
||||
needs: [update-packagejson]
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- run: echo ${{ needs.update-packagejson.outputs.sha }}
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ needs.update-packagejson.outputs.sha }}
|
||||
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
|
||||
# build and pack
|
||||
- run: dotnet build ObservableCollection.WithoutSandbox.slnf -c Release -p:Version=${{ inputs.tag }}
|
||||
@ -40,58 +29,14 @@ jobs:
|
||||
name: nuget
|
||||
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
|
||||
create-release:
|
||||
needs: [update-packagejson, build-unity]
|
||||
needs: [build-dotnet]
|
||||
uses: Cysharp/Actions/.github/workflows/create-release.yaml@main
|
||||
with:
|
||||
commit-id: ${{ needs.update-packagejson.outputs.sha }}
|
||||
commit-id: ${{ github.sha }}
|
||||
dry-run: ${{ inputs.dry-run }}
|
||||
tag: ${{ inputs.tag }}
|
||||
nuget-push: true
|
||||
release-upload: true
|
||||
release-asset-path: ./ObservableCollections.${{ inputs.tag }}.unitypackage/ObservableCollections.${{ inputs.tag }}.unitypackage
|
||||
release-upload: false
|
||||
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
|
||||
---
|
||||
|
||||
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.
|
||||
|
||||
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