├── README.md ├── README.md.meta ├── native-ecslite.asmdef ├── native-ecslite.asmdef.meta ├── package.json ├── package.json.meta ├── src.meta └── src ├── Base.meta ├── Base ├── ILazyReadWriteNativeEntityOperations.cs ├── ILazyReadWriteNativeEntityOperations.cs.meta ├── INativeEntityOperations.cs ├── INativeEntityOperations.cs.meta ├── INativeEntityOperationsTypeless.cs ├── INativeEntityOperationsTypeless.cs.meta ├── IReadOnlyNativeEntityOperations.cs ├── IReadOnlyNativeEntityOperations.cs.meta ├── IReadWriteNativeEntityOperations.cs └── IReadWriteNativeEntityOperations.cs.meta ├── Context.meta ├── Context ├── ContextOperationsHolder.cs ├── ContextOperationsHolder.cs.meta ├── OperationsContext.cs └── OperationsContext.cs.meta ├── EcsGameSystems.meta ├── EcsGameSystems ├── BaseGameJobSystem.cs └── BaseGameJobSystem.cs.meta ├── Extensions.meta ├── Extensions ├── NativeOperationsServiceExtensions.cs ├── NativeOperationsServiceExtensions.cs.meta ├── UnsafeExtensions.cs ├── UnsafeExtensions.cs.meta ├── WrappedDataExtensions.cs └── WrappedDataExtensions.cs.meta ├── FilterWrapper.meta ├── FilterWrapper ├── NativeFilterWrapper.cs └── NativeFilterWrapper.cs.meta ├── LazyReadWriteNativeEntityOperations.cs ├── LazyReadWriteNativeEntityOperations.cs.meta ├── NativeOperationsService.meta ├── NativeOperationsService ├── Base.meta ├── Base │ ├── INativeOperationsService.cs │ └── INativeOperationsService.cs.meta ├── NativeOperationsService.cs └── NativeOperationsService.cs.meta ├── NativeOperationsWrapper.meta ├── NativeOperationsWrapper ├── Base.meta ├── Base │ ├── INativeOperationsWrapper.cs │ ├── INativeOperationsWrapper.cs.meta │ ├── INativeOperationsWrapperTypeless.cs │ ├── INativeOperationsWrapperTypeless.cs.meta │ ├── INativeReadWriteOperationsWrapper.cs │ └── INativeReadWriteOperationsWrapper.cs.meta ├── NativeLazyReadWriteOperationsWrapper.cs ├── NativeLazyReadWriteOperationsWrapper.cs.meta ├── NativeReadOnlyOperationsWrapper.cs ├── NativeReadOnlyOperationsWrapper.cs.meta ├── NativeReadWriteOperationsWrapper.cs └── NativeReadWriteOperationsWrapper.cs.meta ├── ReadOnlyNativeEntityOperations.cs ├── ReadOnlyNativeEntityOperations.cs.meta ├── ReadWriteNativeEntityOperations.cs ├── ReadWriteNativeEntityOperations.cs.meta ├── ReadWriteOperationsData.meta ├── ReadWriteOperationsData ├── Base.meta ├── Base │ ├── IReadWriteOperationsInternalData.cs │ └── IReadWriteOperationsInternalData.cs.meta ├── ReadWriteOperationsInternalData.cs └── ReadWriteOperationsInternalData.cs.meta ├── WrappedData.meta └── WrappedData ├── NativeWrappedData.cs ├── NativeWrappedData.cs.meta ├── ReadOnlyNativeWrappedData.cs └── ReadOnlyNativeWrappedData.cs.meta /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Native extension for Leopotam [ecslite](https://github.com/Leopotam/ecslite) 3 | 4 | An extension for Leopotam ecslite framework with full per entity operations support from Unity Job system side 5 | 6 | 7 | ## Badges 8 | [![MIT License](https://img.shields.io/apm/l/atomic-design-ui.svg?)](https://github.com/tterb/atomic-design-ui/blob/master/LICENSEs) 9 | [![Downloads](https://img.shields.io/github/downloads/odingamesdev/native-ecslite/total.svg)](https://github.com/odingamesdev/native-ecslite/releases) 10 | ## Documentation 11 | 12 | ## Usage/Examples 13 | 14 | System example: 15 | ```csharp 16 | class ExampleSystem : BaseGameJobSystem 17 | { 18 | // Or you can provide operations service that has been created in DI container 19 | public override INativeOperationsService ProvideNativeOperationsService() 20 | => new NativeOperationsService(); 21 | 22 | public override int GetChunkSize(EcsSystems systems) 23 | => 10; 24 | 25 | public override EcsFilter GetFilter(EcsWorld world) 26 | { 27 | return world.Filter().Inc().End(); 28 | } 29 | 30 | // Here you should set entities pool 31 | public override void SetData(EcsSystems systems, ref TJob job) 32 | { 33 | var world = systems.GetWorld(); 34 | var filter = GetFilter() 35 | 36 | job.Filter = GetFilterWrapper(filter); 37 | 38 | job.Component1Operations = OperationsService 39 | .GetReadOnlyOperations(systems); 40 | 41 | job.Component2Operations = OperationsService 42 | .GetReadOnlyOperations(systems); 43 | 44 | job.Component3Operations = OperationsService 45 | .GetReadWriteOperations(systems); 46 | } 47 | } 48 | ``` 49 | Components example: 50 | ```csharp 51 | struct Component1 52 | { 53 | int a; 54 | } 55 | 56 | struct Component2 57 | { 58 | int b; 59 | } 60 | 61 | struct Component3 62 | { 63 | int c; 64 | } 65 | ``` 66 | Job example: 67 | ```csharp 68 | [BurstCompile] 69 | public struct SummAndWriteJob : IJobParallelFor 70 | { 71 | public NativeFilterWrapper Filter; 72 | 73 | public ReadOnlyNativeEntityOperations Component1Operations; 74 | public ReadWriteNativeEntityOperations Component2Operations; 75 | public ReadWriteNativeEntityOperations Component3Operations; 76 | 77 | public void Execute(int index) 78 | { 79 | var entity = Filter.Entity(index); 80 | 81 | var component1Value = Component1Operations.Get(entity); 82 | var component2Value = Component2Operations.Get(entity); 83 | 84 | ref var component3Value = ref Component3Operations.Add(entity); 85 | 86 | component3Value = component1Value + component2Value; 87 | 88 | Component2Operations.Del(entity); 89 | } 90 | } 91 | ``` 92 | And that's all! All you need is to operate over entity values. 93 | You also can use this mechanism outside ecs system, for example in some kind of service, in this sutuation you need to call `ApplyOperations(EcsSystems systems)` on `NativeOperationsService` by yourself 94 | 95 | ## FAQ 96 | ## Know problems 97 | 1. No AutoReset 98 | 2. No internal arrays resizing. Be careful or specify pool arrays size in EcsWorld.Config 99 | 3. No way to create entity inside Job 100 | 4. Not true entity deletion in Job 101 | 102 | ## Future plans 103 | 104 | 1. Entity creation in Job 105 | 2. True entity deletion in Job 106 | 3. Find ways to resize internal managed arrays in Job that has been wrapped to NativeArray 107 | 4. Add AutoReset 108 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6c6a255e443a2cc409993081ca7df4eb 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /native-ecslite.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "native-ecslite", 3 | "rootNamespace": "OdinGames.EcsLite.Native", 4 | "references": [ 5 | "GUID:e59bf9fc7d5a44b18a819a92edd46163", 6 | "GUID:e0cd26848372d4e5c891c569017e11f1", 7 | "GUID:2665a8d13d1b3f18800f46e256720795" 8 | ], 9 | "includePlatforms": [], 10 | "excludePlatforms": [], 11 | "allowUnsafeCode": true, 12 | "overrideReferences": false, 13 | "precompiledReferences": [], 14 | "autoReferenced": true, 15 | "defineConstraints": [], 16 | "versionDefines": [], 17 | "noEngineReferences": false 18 | } -------------------------------------------------------------------------------- /native-ecslite.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 48c6ea1fee8caa742b3f93e15a36783a 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.odingames.native-ecslite", 3 | "author": "Odin Games", 4 | "displayName": "Native LeoECS Lite", 5 | "description": "Extension for LeoECS Lite with full per entity operations support from Unity Job native side", 6 | "version": "0.7.0", 7 | "keywords": [ 8 | "leoecslite", 9 | "leoecs", 10 | "ecs", 11 | "performance", 12 | "odingames", 13 | "nativeecslite", 14 | "jobs", 15 | "burst" 16 | ], 17 | "dependencies": {}, 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/odingamesdev/native-ecslite.git" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 94595b7fdb8838c419aa707831a24ff4 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /src.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 129853874b575b745b5f2a913a27d900 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /src/Base.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 26496508ddb645d9b991dd34924d3a0f 3 | timeCreated: 1641989009 -------------------------------------------------------------------------------- /src/Base/ILazyReadWriteNativeEntityOperations.cs: -------------------------------------------------------------------------------- 1 | using Leopotam.EcsLite; 2 | using OdinGames.EcsLite.Native.NativeOperations.ReadWriteOperationsData; 3 | using OdinGames.EcsLite.Native.NativeOperationsWrapper; 4 | using OdinGames.EcsLite.Native.WrappedData; 5 | using Unity.Burst; 6 | using Unity.Collections; 7 | 8 | namespace OdinGames.EcsLite.Native.Base 9 | { 10 | public interface ILazyReadWriteNativeEntityOperations : INativeEntityOperations where T : unmanaged 11 | { 12 | public void Init(ReadWriteOperationsInternalData internalData); 13 | 14 | void Del(int entity); 15 | 16 | void DelEntity(int entity); 17 | 18 | ref T GetRef(int entity); 19 | } 20 | } -------------------------------------------------------------------------------- /src/Base/ILazyReadWriteNativeEntityOperations.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 219b73bc4b5940dcaf79cfa4cf3c4bae 3 | timeCreated: 1644245988 -------------------------------------------------------------------------------- /src/Base/INativeEntityOperations.cs: -------------------------------------------------------------------------------- 1 | namespace OdinGames.EcsLite.Native.Base 2 | { 3 | public interface INativeEntityOperations : INativeEntityOperationsTypeless where T : unmanaged 4 | { 5 | T Get(int entity); 6 | } 7 | } -------------------------------------------------------------------------------- /src/Base/INativeEntityOperations.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 36cb8d2b905b42718fcd06269f746876 3 | timeCreated: 1642621304 -------------------------------------------------------------------------------- /src/Base/INativeEntityOperationsTypeless.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace OdinGames.EcsLite.Native.Base 4 | { 5 | public interface INativeEntityOperationsTypeless : IDisposable 6 | { 7 | bool Has(int entity); 8 | } 9 | } -------------------------------------------------------------------------------- /src/Base/INativeEntityOperationsTypeless.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c65aaab2ebbd406d8d4de2eaf5d88e5c 3 | timeCreated: 1641989429 -------------------------------------------------------------------------------- /src/Base/IReadOnlyNativeEntityOperations.cs: -------------------------------------------------------------------------------- 1 | using OdinGames.EcsLite.Native.WrappedData; 2 | 3 | namespace OdinGames.EcsLite.Native.Base 4 | { 5 | public interface IReadOnlyNativeEntityOperations : INativeEntityOperations where T : unmanaged 6 | { 7 | void Init(ReadOnlyNativeWrappedData sparseItems, 8 | ReadOnlyNativeWrappedData denseItems); 9 | } 10 | } -------------------------------------------------------------------------------- /src/Base/IReadOnlyNativeEntityOperations.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eb8f56e5d28542e786f4e5e3440e39c7 3 | timeCreated: 1642454583 -------------------------------------------------------------------------------- /src/Base/IReadWriteNativeEntityOperations.cs: -------------------------------------------------------------------------------- 1 | namespace OdinGames.EcsLite.Native.Base 2 | { 3 | public interface IReadWriteNativeEntityOperations : ILazyReadWriteNativeEntityOperations where T : unmanaged 4 | { 5 | void Add(int entity, T value); 6 | 7 | ref T Add(int entity); 8 | } 9 | } -------------------------------------------------------------------------------- /src/Base/IReadWriteNativeEntityOperations.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 736156a705724280b84d96ac3adf641c 3 | timeCreated: 1641989021 -------------------------------------------------------------------------------- /src/Context.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 15da3e9e39f34edaa05840b340c1d795 3 | timeCreated: 1644830730 -------------------------------------------------------------------------------- /src/Context/ContextOperationsHolder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Leopotam.EcsLite; 4 | using OdinGames.EcsLite.Native.NativeOperations.FilterWrapper; 5 | using OdinGames.EcsLite.Native.NativeOperationsWrapper; 6 | using OdinGames.EcsLite.Native.NativeOperationsWrapper.Base; 7 | 8 | namespace OdinGames.EcsLite.Native.Context 9 | { 10 | public class ContextOperationsHolder : IDisposable 11 | { 12 | private readonly Dictionary _readOnlyOperations; 13 | 14 | private readonly Dictionary _readWriteOperations; 15 | 16 | private readonly HashSet _usedReadWriteOperationsWrappers; 17 | private readonly HashSet _usedReadOnlyOperationsWrappers; 18 | 19 | private readonly List _nativeFilters; 20 | 21 | public ContextOperationsHolder() 22 | { 23 | _readOnlyOperations = new Dictionary(20); 24 | _readWriteOperations = new Dictionary(20); 25 | _usedReadWriteOperationsWrappers = new HashSet(); 26 | _usedReadOnlyOperationsWrappers = new HashSet(); 27 | _nativeFilters = new List(); 28 | } 29 | 30 | public void RegisterFilter(NativeFilterWrapper filterWrapper) 31 | { 32 | #if UNITY_EDITOR 33 | _nativeFilters.Add(filterWrapper); 34 | #endif 35 | } 36 | 37 | public NativeReadOnlyOperationsWrapper GetReadOnlyOperationsWrapper() 38 | where T : unmanaged 39 | { 40 | var typeofT = typeof(T); 41 | 42 | NativeReadOnlyOperationsWrapper wrapper; 43 | if (_readOnlyOperations.ContainsKey(typeofT)) 44 | { 45 | wrapper = (NativeReadOnlyOperationsWrapper) _readOnlyOperations[typeofT]; 46 | } 47 | else 48 | { 49 | wrapper = new NativeReadOnlyOperationsWrapper(); 50 | _readOnlyOperations.Add(typeofT, wrapper); 51 | } 52 | 53 | #if UNITY_EDITOR 54 | _usedReadOnlyOperationsWrappers.Add(wrapper); 55 | #endif 56 | 57 | return wrapper; 58 | } 59 | 60 | public NativeLazyReadWriteOperationsWrapper GetLazyReadWriteOperationsWrapper() 61 | where T : unmanaged 62 | { 63 | var typeofT = typeof(T); 64 | 65 | NativeLazyReadWriteOperationsWrapper wrapper; 66 | if (_readWriteOperations.ContainsKey(typeofT)) 67 | { 68 | wrapper = (NativeLazyReadWriteOperationsWrapper) _readWriteOperations[typeofT]; 69 | } 70 | else 71 | { 72 | wrapper = new NativeLazyReadWriteOperationsWrapper(); 73 | _readWriteOperations.Add(typeofT, wrapper); 74 | } 75 | 76 | _usedReadWriteOperationsWrappers.Add(wrapper); 77 | 78 | return wrapper; 79 | } 80 | 81 | public NativeReadWriteOperationsWrapper GetReadWriteOperationsWrapper() 82 | where T : unmanaged 83 | { 84 | var typeofT = typeof(T); 85 | 86 | NativeReadWriteOperationsWrapper wrapper; 87 | if (_readWriteOperations.ContainsKey(typeofT)) 88 | { 89 | wrapper = (NativeReadWriteOperationsWrapper) _readWriteOperations[typeofT]; 90 | } 91 | else 92 | { 93 | wrapper = new NativeReadWriteOperationsWrapper(); 94 | _readWriteOperations.Add(typeofT, wrapper); 95 | } 96 | 97 | _usedReadWriteOperationsWrappers.Add(wrapper); 98 | 99 | return wrapper; 100 | } 101 | 102 | public void ApplyContextOperations(EcsSystems systems) 103 | { 104 | foreach (var operations in _usedReadWriteOperationsWrappers) 105 | { 106 | ApplyReadWriteOperations(systems, operations); 107 | 108 | operations.Dispose(); 109 | } 110 | 111 | #if UNITY_EDITOR 112 | foreach (var operationsPair in _usedReadOnlyOperationsWrappers) 113 | { 114 | operationsPair.Dispose(); 115 | } 116 | 117 | foreach (var filter in _nativeFilters) 118 | { 119 | filter.Dispose(); 120 | } 121 | 122 | _usedReadOnlyOperationsWrappers.Clear(); 123 | _nativeFilters.Clear(); 124 | #endif 125 | 126 | _usedReadWriteOperationsWrappers.Clear(); 127 | } 128 | 129 | private void ApplyReadWriteOperations(EcsSystems systems, INativeReadWriteOperationsWrapper operationsWrapper) 130 | { 131 | ApplyAddComponents(systems, operationsWrapper); 132 | ApplyRemoveComponents(systems, operationsWrapper); 133 | ApplyRemoveEntities(systems, operationsWrapper); 134 | } 135 | 136 | private void ApplyAddComponents(EcsSystems systems, INativeReadWriteOperationsWrapper readWriteNativeEntityOperationsWrapper) 137 | { 138 | var world = systems.GetWorld(); 139 | 140 | var id = readWriteNativeEntityOperationsWrapper.ID; 141 | foreach (var entity in readWriteNativeEntityOperationsWrapper.AddCache) 142 | { 143 | world.OnEntityChange(entity, id, true); 144 | #if DEBUG || LEOECSLITE_WORLD_EVENTS 145 | world.RaiseEntityChangeEvent(entity); 146 | #endif 147 | } 148 | } 149 | 150 | private void ApplyRemoveComponents(EcsSystems systems, INativeReadWriteOperationsWrapper readWriteNativeEntityOperationsWrapper) 151 | { 152 | var world = systems.GetWorld(); 153 | 154 | var id = readWriteNativeEntityOperationsWrapper.ID; 155 | foreach (var entity in readWriteNativeEntityOperationsWrapper.DeleteCache) 156 | { 157 | world.OnEntityChange(entity, id, false); 158 | #if DEBUG || LEOECSLITE_WORLD_EVENTS 159 | world.RaiseEntityChangeEvent(entity); 160 | #endif 161 | } 162 | } 163 | 164 | private void ApplyRemoveEntities(EcsSystems systems, INativeReadWriteOperationsWrapper nativeReadWriteOperationsWrapper) 165 | { 166 | var world = systems.GetWorld(); 167 | foreach (int entity in nativeReadWriteOperationsWrapper.EntitiesToRemove) 168 | { 169 | world.DelEntity(entity); 170 | } 171 | } 172 | 173 | public void Dispose() 174 | { 175 | foreach (var wrapper in _usedReadOnlyOperationsWrappers) 176 | { 177 | wrapper.Dispose(); 178 | } 179 | 180 | foreach (var wrapper in _usedReadWriteOperationsWrappers) 181 | { 182 | wrapper.Dispose(); 183 | } 184 | } 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /src/Context/ContextOperationsHolder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 63120b13d7b743e2b3bd1ea666b0fdb0 3 | timeCreated: 1644830769 -------------------------------------------------------------------------------- /src/Context/OperationsContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace OdinGames.EcsLite.Native.Context 4 | { 5 | public class OperationsContext 6 | { 7 | private Guid _guid; 8 | 9 | public static OperationsContext Create() 10 | { 11 | return new OperationsContext 12 | { 13 | _guid = Guid.NewGuid() 14 | }; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/Context/OperationsContext.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3c1732638cfa4f2f86b12012d751bd2b 3 | timeCreated: 1644830735 -------------------------------------------------------------------------------- /src/EcsGameSystems.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e0c2581cbf4349fc96a6e888fce13676 3 | timeCreated: 1643324194 -------------------------------------------------------------------------------- /src/EcsGameSystems/BaseGameJobSystem.cs: -------------------------------------------------------------------------------- 1 | using Leopotam.EcsLite; 2 | using OdinGames.EcsLite.Native.NativeOperationsService.Base; 3 | using Unity.Jobs; 4 | 5 | namespace OdinGames.EcsLite.Native.EcsGameSystems 6 | { 7 | /// 8 | /// Sample realization of base game system that Schedule job of specified type 9 | /// 10 | /// 11 | public abstract class BaseGameJobSystem : IEcsRunSystem where TJob : struct 12 | { 13 | private EcsFilter _filter; 14 | 15 | protected INativeOperationsService OperationsService; 16 | 17 | protected abstract INativeOperationsService ProvideNativeOperationsService(); 18 | 19 | protected abstract void Schedule(ref TJob job); 20 | 21 | protected abstract void SetData(EcsSystems systems, ref TJob job); 22 | 23 | protected virtual void GetData(EcsSystems systems, ref TJob job) { } 24 | 25 | protected abstract int GetChunkSize(EcsSystems systems); 26 | 27 | protected abstract EcsFilter GetFilter(EcsWorld world); 28 | 29 | protected virtual bool RunConditions(EcsSystems systems) => true; 30 | 31 | public void Run(EcsSystems systems) 32 | { 33 | if (!RunConditions(systems)) return; 34 | OperationsService ??= ProvideNativeOperationsService(); 35 | _filter ??= GetFilter(systems.GetWorld()); 36 | 37 | var filterEntitiesCount = _filter.GetEntitiesCount(); 38 | if (filterEntitiesCount > 0) 39 | { 40 | TJob job = default; 41 | SetData(systems, ref job); 42 | 43 | Schedule(ref job); 44 | 45 | OperationsService.ApplyOperations(systems); 46 | 47 | GetData(systems, ref job); 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/EcsGameSystems/BaseGameJobSystem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b74bf4f1a4b0403ca3a58e405fccc724 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/Extensions.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 19e8c5e262bc435e9e1b85d01561d44a 3 | timeCreated: 1643322924 -------------------------------------------------------------------------------- /src/Extensions/NativeOperationsServiceExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Leopotam.EcsLite; 3 | using OdinGames.EcsLite.Native.NativeOperationsWrapper; 4 | using OdinGames.EcsLite.Native.NativeOperationsWrapper.Base; 5 | 6 | namespace OdinGames.EcsLite.Native.Extensions 7 | { 8 | public static class NativeOperationsServiceExtensions 9 | { 10 | public static bool GetResetMethod(INativeOperationsWrapper wrapper) where T : unmanaged 11 | { 12 | var isAutoReset = typeof (IEcsAutoReset).IsAssignableFrom (typeof(T)); 13 | 14 | if (!isAutoReset) 15 | return false; 16 | 17 | var autoResetMethod = typeof(T).GetMethod(nameof(IEcsAutoReset.AutoReset)); 18 | 19 | var autoResetDelegate = (NativeReadWriteOperationsWrapper.AutoResetDelegate)Delegate 20 | .CreateDelegate(typeof(NativeReadWriteOperationsWrapper.AutoResetDelegate), 21 | null, 22 | autoResetMethod); 23 | 24 | //wrapper.ResetDelegate = autoResetDelegate; 25 | 26 | // wrapper.NativeResetDelegate = 27 | // new FunctionPointer.AutoResetDelegate>(Marshal.GetFunctionPointerForDelegate(wrapper.ResetDelegate)); 28 | 29 | return true; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/Extensions/NativeOperationsServiceExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: edf995d9235743739cac79b3b0ad8031 3 | timeCreated: 1642869757 -------------------------------------------------------------------------------- /src/Extensions/UnsafeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using Unity.Collections; 4 | using Unity.Collections.LowLevel.Unsafe; 5 | 6 | namespace OdinGames.EcsLite.Native.Extensions 7 | { 8 | public static unsafe class UnsafeExtensions 9 | { 10 | internal static ref T GetRef(this NativeArray array, int index) 11 | where T : struct 12 | { 13 | if (index < 0 || index >= array.Length) 14 | throw new ArgumentOutOfRangeException(nameof(index)); 15 | unsafe 16 | { 17 | return ref UnsafeUtility.ArrayElementAsRef(array.GetUnsafePtr(), index); 18 | } 19 | } 20 | 21 | public struct SharedIndex : IDisposable 22 | { 23 | [NativeDisableUnsafePtrRestriction] 24 | private readonly int* _index; 25 | 26 | private readonly Allocator _allocator; 27 | 28 | public ref int Value => ref *_index; 29 | 30 | // Use this if you want a Job shared index that value can be safely changed between threads 31 | public SharedIndex(Allocator allocator = Allocator.TempJob, int startValue = 0) 32 | { 33 | _index = Alloc(allocator, startValue); 34 | _allocator = allocator; 35 | } 36 | 37 | // Use this if you want to create Shared index from existing variable 38 | // For example, if you have Managed and Native API and share some variables over them 39 | public SharedIndex(ref int index) 40 | { 41 | fixed (int* indexPtr = &index) 42 | { 43 | _index = indexPtr; 44 | } 45 | 46 | _allocator = Allocator.None; 47 | } 48 | 49 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 50 | public int PostIncrement() 51 | { 52 | var oldValue = *_index; 53 | System.Threading.Interlocked.Increment(ref *_index); 54 | return oldValue; 55 | } 56 | 57 | public static SharedIndex operator ++(SharedIndex index) 58 | { 59 | index.PostIncrement(); 60 | return index; 61 | } 62 | 63 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 64 | public ref int PreIncrement() 65 | { 66 | System.Threading.Interlocked.Increment(ref *_index); 67 | return ref Value; 68 | } 69 | 70 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 71 | public ref int PreDecrement() 72 | { 73 | System.Threading.Interlocked.Decrement(ref *_index); 74 | return ref Value; 75 | } 76 | 77 | public void Dispose() 78 | { 79 | if (_allocator != Allocator.None) 80 | Free(_index, _allocator); 81 | } 82 | } 83 | 84 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 85 | public static T* Alloc(Allocator allocator, T defaultValue = default) 86 | where T : unmanaged 87 | { 88 | T* allocated = (T*) UnsafeUtility.Malloc( 89 | sizeof(T), sizeof(T), allocator); 90 | 91 | *allocated = defaultValue; 92 | 93 | return allocated; 94 | } 95 | 96 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 97 | public static void Free(T* pointer, Allocator allocator) 98 | where T : unmanaged 99 | { 100 | UnsafeUtility.Free(pointer, allocator); 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /src/Extensions/UnsafeExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 248a63d5eaf8439abf73fc688b3f8020 3 | timeCreated: 1643322972 -------------------------------------------------------------------------------- /src/Extensions/WrappedDataExtensions.cs: -------------------------------------------------------------------------------- 1 | using OdinGames.EcsLite.Native.WrappedData; 2 | using Unity.Collections; 3 | using Unity.Collections.LowLevel.Unsafe; 4 | 5 | namespace OdinGames.EcsLite.Native.Extensions 6 | { 7 | public static class WrappedDataExtensions 8 | { 9 | public static unsafe NativeWrappedData WrapToNative (this T[] managedData) where T : unmanaged { 10 | fixed (void* ptr = managedData) { 11 | #if UNITY_EDITOR 12 | var nativeData = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray (ptr, managedData.Length, Allocator.None); 13 | var sh = AtomicSafetyHandle.Create (); 14 | NativeArrayUnsafeUtility.SetAtomicSafetyHandle (ref nativeData, sh); 15 | return new NativeWrappedData { Array = nativeData, SafetyHandle = sh }; 16 | #else 17 | return new NativeWrappedData { Array = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray (ptr, managedData.Length, Allocator.None) }; 18 | #endif 19 | } 20 | } 21 | 22 | public static ReadOnlyNativeWrappedData ToReadOnly(this NativeWrappedData wrappedData) 23 | where T : unmanaged 24 | { 25 | ReadOnlyNativeWrappedData readOnlyNativeWrappedData; 26 | 27 | readOnlyNativeWrappedData.Array = wrappedData.Array.AsReadOnly(); 28 | #if UNITY_EDITOR 29 | readOnlyNativeWrappedData.SafetyHandle = wrappedData.SafetyHandle; 30 | #endif 31 | 32 | return readOnlyNativeWrappedData; 33 | } 34 | 35 | public static unsafe ReadOnlyNativeWrappedData WrapToReadOnlyNative (this T[] managedData) where T : unmanaged { 36 | fixed (void* ptr = managedData) { 37 | #if UNITY_EDITOR 38 | var nativeData = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray (ptr, managedData.Length, Allocator.None); 39 | var sh = AtomicSafetyHandle.Create (); 40 | NativeArrayUnsafeUtility.SetAtomicSafetyHandle (ref nativeData, sh); 41 | return new ReadOnlyNativeWrappedData { Array = nativeData.AsReadOnly(), SafetyHandle = sh }; 42 | #else 43 | return new ReadOnlyNativeWrappedData { Array = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray (ptr, managedData.Length, Allocator.None).AsReadOnly() }; 44 | #endif 45 | } 46 | } 47 | 48 | public static void UnwrapFromNative (this ReadOnlyNativeWrappedData sh) where T1 : unmanaged { 49 | #if UNITY_EDITOR 50 | AtomicSafetyHandle.CheckDeallocateAndThrow (sh.SafetyHandle); 51 | AtomicSafetyHandle.Release (sh.SafetyHandle); 52 | #endif 53 | } 54 | 55 | public static void UnwrapFromNative (this NativeWrappedData sh) where T1 : unmanaged { 56 | #if UNITY_EDITOR 57 | AtomicSafetyHandle.CheckDeallocateAndThrow (sh.SafetyHandle); 58 | AtomicSafetyHandle.Release (sh.SafetyHandle); 59 | #endif 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /src/Extensions/WrappedDataExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6f2781ccf36d4c89aba344a7a77999a0 3 | timeCreated: 1643321601 -------------------------------------------------------------------------------- /src/FilterWrapper.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0479c7d9494141338478b6279754acfa 3 | timeCreated: 1644051801 -------------------------------------------------------------------------------- /src/FilterWrapper/NativeFilterWrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Leopotam.EcsLite; 3 | using OdinGames.EcsLite.Native.Extensions; 4 | using OdinGames.EcsLite.Native.WrappedData; 5 | 6 | namespace OdinGames.EcsLite.Native.NativeOperations.FilterWrapper 7 | { 8 | public struct NativeFilterWrapper : IDisposable 9 | { 10 | private ReadOnlyNativeWrappedData _filter; 11 | private int _length; 12 | 13 | public void Init(EcsFilter filter) 14 | { 15 | _filter = filter.GetRawEntities().WrapToReadOnlyNative(); 16 | _length = filter.GetEntitiesCount(); 17 | } 18 | 19 | public int this[int index] 20 | => _filter.Array[index]; 21 | 22 | public int Count() 23 | => _length; 24 | 25 | public void Dispose() 26 | { 27 | _filter.UnwrapFromNative(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/FilterWrapper/NativeFilterWrapper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2c0234c40f194019969bfd2d49acc0d7 3 | timeCreated: 1644051812 -------------------------------------------------------------------------------- /src/LazyReadWriteNativeEntityOperations.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using OdinGames.EcsLite.Native.Base; 3 | using OdinGames.EcsLite.Native.Extensions; 4 | using OdinGames.EcsLite.Native.NativeOperations.ReadWriteOperationsData; 5 | using UnityEngine; 6 | 7 | namespace OdinGames.EcsLite.Native.NativeOperations 8 | { 9 | public struct LazyReadWriteNativeEntityOperations : ILazyReadWriteNativeEntityOperations where T : unmanaged 10 | { 11 | private ReadWriteOperationsInternalData _internalData; 12 | 13 | public void Init(ReadWriteOperationsInternalData internalData) 14 | { 15 | _internalData = internalData; 16 | } 17 | 18 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 19 | public bool Has(int entity) 20 | { 21 | return _internalData.SparseItems.Array[entity] > 0; 22 | } 23 | 24 | // Auto reset to default should be enough because in burst we only have unmanaged value types, which 25 | // overwrites automatically 26 | public void Del(int entity) 27 | { 28 | ref var sparseData = ref _internalData.SparseItems.Array.GetRef(entity); 29 | if (sparseData > 0) 30 | { 31 | _internalData.ComponentsToRemove.AddNoResize(entity); 32 | _internalData.RecycledItems.Array[_internalData.RecycledItemsCount.PostIncrement()] = sparseData; 33 | 34 | if (_internalData.RecycledItemsCount.Value == _internalData.RecycledItems.Array.Length) { 35 | Debug.LogError("Try to increase RecycledItemsCount for pools in EcsWorld Config"); 36 | } 37 | //if (_isAutoReset) 38 | { 39 | // _autoReset.Invoke(ref _denseItems.Array.GetRef(sparseData)); 40 | } 41 | // else 42 | { 43 | _internalData.DenseItems.Array[sparseData] = default; 44 | } 45 | 46 | sparseData = 0; 47 | ref var entityData = ref _internalData.Entities.Array.GetRef(entity); 48 | entityData.ComponentsCount--; 49 | 50 | if (entityData.ComponentsCount == 0) 51 | { 52 | _internalData.EntitiesToRemove.AddNoResize(entity); 53 | } 54 | } 55 | } 56 | 57 | public void DelEntity(int entity) 58 | { 59 | _internalData.EntitiesToRemove.AddNoResize(entity); 60 | } 61 | 62 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 63 | public T Get(int entity) 64 | { 65 | if (!Has(entity)) return Add(entity); 66 | var realIndex = _internalData.SparseItems.Array[entity]; 67 | return _internalData.DenseItems.Array[realIndex]; 68 | } 69 | 70 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 71 | public ref T GetRef(int entity) 72 | { 73 | if (!Has(entity)) return ref Add(entity); 74 | var realIndex = _internalData.SparseItems.Array[entity]; 75 | return ref _internalData.DenseItems.Array.GetRef(realIndex); 76 | } 77 | 78 | private ref T Add(int entity) 79 | { 80 | int idx; 81 | if (_internalData.RecycledItemsCount.Value > 0) 82 | { 83 | idx = _internalData.RecycledItems.Array[_internalData.RecycledItemsCount.PreDecrement()]; 84 | } 85 | else 86 | { 87 | idx = _internalData.DenseItemsCount.Value; 88 | if (_internalData.DenseItemsCount.Value == _internalData.DenseItems.Array.Length) 89 | { 90 | Debug.LogError("For now i have no idea is it possible to resize managed array treated as a NativeArray from job. Try to increase entities count in WorldConfig"); 91 | } 92 | _internalData.DenseItemsCount++; 93 | 94 | //if (_isAutoReset) 95 | // _autoReset.Invoke(ref _denseItems.Array.GetRef(idx)); 96 | } 97 | _internalData.SparseItems[entity] = idx; 98 | _internalData.ComponentsToAdd.AddNoResize(entity); 99 | _internalData.Entities[entity].ComponentsCount++; 100 | return ref _internalData.DenseItems.Array.GetRef(idx); 101 | } 102 | 103 | public void Dispose() 104 | { 105 | _internalData.SparseItems.UnwrapFromNative(); 106 | _internalData.DenseItems.UnwrapFromNative(); 107 | _internalData.RecycledItems.UnwrapFromNative(); 108 | _internalData.Entities.UnwrapFromNative(); 109 | 110 | _internalData.RecycledItemsCount.Dispose(); 111 | _internalData.DenseItemsCount.Dispose(); 112 | } 113 | } 114 | } -------------------------------------------------------------------------------- /src/LazyReadWriteNativeEntityOperations.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ff0742f814a64b17a8f55abfd3dc3cd2 3 | timeCreated: 1644245933 -------------------------------------------------------------------------------- /src/NativeOperationsService.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c72198e72b7a4401ac15cb0d17149ab3 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /src/NativeOperationsService/Base.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d79c1ce5ae1d4e78bfa8dbb520722582 3 | timeCreated: 1641989141 -------------------------------------------------------------------------------- /src/NativeOperationsService/Base/INativeOperationsService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Leopotam.EcsLite; 3 | using OdinGames.EcsLite.Native.Context; 4 | using OdinGames.EcsLite.Native.NativeOperations; 5 | using OdinGames.EcsLite.Native.NativeOperations.FilterWrapper; 6 | using Unity.Collections; 7 | 8 | namespace OdinGames.EcsLite.Native.NativeOperationsService.Base 9 | { 10 | public interface INativeOperationsService : IDisposable 11 | { 12 | void ApplyOperations(EcsSystems systems); 13 | 14 | void ChangeContext(OperationsContext context); 15 | 16 | void ChangeToDefaultContext(); 17 | 18 | ReadOnlyNativeEntityOperations GetReadOnlyOperations(EcsSystems systems) 19 | where T : unmanaged; 20 | 21 | ReadWriteNativeEntityOperations GetReadWriteOperations(EcsSystems systems, 22 | Allocator allocator = Allocator.TempJob, 23 | int internalBuffersCapacity = 30) 24 | where T : unmanaged; 25 | 26 | LazyReadWriteNativeEntityOperations GetLazyReadWriteOperations(EcsSystems systems, 27 | Allocator allocator = Allocator.TempJob, 28 | int internalBuffersCapacity = 30) 29 | where T : unmanaged; 30 | 31 | NativeFilterWrapper GetFilterWrapper(EcsFilter filter); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/NativeOperationsService/Base/INativeOperationsService.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0d0106ccf7964a928acb1dbe2112a39b 3 | timeCreated: 1641989151 -------------------------------------------------------------------------------- /src/NativeOperationsService/NativeOperationsService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Leopotam.EcsLite; 3 | using OdinGames.EcsLite.Native.Context; 4 | using OdinGames.EcsLite.Native.NativeOperations; 5 | using OdinGames.EcsLite.Native.NativeOperations.FilterWrapper; 6 | using OdinGames.EcsLite.Native.NativeOperations.ReadWriteOperationsData; 7 | using OdinGames.EcsLite.Native.NativeOperationsService.Base; 8 | using OdinGames.EcsLite.Native.Extensions; 9 | using Unity.Collections; 10 | 11 | namespace OdinGames.EcsLite.Native.NativeOperationsService 12 | { 13 | public class NativeOperationsService : INativeOperationsService 14 | { 15 | private readonly Dictionary _contextOperations; 16 | private readonly OperationsContext _defaultContext; 17 | private OperationsContext _currentContext; 18 | 19 | [UnityEngine.Scripting.Preserve] 20 | public NativeOperationsService() 21 | { 22 | _contextOperations = new Dictionary(); 23 | _defaultContext = OperationsContext.Create(); 24 | _currentContext = _defaultContext; 25 | } 26 | 27 | public void ApplyOperations(EcsSystems systems) 28 | { 29 | var context = _contextOperations[_currentContext]; 30 | context.ApplyContextOperations(systems); 31 | } 32 | 33 | public NativeFilterWrapper GetFilterWrapper(EcsFilter filter) 34 | { 35 | NativeFilterWrapper wrapper = default; 36 | 37 | wrapper.Init(filter); 38 | 39 | ContextOperationsHolder holder = ResolveHolder(); 40 | holder.RegisterFilter(wrapper); 41 | 42 | return wrapper; 43 | } 44 | 45 | public void ChangeContext(OperationsContext context) 46 | => _currentContext = context; 47 | 48 | public void ChangeToDefaultContext() 49 | => _currentContext = _defaultContext; 50 | 51 | public ReadOnlyNativeEntityOperations GetReadOnlyOperations(EcsSystems systems) 52 | where T : unmanaged 53 | { 54 | var pool = systems.GetWorld().GetPool(); 55 | var sparse = pool.GetRawSparseItems(); 56 | var dense = pool.GetRawDenseItems(); 57 | 58 | var nativeSparse = sparse.WrapToReadOnlyNative(); 59 | var nativeDense = dense.WrapToReadOnlyNative(); 60 | 61 | ContextOperationsHolder holder = ResolveHolder(); 62 | 63 | var wrapper = holder.GetReadOnlyOperationsWrapper(); 64 | wrapper.Init(nativeSparse, 65 | nativeDense); 66 | 67 | return wrapper.Operations; 68 | } 69 | 70 | public LazyReadWriteNativeEntityOperations GetLazyReadWriteOperations(EcsSystems systems, 71 | Allocator operationAllocator = Allocator.TempJob, 72 | int internalBuffersCapacity = 30) 73 | where T : unmanaged 74 | { 75 | ContextOperationsHolder holder = ResolveHolder(); 76 | 77 | var wrapper = holder.GetLazyReadWriteOperationsWrapper(); 78 | 79 | var internalData = GetReadWriteOperationsInternalData(systems); 80 | 81 | wrapper.Init(internalData, operationAllocator, internalBuffersCapacity); 82 | 83 | return wrapper.Operations; 84 | } 85 | 86 | public ReadWriteNativeEntityOperations GetReadWriteOperations(EcsSystems systems, 87 | Allocator operationAllocator = Allocator.TempJob, 88 | int internalBuffersCapacity = 30) 89 | where T : unmanaged 90 | { 91 | ContextOperationsHolder holder = ResolveHolder(); 92 | 93 | var wrapper = holder.GetReadWriteOperationsWrapper(); 94 | 95 | var internalData = GetReadWriteOperationsInternalData(systems); 96 | 97 | wrapper.Init(internalData, operationAllocator, internalBuffersCapacity); 98 | 99 | return wrapper.Operations; 100 | } 101 | 102 | private ContextOperationsHolder ResolveHolder() 103 | { 104 | ContextOperationsHolder holder; 105 | 106 | if (_contextOperations.ContainsKey(_currentContext)) 107 | { 108 | holder = _contextOperations[_currentContext]; 109 | } 110 | else 111 | { 112 | holder = new ContextOperationsHolder(); 113 | _contextOperations.Add(_currentContext, holder); 114 | } 115 | 116 | return holder; 117 | } 118 | 119 | private ReadWriteOperationsInternalData GetReadWriteOperationsInternalData(EcsSystems systems) 120 | where T : unmanaged 121 | { 122 | var world = systems.GetWorld(); 123 | var pool = world.GetPool(); 124 | 125 | var sparse = pool.GetRawSparseItems(); 126 | var dense = pool.GetRawDenseItems(); 127 | var recycled = pool.GetRawRecycledItems(); 128 | 129 | var entities = world.GetRawEntities(); 130 | 131 | var nativeSparse = sparse.WrapToNative(); 132 | var nativeDense = dense.WrapToNative(); 133 | var nativeRecycled = recycled.WrapToNative(); 134 | 135 | var nativeEntities = entities.WrapToNative(); 136 | 137 | ref var recycledItemsCount = ref pool.GetRawRecycledItemsCount(); 138 | ref var denseItemsCount = ref pool.GetRawDenseItemsCount(); 139 | var poolId = pool.GetId(); 140 | 141 | ReadWriteOperationsInternalData internalData = default; 142 | 143 | internalData.Init(nativeSparse, 144 | nativeDense, 145 | nativeRecycled, 146 | nativeEntities, 147 | ref recycledItemsCount, 148 | ref denseItemsCount, 149 | poolId); 150 | 151 | return internalData; 152 | } 153 | 154 | public void Dispose() 155 | { 156 | foreach (var pair in _contextOperations) 157 | { 158 | pair.Value.Dispose(); 159 | } 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/NativeOperationsService/NativeOperationsService.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a23ca2f32d9a45c5a5ad484144557147 3 | timeCreated: 1641989115 -------------------------------------------------------------------------------- /src/NativeOperationsWrapper.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 521ec0f0e9b2487fb65bf43da60ab4c1 3 | timeCreated: 1643060094 -------------------------------------------------------------------------------- /src/NativeOperationsWrapper/Base.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 56ecef5f9d6b455b8e5f42a00ed6ea13 3 | timeCreated: 1643060153 -------------------------------------------------------------------------------- /src/NativeOperationsWrapper/Base/INativeOperationsWrapper.cs: -------------------------------------------------------------------------------- 1 | namespace OdinGames.EcsLite.Native.NativeOperationsWrapper.Base 2 | { 3 | public interface INativeOperationsWrapper : INativeOperationsWrapperTypeless where T : unmanaged 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /src/NativeOperationsWrapper/Base/INativeOperationsWrapper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 939756e440784cf797e8299d21170110 3 | timeCreated: 1643060146 -------------------------------------------------------------------------------- /src/NativeOperationsWrapper/Base/INativeOperationsWrapperTypeless.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace OdinGames.EcsLite.Native.NativeOperationsWrapper.Base 4 | { 5 | public interface INativeOperationsWrapperTypeless : IDisposable 6 | { 7 | } 8 | } -------------------------------------------------------------------------------- /src/NativeOperationsWrapper/Base/INativeOperationsWrapperTypeless.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f9be0643a5314cf6af823a919c2ce500 3 | timeCreated: 1643060169 -------------------------------------------------------------------------------- /src/NativeOperationsWrapper/Base/INativeReadWriteOperationsWrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Unity.Collections; 3 | 4 | namespace OdinGames.EcsLite.Native.NativeOperationsWrapper.Base 5 | { 6 | public interface INativeReadWriteOperationsWrapper : IDisposable 7 | { 8 | int ID { get; } 9 | NativeList DeleteCache { get; } 10 | NativeList AddCache { get; } 11 | NativeList EntitiesToRemove { get; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/NativeOperationsWrapper/Base/INativeReadWriteOperationsWrapper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 42f906a2cf85455a83cfbe3534784a15 3 | timeCreated: 1643104589 -------------------------------------------------------------------------------- /src/NativeOperationsWrapper/NativeLazyReadWriteOperationsWrapper.cs: -------------------------------------------------------------------------------- 1 | using OdinGames.EcsLite.Native.NativeOperations; 2 | using OdinGames.EcsLite.Native.NativeOperations.ReadWriteOperationsData; 3 | using OdinGames.EcsLite.Native.NativeOperationsWrapper.Base; 4 | using Unity.Burst; 5 | using Unity.Collections; 6 | 7 | namespace OdinGames.EcsLite.Native.NativeOperationsWrapper 8 | { 9 | public class NativeLazyReadWriteOperationsWrapper : INativeReadWriteOperationsWrapper, 10 | INativeOperationsWrapper 11 | where T : unmanaged 12 | { 13 | public LazyReadWriteNativeEntityOperations Operations; 14 | 15 | public delegate void AutoResetDelegate(ref T value); 16 | 17 | public AutoResetDelegate ResetDelegate { get; set; } 18 | 19 | public FunctionPointer NativeResetDelegate { get; set; } 20 | 21 | public int ID { get; private set; } 22 | public NativeList DeleteCache { get; private set; } 23 | public NativeList AddCache { get; private set; } 24 | public NativeList EntitiesToRemove { get; private set; } 25 | 26 | public void Init(ReadWriteOperationsInternalData internalData, 27 | Allocator operationAllocator = Allocator.TempJob, 28 | int defaultCapacity = 30) 29 | { 30 | ID = internalData.ID; 31 | DeleteCache = new NativeList(defaultCapacity, operationAllocator); 32 | AddCache = new NativeList(defaultCapacity, operationAllocator); 33 | EntitiesToRemove = new NativeList(defaultCapacity, operationAllocator); 34 | 35 | //AutoResetHelper.GetResetMethod(this); 36 | //var isAutoReset = ResetDelegate == null; 37 | 38 | internalData.InitCollections(DeleteCache, 39 | AddCache, 40 | EntitiesToRemove); 41 | 42 | Operations = default; 43 | 44 | Operations.Init(internalData); 45 | } 46 | 47 | public void Dispose() 48 | { 49 | Operations.Dispose(); 50 | DeleteCache.Dispose(); 51 | AddCache.Dispose(); 52 | EntitiesToRemove.Dispose(); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/NativeOperationsWrapper/NativeLazyReadWriteOperationsWrapper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 45a1f7020c594e7f88490a2914d28134 3 | timeCreated: 1644247265 -------------------------------------------------------------------------------- /src/NativeOperationsWrapper/NativeReadOnlyOperationsWrapper.cs: -------------------------------------------------------------------------------- 1 | using OdinGames.EcsLite.Native.NativeOperations; 2 | using OdinGames.EcsLite.Native.NativeOperationsWrapper.Base; 3 | using OdinGames.EcsLite.Native.WrappedData; 4 | 5 | namespace OdinGames.EcsLite.Native.NativeOperationsWrapper 6 | { 7 | public class NativeReadOnlyOperationsWrapper : INativeOperationsWrapper where T : unmanaged 8 | { 9 | public ReadOnlyNativeEntityOperations Operations; 10 | 11 | public void Init(ReadOnlyNativeWrappedData sparse, 12 | ReadOnlyNativeWrappedData dense) 13 | { 14 | Operations = default; 15 | 16 | Operations.Init(sparse, 17 | dense); 18 | } 19 | 20 | public void Dispose() 21 | { 22 | Operations.Dispose(); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/NativeOperationsWrapper/NativeReadOnlyOperationsWrapper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 01a8e763c1594b79ae6a1555b3d7876c 3 | timeCreated: 1643060102 -------------------------------------------------------------------------------- /src/NativeOperationsWrapper/NativeReadWriteOperationsWrapper.cs: -------------------------------------------------------------------------------- 1 | using OdinGames.EcsLite.Native.NativeOperations; 2 | using OdinGames.EcsLite.Native.NativeOperations.ReadWriteOperationsData; 3 | using OdinGames.EcsLite.Native.NativeOperationsWrapper.Base; 4 | using Unity.Burst; 5 | using Unity.Collections; 6 | 7 | namespace OdinGames.EcsLite.Native.NativeOperationsWrapper 8 | { 9 | public class NativeReadWriteOperationsWrapper : INativeReadWriteOperationsWrapper, 10 | INativeOperationsWrapper 11 | where T : unmanaged 12 | { 13 | public ReadWriteNativeEntityOperations Operations; 14 | 15 | public delegate void AutoResetDelegate(ref T value); 16 | 17 | public AutoResetDelegate ResetDelegate { get; set; } 18 | 19 | public FunctionPointer NativeResetDelegate { get; set; } 20 | 21 | public int ID { get; private set; } 22 | public NativeList DeleteCache { get; private set; } 23 | public NativeList AddCache { get; private set; } 24 | public NativeList EntitiesToRemove { get; private set; } 25 | 26 | public void Init(ReadWriteOperationsInternalData internalData, 27 | Allocator operationAllocator = Allocator.TempJob, 28 | int defaultCapacity = 30) 29 | { 30 | ID = internalData.ID; 31 | DeleteCache = new NativeList(defaultCapacity, operationAllocator); 32 | AddCache = new NativeList(defaultCapacity, operationAllocator); 33 | EntitiesToRemove = new NativeList(defaultCapacity, operationAllocator); 34 | 35 | //AutoResetHelper.GetResetMethod(this); 36 | //var isAutoReset = ResetDelegate == null; 37 | 38 | internalData.InitCollections(DeleteCache, 39 | AddCache, 40 | EntitiesToRemove); 41 | 42 | Operations = default; 43 | 44 | 45 | Operations.Init(internalData); 46 | } 47 | 48 | public void Dispose() 49 | { 50 | Operations.Dispose(); 51 | DeleteCache.Dispose(); 52 | AddCache.Dispose(); 53 | EntitiesToRemove.Dispose(); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/NativeOperationsWrapper/NativeReadWriteOperationsWrapper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: efe12613c6344992942634b3738ed262 3 | timeCreated: 1643060130 -------------------------------------------------------------------------------- /src/ReadOnlyNativeEntityOperations.cs: -------------------------------------------------------------------------------- 1 | using OdinGames.EcsLite.Native.Base; 2 | using OdinGames.EcsLite.Native.Extensions; 3 | using OdinGames.EcsLite.Native.WrappedData; 4 | 5 | namespace OdinGames.EcsLite.Native.NativeOperations 6 | { 7 | // Use this if you don't want to add/remove components from entity dynamically 8 | public struct ReadOnlyNativeEntityOperations : IReadOnlyNativeEntityOperations where T : unmanaged 9 | { 10 | private ReadOnlyNativeWrappedData _sparseItems; 11 | private ReadOnlyNativeWrappedData _denseItems; 12 | 13 | public void Init(ReadOnlyNativeWrappedData sparseItems, 14 | ReadOnlyNativeWrappedData denseItems) 15 | { 16 | _sparseItems = sparseItems; 17 | _denseItems = denseItems; 18 | } 19 | 20 | public bool Has(int entity) 21 | { 22 | if (_sparseItems.Array.Length - 1 < entity || entity < 0) return false; 23 | return _sparseItems.Array[entity] > 0; 24 | } 25 | 26 | public T Get(int entity) 27 | { 28 | var realIndex = _sparseItems.Array[entity]; 29 | return _denseItems.Array[realIndex]; 30 | } 31 | 32 | public void Dispose() 33 | { 34 | _sparseItems.UnwrapFromNative(); 35 | _denseItems.UnwrapFromNative(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/ReadOnlyNativeEntityOperations.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c95d983634e5444bacb745a2e19c50e9 3 | timeCreated: 1642454521 -------------------------------------------------------------------------------- /src/ReadWriteNativeEntityOperations.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Leopotam.EcsLite; 3 | using OdinGames.EcsLite.Native.Base; 4 | using OdinGames.EcsLite.Native.Extensions; 5 | using OdinGames.EcsLite.Native.NativeOperations.ReadWriteOperationsData; 6 | using OdinGames.EcsLite.Native.NativeOperationsWrapper; 7 | using OdinGames.EcsLite.Native.WrappedData; 8 | using Unity.Burst; 9 | using Unity.Collections; 10 | using UnityEngine; 11 | 12 | namespace OdinGames.EcsLite.Native.NativeOperations 13 | { 14 | public struct ReadWriteNativeEntityOperations : IReadWriteNativeEntityOperations where T : unmanaged 15 | { 16 | private ReadWriteOperationsInternalData _internalData; 17 | 18 | public void Init(ReadWriteOperationsInternalData internalData) 19 | { 20 | _internalData = internalData; 21 | } 22 | 23 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 24 | public bool Has(int entity) 25 | { 26 | return _internalData.SparseItems.Array[entity] > 0; 27 | } 28 | 29 | // Auto reset to default should be enough because in burst we only have unmanaged value types, which 30 | // overwrites automatically 31 | public void Del(int entity) 32 | { 33 | ref var sparseData = ref _internalData.SparseItems.Array.GetRef(entity); 34 | if (sparseData > 0) 35 | { 36 | _internalData.ComponentsToRemove.AddNoResize(entity); 37 | _internalData.RecycledItems.Array[_internalData.RecycledItemsCount.PostIncrement()] = sparseData; 38 | 39 | if (_internalData.RecycledItemsCount.Value == _internalData.RecycledItems.Array.Length) { 40 | Debug.LogError("Try to increase RecycledItemsCount for pools in EcsWorld Config"); 41 | } 42 | //if (_isAutoReset) 43 | { 44 | // _autoReset.Invoke(ref _denseItems.Array.GetRef(sparseData)); 45 | } 46 | // else 47 | { 48 | _internalData.DenseItems.Array[sparseData] = default; 49 | } 50 | 51 | sparseData = 0; 52 | ref var entityData = ref _internalData.Entities.Array.GetRef(entity); 53 | entityData.ComponentsCount--; 54 | 55 | if (entityData.ComponentsCount == 0) 56 | { 57 | _internalData.EntitiesToRemove.AddNoResize(entity); 58 | } 59 | } 60 | } 61 | 62 | public void DelEntity(int entity) 63 | { 64 | _internalData.EntitiesToRemove.AddNoResize(entity); 65 | } 66 | 67 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 68 | public T Get(int entity) 69 | { 70 | var realIndex = _internalData.SparseItems.Array[entity]; 71 | return _internalData.DenseItems.Array[realIndex]; 72 | } 73 | 74 | public void Add(int entity, T value) 75 | { 76 | int idx; 77 | if (_internalData.RecycledItemsCount.Value > 0) 78 | { 79 | idx = _internalData.RecycledItems.Array[_internalData.RecycledItemsCount.PreIncrement()]; 80 | } 81 | else 82 | { 83 | idx = _internalData.DenseItemsCount.Value; 84 | if (_internalData.DenseItemsCount.Value == _internalData.DenseItems.Array.Length) 85 | { 86 | Debug.LogError("For now i have no idea is it possible to resize managed array treated as a NativeArray from job. Try to increase entities count in WorldConfig"); 87 | } 88 | 89 | _internalData.DenseItemsCount++; 90 | 91 | _internalData.DenseItems.Array[idx] = value; 92 | } 93 | 94 | _internalData.SparseItems[entity] = idx; 95 | _internalData.ComponentsToAdd.AddNoResize(entity); 96 | _internalData.Entities[entity].ComponentsCount++; 97 | } 98 | 99 | public ref T Add(int entity) 100 | { 101 | int idx; 102 | if (_internalData.RecycledItemsCount.Value > 0) 103 | { 104 | idx = _internalData.RecycledItems.Array[_internalData.RecycledItemsCount.PreDecrement()]; 105 | } 106 | else 107 | { 108 | idx = _internalData.DenseItemsCount.Value; 109 | if (_internalData.DenseItemsCount.Value == _internalData.DenseItems.Array.Length) 110 | { 111 | Debug.LogError("For now i have no idea is it possible to resize managed array treated as a NativeArray from job. Try to increase entities count in WorldConfig"); 112 | } 113 | _internalData.DenseItemsCount++; 114 | 115 | //if (_isAutoReset) 116 | // _autoReset.Invoke(ref _denseItems.Array.GetRef(idx)); 117 | } 118 | _internalData.SparseItems[entity] = idx; 119 | _internalData.ComponentsToAdd.AddNoResize(entity); 120 | _internalData.Entities[entity].ComponentsCount++; 121 | return ref _internalData.DenseItems.Array.GetRef(idx); 122 | } 123 | 124 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 125 | public ref T GetRef(int entity) 126 | { 127 | var realIndex = _internalData.SparseItems.Array[entity]; 128 | return ref _internalData.DenseItems.Array.GetRef(realIndex); 129 | } 130 | 131 | public void Dispose() 132 | { 133 | _internalData.SparseItems.UnwrapFromNative(); 134 | _internalData.DenseItems.UnwrapFromNative(); 135 | _internalData.RecycledItems.UnwrapFromNative(); 136 | _internalData.Entities.UnwrapFromNative(); 137 | } 138 | } 139 | } -------------------------------------------------------------------------------- /src/ReadWriteNativeEntityOperations.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 446bbad1fc8b4ac3bb861fc9e1c59a78 3 | timeCreated: 1641989069 -------------------------------------------------------------------------------- /src/ReadWriteOperationsData.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 95703d5747b34c7d94dffb3c3525353c 3 | timeCreated: 1644246522 -------------------------------------------------------------------------------- /src/ReadWriteOperationsData/Base.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 755da1de69bd439ab28a4c47b45fcced 3 | timeCreated: 1644246522 -------------------------------------------------------------------------------- /src/ReadWriteOperationsData/Base/IReadWriteOperationsInternalData.cs: -------------------------------------------------------------------------------- 1 | using Leopotam.EcsLite; 2 | using OdinGames.EcsLite.Native.NativeOperationsWrapper; 3 | using OdinGames.EcsLite.Native.WrappedData; 4 | using Unity.Burst; 5 | using Unity.Collections; 6 | 7 | namespace OdinGames.EcsLite.Native.NativeOperations.ReadWriteOperationsData.Base 8 | { 9 | public interface IReadWriteOperationsInternalData 10 | where T : unmanaged 11 | { 12 | void Init(NativeWrappedData sparseItems, 13 | NativeWrappedData denseItems, 14 | NativeWrappedData recycledItems, 15 | NativeWrappedData entities, 16 | ref int recycledItemsCount, 17 | ref int denseItemsCount, 18 | int id); 19 | 20 | void InitCollections(NativeList componentsToRemove, 21 | NativeList componentsToAdd, 22 | NativeList entitiesToRemove, 23 | bool isAutoReset = false, 24 | FunctionPointer.AutoResetDelegate> resetDelegate = default); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/ReadWriteOperationsData/Base/IReadWriteOperationsInternalData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e59e33ea0c5647b1ac99b254f917b63c 3 | timeCreated: 1644246522 -------------------------------------------------------------------------------- /src/ReadWriteOperationsData/ReadWriteOperationsInternalData.cs: -------------------------------------------------------------------------------- 1 | using Leopotam.EcsLite; 2 | using OdinGames.EcsLite.Native.Extensions; 3 | using OdinGames.EcsLite.Native.NativeOperations.ReadWriteOperationsData.Base; 4 | using OdinGames.EcsLite.Native.NativeOperationsWrapper; 5 | using OdinGames.EcsLite.Native.WrappedData; 6 | using Unity.Burst; 7 | using Unity.Collections; 8 | 9 | namespace OdinGames.EcsLite.Native.NativeOperations.ReadWriteOperationsData 10 | { 11 | public struct ReadWriteOperationsInternalData : IReadWriteOperationsInternalData 12 | where T : unmanaged 13 | { 14 | public NativeWrappedData SparseItems; 15 | public NativeWrappedData DenseItems; 16 | public NativeWrappedData RecycledItems; 17 | public NativeWrappedData Entities; 18 | 19 | public UnsafeExtensions.SharedIndex RecycledItemsCount; 20 | public UnsafeExtensions.SharedIndex DenseItemsCount; 21 | 22 | public NativeList.ParallelWriter ComponentsToRemove; 23 | public NativeList.ParallelWriter ComponentsToAdd; 24 | 25 | public NativeList.ParallelWriter EntitiesToRemove; 26 | 27 | public int ID; 28 | 29 | public bool IsAutoReset; 30 | public FunctionPointer.AutoResetDelegate> AutoReset; 31 | 32 | public void Init(NativeWrappedData sparseItems, 33 | NativeWrappedData denseItems, 34 | NativeWrappedData recycledItems, 35 | NativeWrappedData entities, 36 | ref int recycledItemsCount, 37 | ref int denseItemsCount, 38 | int id) 39 | { 40 | SparseItems = sparseItems; 41 | DenseItems = denseItems; 42 | RecycledItems = recycledItems; 43 | Entities = entities; 44 | 45 | RecycledItemsCount = new UnsafeExtensions.SharedIndex(ref recycledItemsCount); 46 | DenseItemsCount = new UnsafeExtensions.SharedIndex(ref denseItemsCount); 47 | 48 | ID = id; 49 | } 50 | 51 | public void InitCollections(NativeList componentsToRemove, 52 | NativeList componentsToAdd, 53 | NativeList entitiesToRemove, 54 | bool isAutoReset = false, 55 | FunctionPointer.AutoResetDelegate> resetDelegate = default) 56 | { 57 | ComponentsToRemove = componentsToRemove.AsParallelWriter(); 58 | ComponentsToAdd = componentsToAdd.AsParallelWriter(); 59 | EntitiesToRemove = entitiesToRemove.AsParallelWriter(); 60 | //_isAutoReset = isAutoReset; 61 | //_autoReset = autoReset; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/ReadWriteOperationsData/ReadWriteOperationsInternalData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 54c9ff81bd06478b8e302a492161cff8 3 | timeCreated: 1644246481 -------------------------------------------------------------------------------- /src/WrappedData.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 25cb6e69e83b4e2dbb24686b5c763053 3 | timeCreated: 1643321567 -------------------------------------------------------------------------------- /src/WrappedData/NativeWrappedData.cs: -------------------------------------------------------------------------------- 1 | using OdinGames.EcsLite.Native.Extensions; 2 | using Unity.Collections; 3 | using Unity.Collections.LowLevel.Unsafe; 4 | 5 | namespace OdinGames.EcsLite.Native.WrappedData 6 | { 7 | public struct NativeWrappedData where T : unmanaged 8 | { 9 | [NativeDisableParallelForRestriction] 10 | public NativeArray Array; 11 | 12 | // Is it really needed here? 13 | public ref T this[int index] => ref Array.GetRef(index); 14 | #if UNITY_EDITOR 15 | public AtomicSafetyHandle SafetyHandle; 16 | #endif 17 | } 18 | } -------------------------------------------------------------------------------- /src/WrappedData/NativeWrappedData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: aa2e43d273d446208c7c0928eb0948f0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /src/WrappedData/ReadOnlyNativeWrappedData.cs: -------------------------------------------------------------------------------- 1 | using Unity.Collections; 2 | using Unity.Collections.LowLevel.Unsafe; 3 | 4 | namespace OdinGames.EcsLite.Native.WrappedData 5 | { 6 | public struct ReadOnlyNativeWrappedData where T : unmanaged 7 | { 8 | [ReadOnly] 9 | public NativeArray.ReadOnly Array; 10 | #if UNITY_EDITOR 11 | public AtomicSafetyHandle SafetyHandle; 12 | #endif 13 | } 14 | } -------------------------------------------------------------------------------- /src/WrappedData/ReadOnlyNativeWrappedData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d6ff0e977c7445839595187515c118c1 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | --------------------------------------------------------------------------------