├── .gitignore ├── CHANGELOG.md ├── CHANGELOG.md.meta ├── Documentation~ ├── TableOfContents.md ├── index.md ├── manual.md └── scriptableobject-conversion-system.md ├── Hydrogen.Entities.Hybrid.Tests.meta ├── Hydrogen.Entities.Hybrid.Tests ├── Assembly.cs ├── Assembly.cs.meta ├── Content.meta ├── ConvertScriptableObjectToBlobTests.cs ├── ConvertScriptableObjectToBlobTests.cs.meta ├── Hydrogen.Entities.Hybrid.Tests.asmdef └── Hydrogen.Entities.Hybrid.Tests.asmdef.meta ├── Hydrogen.Entities.Hybrid.meta ├── Hydrogen.Entities.Hybrid ├── Hydrogen.Entities.Hybrid.asmdef ├── Hydrogen.Entities.Hybrid.asmdef.meta ├── IConvertScriptableObjectToBlob.cs ├── IConvertScriptableObjectToBlob.cs.meta ├── ScriptableObjectConversionSystem.cs └── ScriptableObjectConversionSystem.cs.meta ├── LICENSE.md ├── LICENSE.md.meta ├── README.md ├── README.md.meta ├── Samples~ └── ConfigFileLoading │ ├── Contents.meta │ ├── Contents │ ├── ConfigFileLoading.unity │ └── ConfigFileLoading.unity.meta │ ├── README.md │ ├── README.md.meta │ ├── Scripts.meta │ └── Scripts │ ├── IniFileExample.cs │ └── IniFileExample.cs.meta ├── package.json └── package.json.meta /.gitignore: -------------------------------------------------------------------------------- 1 | [Ll]ibrary/ 2 | [Tt]emp/ 3 | [Oo]bj/ 4 | [Bb]uild/ 5 | [Bb]uilds/ 6 | Assets/AssetStoreTools* 7 | 8 | # Visual Studio cache directory 9 | .vs/ 10 | 11 | # Autogenerated VS/MD/Consulo solution and project files 12 | ExportedObj/ 13 | .consulo/ 14 | *.csproj 15 | *.unityproj 16 | *.sln 17 | *.suo 18 | *.tmp 19 | *.user 20 | *.userprefs 21 | *.pidb 22 | *.booproj 23 | *.svd 24 | *.pdb 25 | *.opendb 26 | 27 | # Unity3D generated meta files 28 | *.pidb.meta 29 | *.pdb.meta 30 | 31 | # Unity3D Generated File On Crash Reports 32 | sysinfo.txt 33 | 34 | # Builds 35 | *.apk 36 | *.unitypackage 37 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [0.2.2-preview.2] - 2020-02-17 4 | - Minor fix for an API rename 5 | 6 | ## [0.2.2-preview.1] - 2019-11-04 7 | - Removed unnecessary system ordering attributes from sample systems, thanks to the system group additions. 8 | 9 | ## [0.2.2-preview.0] - 2019-11-03 10 | - Added SingletonConvertGroup and SingletonPostConvertGroup to simplify managing order for conversion systems. 11 | - SingletonConvertSystem now all by default run in SingletonConvertGroup 12 | - All SingletonChanged* variant systems now run in SingletonPostConvertGroup 13 | - Bumped required Entities version to 0.3.0-preview.0, since it fixes several ConvertToEntity issues. 14 | 15 | ## [0.2.1-preview.1] - 2019-11-30 16 | - Fixed Warnings with using manual GO conversion in tests due to API changes. 17 | 18 | ## [0.2.1-preview.0] - 2019-11-27 19 | - Fixed issues with Entities 0.2.0 compatibility 20 | - Updated tests to fix issues with bugs being introduced and fixed in the API. 21 | 22 | ## [0.2.0-preview.3] - 2019-11-18 23 | - Added 3 working samples based on user feedback. 24 | - Added more base classes to reduce boilerplate for common system patterns. 25 | - Eliminated need to override a copy function for changing out Blob Asset Singletons. 26 | 27 | ## [0.2.0-preview.2] - 2019-11-05 28 | - Fixed Hydrogen.Entities and Hydrogen.Entities.Hybrid asmdefs not being auto-referenced for projects not using asmdefs. 29 | - Added Basic Converter Samples. 30 | 31 | ## [0.2.0-preview.1] - 2019-10-17 32 | - Removed Obsolete parts of the API 33 | 34 | ## [0.2.0-preview.0] - 2019-10-17 35 | - Obsoleted old Config and Singleton API, in favor of the new SingletonConverter Framework 36 | - Added full unit Test coverage for both ScriptableObjectConversionSystem, and the new SingletonConverter Framework. 37 | - Split things up into more assembly definitions. 38 | - Blob Singletons loaded via a converter in a subscene will now copy instead of assign to avoid invalid memory access 39 | errors 40 | - Rewrote Documentation 41 | 42 | ## [0.1.3] - 2019-09-05 43 | - Fixed Incorrect asmdef setting 44 | - Began work on new Conversion Framework. 45 | 46 | ## [0.1.2] - 2019-08-19 47 | - Simplified IConvertScriptableObjectToBlob API surface. 48 | - User can now access the GameObjectConversionSystem from ScriptableObjectConversionSystem's GoConversionSystem property. 49 | 50 | ## [0.1.1] 51 | 52 | Minor adjustments to package naming. 53 | Added Initial Documentation 54 | 55 | ## [0.1.0] 56 | Initial commits. 57 | 58 | Config and BlobAsset/ref helpers. 59 | -------------------------------------------------------------------------------- /CHANGELOG.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d2e05bd62bce0c64bb29d261fbd2f519 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Documentation~/TableOfContents.md: -------------------------------------------------------------------------------- 1 | * [Hydrogen.Entities overview](./index.md) 2 | * [Manual](./manual.md) 3 | * [ScriptableObjectConversionSystem](./scriptableobject-conversion-system.md) 4 | -------------------------------------------------------------------------------- /Documentation~/index.md: -------------------------------------------------------------------------------- 1 | # About Hydrogen Entities 2 | 3 | Hydrogen.Entities is a support library that contains several utilities for working with [Unity's DOTS framework](https://unity.com/dots). 4 | It is designed to be as simple as possible to assist in certain types of [Entity conversions](https://docs.unity3d.com/Packages/com.unity.entities@0.3/api/Unity.Entities.Entity.html). 5 | 6 | In particular it has support for creating singleton data for configuration purposes and creating [```BlobAssetReference```](https://docs.unity3d.com/Packages/com.unity.entities@0.3/api/Unity.Entities.BlobAssetReference-1.html) from ScriptableObjects. 7 | This makes it easier to use Pure(er) ECS data and less need for overhead when accessing shared configuration data. 8 | 9 | There are also [Unit Tests](https://docs.unity3d.com/Packages/com.unity.test-framework@1.1/manual/index.html) setup to ensure robustness, and to serve as examples for programmers interested in utilizing the framework. 10 | 11 | # Installation 12 | 13 | To install this package, you can follow the instructions for using [github packages](https://docs.unity3d.com/Manual/upm-git.html) from the [Unity Package Manager](https://docs.unity3d.com/Packages/com.unity.package-manager-ui@latest/index.html). 14 | > **Note**: The github page for the framework is https://github.com/periodyctom/Hydrogen.Entities. 15 | 16 | # Using Hydrogen.Entities 17 | 18 | You can read the [manual](./manual.md) for usage information. 19 | 20 | The [table of contents](./TableOfContents.md) has a listing of the important pages. 21 | 22 | # Technical Details 23 | 24 | ## Requirements 25 | 26 | This version of Hydrogen.Entities has been tested with 2019.3b4+. 27 | 28 | ## Document History 29 | | Date | Reason | 30 | | :--------- | :----------------------------------- | 31 | | December 29, 2020 | Long overdue cleanup after getting rid of code rot. Several Unity DOTS features now go beyond what this API supports. | 32 | | December 03, 2019 | Updated after documentation improvements and hyperlink updates. | 33 | | October 14, 2019 | Updated after major revision to 0.2.0 | -------------------------------------------------------------------------------- /Documentation~/manual.md: -------------------------------------------------------------------------------- 1 | # Hydrogen.Entities manual 2 | 3 | This is the manual for the Hydrogen.Entities DOTS Utility framework. 4 | 5 | ## Introduction 6 | 7 | * [Hydrogen.Entities overview](./index.md) 8 | 9 | ## **Getting Started** 10 | 11 | * [Installation](./index.md#installation) 12 | * [Using the ScriptableObjectConversionSystem](./scriptableobject-conversion-system.md) 13 | * [Implementing IConvertScriptableObjectToBlob<T>](./scriptableobject-conversion-system.md#iconvertscriptableobjecttoblobt) 14 | * [Providing custom functions for externally defined ScriptableObjects](./scriptableobject-conversion-system.md#scripttoblobfuncin-t0-t1) 15 | -------------------------------------------------------------------------------- /Documentation~/scriptableobject-conversion-system.md: -------------------------------------------------------------------------------- 1 | # **ScriptableObjectConversionSystem** 2 | 3 | Similar to and piggybacking on the [GameObject](https://docs.unity3d.com/ScriptReference/GameObject.html) conversion pipeline. 4 | The ScriptableObjectConversionSystems has functions for creating Blob assets and [BlobAssetReference<T>](https://docs.unity3d.com/Packages/com.unity.entities@0.3/api/Unity.Entities.BlobAssetReference-1.html) to them from [ScriptableObjects](https://docs.unity3d.com/ScriptReference/ScriptableObject.html). 5 | The conversion system caches created BlobAssetReferences<T> so given the same inputs, you should get the same result. 6 | This allows a converted SO to be referenced in more than one place. 7 | 8 | The conversion flow is also given access to the GameObjectConversionSystem used in converting GOs, so you can create SO conversions that reference converted prefabs, given the originating prefab references! 9 | 10 | There are 2 main conversion routes: 11 | 12 | ## **IConvertScriptableObjectToBlob<T>** 13 | An interface that should be used on a ScriptableObject that defines it's own conversion into a Blob Asset. 14 | This is used to create a **BlobAssetReference<T>** that points to the converted SO blob and can either be assigned in one place, or shared between multiple entities or blobs. 15 | 16 | For example: 17 | ```cs 18 | private class NodeDefinition : ScriptableObject, IConvertScriptableObjectToBlob 19 | { 20 | public int Value = 0; 21 | 22 | public NodeDefinition Left; 23 | public NodeDefinition Right; 24 | 25 | public BlobAssetReference Convert(ScriptableObjectConversionSystem conversion) 26 | { 27 | var builder = new BlobBuilder(Allocator.Temp); 28 | 29 | ref NodeBlob dst = ref builder.ConstructRoot(); 30 | 31 | BlobAssetReference left = Left != null 32 | ? conversion.GetBlob(Left) 33 | : BlobAssetReference.Null; 34 | 35 | BlobAssetReference right = Right != null 36 | ? conversion.GetBlob(Right) 37 | : BlobAssetReference.Null; 38 | 39 | dst.Left = left; 40 | dst.Right = right; 41 | dst.Value = Value; 42 | 43 | BlobAssetReference result = builder.CreateBlobAssetReference(Allocator.Persistent); 44 | 45 | builder.Dispose(); 46 | 47 | return result; 48 | } 49 | } 50 | 51 | private struct NodeBlob 52 | { 53 | public BlobAssetReference Left; 54 | public BlobAssetReference Right; 55 | public int Value; 56 | } 57 | ``` 58 | 59 | 60 | ## **ScriptToBlobFunc<in T0, T1>** 61 | A delegate for manual conversions that do not utilize the IConvertScriptableObjectToBlob<T> workflow, primarily intended for scenarios where access to the original SO code is limited or non-existant. Such as Unity-developed config data, or 3rd-party assets/packages where code changes would be overwritten. 62 | It's recommended you use a static method as this will ensure a deterministic result if you intend to get the same SO conversion from multiple places. 63 | 64 | For example: 65 | ```cs 66 | private static BlobAssetReference ConvertCustomToBlob02( 67 | TestScriptableCustomFunc src, 68 | ScriptableObjectConversionSystem conversion) 69 | { 70 | var builder = new BlobBuilder(Allocator.Temp); 71 | 72 | ref TestBlob02 dst = ref builder.ConstructRoot(); 73 | 74 | builder.AllocateString(ref dst.Foo, src.Foo); 75 | 76 | dst.Bar = src.Bar; 77 | 78 | ref BazData bazData = ref builder.Allocate(ref dst.Baz); 79 | 80 | bazData = src.Baz; 81 | 82 | BlobAssetReference result = builder.CreateBlobAssetReference(Allocator.Persistent); 83 | 84 | builder.Dispose(); 85 | 86 | return result; 87 | } 88 | 89 | private class TestScriptableCustomFunc : ScriptableObject 90 | { 91 | public string Foo = kFooText; 92 | public uint Bar = kMeaningOfLifeUInt; 93 | public BazData Baz = sm_testBaz; 94 | } 95 | 96 | private struct TestBlob02 97 | { 98 | public BlobString Foo; 99 | public uint Bar; 100 | public BlobPtr Baz; 101 | } 102 | 103 | [Serializable] 104 | private struct BazData : IEquatable 105 | { 106 | public uint A; 107 | public uint B; 108 | public uint C; 109 | public uint D; 110 | 111 | public BazData(uint a, uint b, uint c, uint d) 112 | { 113 | A = a; 114 | B = b; 115 | C = c; 116 | D = d; 117 | } 118 | 119 | public bool Equals(BazData other) => A == other.A && B == other.B && C == other.C && D == other.D; 120 | 121 | public override bool Equals(object obj) => obj is BazData other && Equals(other); 122 | 123 | [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] 124 | public override int GetHashCode() 125 | { 126 | unchecked 127 | { 128 | int hashCode = (int) A; 129 | hashCode = (hashCode * 397) ^ (int) B; 130 | hashCode = (hashCode * 397) ^ (int) C; 131 | hashCode = (hashCode * 397) ^ (int) D; 132 | 133 | return hashCode; 134 | } 135 | } 136 | } 137 | ``` -------------------------------------------------------------------------------- /Hydrogen.Entities.Hybrid.Tests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 84b2c54f3714af54b8dbeb6c96db8a85 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Hydrogen.Entities.Hybrid.Tests/Assembly.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("Hydrogen.Entities.Hybrid.Editor.Tests")] -------------------------------------------------------------------------------- /Hydrogen.Entities.Hybrid.Tests/Assembly.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0da56aab8fa4e984993503a60b06e271 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Hydrogen.Entities.Hybrid.Tests/Content.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 72d0f23944962c140acfde531be8eb7d 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Hydrogen.Entities.Hybrid.Tests/ConvertScriptableObjectToBlobTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using NUnit.Framework; 4 | using Unity.Collections; 5 | using Unity.Entities; 6 | using Unity.Entities.Tests; 7 | using UnityEngine; 8 | using UnityEngine.TestTools.Utils; 9 | using Object = UnityEngine.Object; 10 | 11 | // ReSharper disable once CheckNamespace 12 | namespace Hydrogen.Entities.Tests 13 | { 14 | public class ConvertScriptableObjectToBlobTests : ECSTestsFixture 15 | { 16 | const float kMeaningOfLifeFloat = 42.0f; 17 | const uint kMeaningOfLifeUInt = 42u; 18 | const string kFooText = "Lorem Ipsum"; 19 | static readonly int[] sm_integers = {0, 1, 2, 3}; 20 | static readonly BazData sm_testBaz = new BazData(1,2,3,4); 21 | 22 | GameObjectConversionSettings MakeDefaultSettings() => 23 | new GameObjectConversionSettings() 24 | { 25 | DestinationWorld = World, 26 | ConversionFlags = GameObjectConversionUtility.ConversionFlags.AssignName 27 | }; 28 | 29 | struct TestBlob01 30 | { 31 | public BlobString Name; 32 | public BlobPtr AFloat; 33 | public BlobArray Ints; 34 | } 35 | 36 | class TestScriptableInterface01 : ScriptableObject, IConvertScriptableObjectToBlob 37 | { 38 | public float AFloat = kMeaningOfLifeFloat; 39 | public int[] Integers = sm_integers; 40 | 41 | public BlobAssetReference Convert(ScriptableObjectConversionSystem conversion) 42 | { 43 | var builder = new BlobBuilder(Allocator.Temp); 44 | 45 | ref var target = ref builder.ConstructRoot(); 46 | 47 | if(!string.IsNullOrEmpty(name) && name.Length > 0) 48 | builder.AllocateString(ref target.Name, name); 49 | else 50 | target.Name = new BlobString(); 51 | 52 | ref var afloat = ref builder.Allocate(ref target.AFloat); 53 | 54 | afloat = AFloat; 55 | 56 | var intsLen = Integers.Length; 57 | 58 | if (intsLen > 0) 59 | builder.Construct(ref target.Ints, Integers); 60 | else 61 | target.Ints = new BlobArray(); 62 | 63 | var assetRef = 64 | builder.CreateBlobAssetReference(Allocator.Persistent); 65 | 66 | builder.Dispose(); 67 | 68 | return assetRef; 69 | } 70 | } 71 | 72 | class TestScriptableCustomFunc : ScriptableObject 73 | { 74 | public string Foo = kFooText; 75 | public uint Bar = kMeaningOfLifeUInt; 76 | public BazData Baz = sm_testBaz; 77 | } 78 | 79 | struct TestBlob02 80 | { 81 | public BlobString Foo; 82 | public uint Bar; 83 | public BlobPtr Baz; 84 | } 85 | 86 | class NodeDefinition : ScriptableObject, IConvertScriptableObjectToBlob 87 | { 88 | public int Value; 89 | 90 | public NodeDefinition Left; 91 | public NodeDefinition Right; 92 | 93 | public BlobAssetReference Convert(ScriptableObjectConversionSystem conversion) 94 | { 95 | var builder = new BlobBuilder(Allocator.Temp); 96 | 97 | ref var dst = ref builder.ConstructRoot(); 98 | 99 | var left = Left != null 100 | ? conversion.GetBlob(Left) 101 | : BlobAssetReference.Null; 102 | 103 | var right = Right != null 104 | ? conversion.GetBlob(Right) 105 | : BlobAssetReference.Null; 106 | 107 | dst.Left = left; 108 | dst.Right = right; 109 | dst.Value = Value; 110 | 111 | var result = builder.CreateBlobAssetReference(Allocator.Persistent); 112 | 113 | builder.Dispose(); 114 | 115 | return result; 116 | } 117 | } 118 | 119 | struct NodeBlob 120 | { 121 | public BlobAssetReference Left; 122 | public BlobAssetReference Right; 123 | public int Value; 124 | } 125 | 126 | [Serializable] 127 | struct BazData : IEquatable 128 | { 129 | public uint A; 130 | public uint B; 131 | public uint C; 132 | public uint D; 133 | 134 | public BazData(uint a, uint b, uint c, uint d) 135 | { 136 | A = a; 137 | B = b; 138 | C = c; 139 | D = d; 140 | } 141 | 142 | public bool Equals(BazData other) => A == other.A && B == other.B && C == other.C && D == other.D; 143 | 144 | public override bool Equals(object obj) => obj is BazData other && Equals(other); 145 | 146 | [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] 147 | public override int GetHashCode() 148 | { 149 | unchecked 150 | { 151 | var hashCode = (int) A; 152 | hashCode = (hashCode * 397) ^ (int) B; 153 | hashCode = (hashCode * 397) ^ (int) C; 154 | hashCode = (hashCode * 397) ^ (int) D; 155 | 156 | return hashCode; 157 | } 158 | } 159 | } 160 | 161 | static BlobAssetReference ConvertCustomToBlob02( 162 | TestScriptableCustomFunc src, 163 | ScriptableObjectConversionSystem conversion) 164 | { 165 | var builder = new BlobBuilder(Allocator.Temp); 166 | 167 | ref var dst = ref builder.ConstructRoot(); 168 | 169 | builder.AllocateString(ref dst.Foo, src.Foo); 170 | 171 | dst.Bar = src.Bar; 172 | 173 | ref var bazData = ref builder.Allocate(ref dst.Baz); 174 | 175 | bazData = src.Baz; 176 | 177 | var result = builder.CreateBlobAssetReference(Allocator.Persistent); 178 | 179 | builder.Dispose(); 180 | 181 | return result; 182 | } 183 | 184 | static BlobAssetReference ConvertInterfaceToBlob01( 185 | TestScriptableInterface01 src, 186 | ScriptableObjectConversionSystem conversion) 187 | { 188 | var builder = new BlobBuilder(Allocator.Temp); 189 | 190 | ref var target = ref builder.ConstructRoot(); 191 | 192 | if(!string.IsNullOrEmpty(src.name)) 193 | builder.AllocateString(ref target.Name, src.name); 194 | else 195 | target.Name = new BlobString(); 196 | 197 | ref var afloat = ref builder.Allocate(ref target.AFloat); 198 | 199 | afloat = src.AFloat; 200 | 201 | var intsLen = src.Integers.Length; 202 | 203 | if (intsLen > 0) 204 | builder.Construct(ref target.Ints, src.Integers); 205 | else 206 | target.Ints = new BlobArray(); 207 | 208 | var result = 209 | builder.CreateBlobAssetReference(Allocator.Persistent); 210 | 211 | builder.Dispose(); 212 | 213 | return result; 214 | } 215 | 216 | static readonly ScriptToBlobFunc sm_convertCustomToBlob02 = 217 | ConvertCustomToBlob02; 218 | 219 | static readonly ScriptToBlobFunc sm_convertInterfaceToBlob01 = 220 | ConvertInterfaceToBlob01; 221 | 222 | static void TryDisposeBlob(in BlobAssetReference reference) 223 | where T : struct 224 | { 225 | // ReSharper disable once PossiblyImpureMethodCallOnReadonlyVariable 226 | if(reference.IsCreated) reference.Dispose(); 227 | } 228 | 229 | ScriptableObjectConversionSystem m_conversion; 230 | 231 | [SetUp] 232 | public override void Setup() 233 | { 234 | base.Setup(); 235 | m_conversion = World.GetOrCreateSystem(); 236 | } 237 | 238 | [Test] 239 | public void ConvertScriptableObjectToBlob_WithInterface() 240 | { 241 | var src = ScriptableObject.CreateInstance(); 242 | var reference = BlobAssetReference.Null; 243 | 244 | try 245 | { 246 | Assert.NotNull(src); 247 | 248 | // ReSharper disable once CompareOfFloatsByEqualityOperator 249 | Assert.IsTrue(src.AFloat == kMeaningOfLifeFloat); 250 | Assert.IsTrue(src.Integers.Length == 4); 251 | Assert.IsTrue(src.Integers[0] == 0 && src.Integers[1] == 1 && src.Integers[2] == 2 && src.Integers[3] == 3); 252 | 253 | reference = m_conversion.GetBlob(src); 254 | Assert.IsTrue(reference.IsCreated); 255 | 256 | ref var dst = ref reference.Value; 257 | // ReSharper disable once CompareOfFloatsByEqualityOperator 258 | Assert.IsTrue(src.AFloat == dst.AFloat.Value); 259 | Assert.IsTrue(src.name == dst.Name.ToString()); 260 | Assert.IsTrue(src.Integers.Length == dst.Ints.Length); 261 | 262 | for (var i = 0; i < 4; i++) 263 | Assert.IsTrue(src.Integers[i] == dst.Ints[i]); 264 | } 265 | finally 266 | { 267 | Object.DestroyImmediate(src); 268 | TryDisposeBlob(reference); 269 | } 270 | } 271 | 272 | [Test] 273 | public void ConvertScriptableObjectToBlob_WithFunction() 274 | { 275 | var src = ScriptableObject.CreateInstance(); 276 | var reference = BlobAssetReference.Null; 277 | 278 | try 279 | { 280 | Assert.NotNull(src); 281 | 282 | // ReSharper disable once CompareOfFloatsByEqualityOperator 283 | Assert.IsTrue(src.Foo == kFooText); 284 | Assert.IsTrue(src.Bar == kMeaningOfLifeUInt); 285 | Assert.IsTrue(src.Baz.Equals(sm_testBaz)); 286 | 287 | reference = m_conversion.GetBlob(src, sm_convertCustomToBlob02); 288 | Assert.IsTrue(reference.IsCreated); 289 | 290 | ref var dst = ref reference.Value; 291 | // ReSharper disable once CompareOfFloatsByEqualityOperator 292 | Assert.IsTrue(src.Foo == dst.Foo.ToString()); 293 | Assert.IsTrue(src.Bar == dst.Bar); 294 | Assert.IsTrue(src.Baz.Equals(dst.Baz.Value)); 295 | } 296 | finally 297 | { 298 | Object.DestroyImmediate(src); 299 | TryDisposeBlob(reference); 300 | } 301 | } 302 | 303 | [Test] 304 | public void ConvertScriptableObjectToBlob_WithBoth() 305 | { 306 | var original = ScriptableObject.CreateInstance(); 307 | original.name = "Test"; 308 | 309 | var interfaceTest = BlobAssetReference.Null; 310 | var functionTest = BlobAssetReference.Null; 311 | 312 | try 313 | { 314 | Assert.IsTrue(original.name == "Test"); 315 | Assert.IsTrue(Utils.AreFloatsEqual(original.AFloat, kMeaningOfLifeFloat, float.Epsilon)); 316 | Assert.IsTrue( 317 | original.Integers[0] == sm_integers[0] 318 | && original.Integers[1] == sm_integers[1] 319 | && original.Integers[2] == sm_integers[2] 320 | && original.Integers[3] == sm_integers[3]); 321 | 322 | interfaceTest = m_conversion.GetBlob(original); 323 | functionTest = m_conversion.GetBlob(original, sm_convertInterfaceToBlob01); 324 | 325 | ref var interfaceBlob = ref interfaceTest.Value; 326 | ref var functionBlob = ref functionTest.Value; 327 | 328 | Assert.IsTrue(interfaceBlob.Name.ToString() == functionBlob.Name.ToString()); 329 | Assert.IsTrue( 330 | Utils.AreFloatsEqual(interfaceBlob.AFloat.Value, functionBlob.AFloat.Value, float.Epsilon)); 331 | Assert.IsTrue(interfaceBlob.Ints.Length == functionBlob.Ints.Length); 332 | 333 | for (var i = 0; i < 4; i++) 334 | Assert.IsTrue(interfaceBlob.Ints[i] == functionBlob.Ints[i]); 335 | 336 | Assert.IsTrue(interfaceBlob.Name.ToString() == original.name); 337 | Assert.IsTrue(Utils.AreFloatsEqual(interfaceBlob.AFloat.Value, original.AFloat, float.Epsilon)); 338 | Assert.IsTrue(interfaceBlob.Ints.Length == original.Integers.Length); 339 | 340 | for (var i = 0; i < 4; i++) 341 | Assert.IsTrue(interfaceBlob.Ints[i] == original.Integers[i]); 342 | } 343 | finally 344 | { 345 | Object.DestroyImmediate(original); 346 | TryDisposeBlob(interfaceTest); 347 | TryDisposeBlob(functionTest); 348 | } 349 | } 350 | 351 | [Test] 352 | public void ConvertScriptableObjectToBlob_WithChainedBlobReferences() 353 | { 354 | var a = ScriptableObject.CreateInstance(); 355 | var b = ScriptableObject.CreateInstance(); 356 | var c = ScriptableObject.CreateInstance(); 357 | var d = ScriptableObject.CreateInstance(); 358 | var e = ScriptableObject.CreateInstance(); 359 | 360 | a.Value = 0; 361 | a.Left = b; 362 | a.Right = c; 363 | 364 | b.Value = 1; 365 | b.Left = d; 366 | b.Right = null; 367 | 368 | c.Value = 2; 369 | c.Left = null; 370 | c.Right = e; 371 | 372 | d.Value = 3; 373 | e.Value = 4; 374 | 375 | var aBlob = BlobAssetReference.Null; 376 | var bBlob = BlobAssetReference.Null; 377 | var cBlob = BlobAssetReference.Null; 378 | var dBlob = BlobAssetReference.Null; 379 | var eBlob = BlobAssetReference.Null; 380 | 381 | try 382 | { 383 | aBlob = m_conversion.GetBlob(a); 384 | bBlob = m_conversion.GetBlob(b); 385 | cBlob = m_conversion.GetBlob(c); 386 | dBlob = m_conversion.GetBlob(d); 387 | eBlob = m_conversion.GetBlob(e); 388 | 389 | Assert.IsTrue(aBlob.Value.Value == 0); 390 | Assert.IsTrue(bBlob.Value.Value == 1); 391 | Assert.IsTrue(cBlob.Value.Value == 2); 392 | Assert.IsTrue(dBlob.Value.Value == 3); 393 | Assert.IsTrue(eBlob.Value.Value == 4); 394 | 395 | Assert.IsTrue(aBlob.Value.Left == bBlob); 396 | Assert.IsTrue(aBlob.Value.Right == cBlob); 397 | Assert.IsTrue(bBlob.Value.Left == dBlob); 398 | Assert.IsTrue(bBlob.Value.Right == BlobAssetReference.Null); 399 | Assert.IsTrue(cBlob.Value.Left == BlobAssetReference.Null); 400 | Assert.IsTrue(cBlob.Value.Right == eBlob); 401 | Assert.IsTrue(dBlob.Value.Left == BlobAssetReference.Null); 402 | Assert.IsTrue(dBlob.Value.Right == BlobAssetReference.Null); 403 | Assert.IsTrue(eBlob.Value.Left == BlobAssetReference.Null); 404 | Assert.IsTrue(eBlob.Value.Right == BlobAssetReference.Null); 405 | } 406 | finally 407 | { 408 | Object.DestroyImmediate(a); 409 | Object.DestroyImmediate(b); 410 | Object.DestroyImmediate(c); 411 | Object.DestroyImmediate(d); 412 | Object.DestroyImmediate(e); 413 | 414 | TryDisposeBlob(aBlob); 415 | TryDisposeBlob(bBlob); 416 | TryDisposeBlob(cBlob); 417 | TryDisposeBlob(dBlob); 418 | TryDisposeBlob(eBlob); 419 | } 420 | } 421 | } 422 | } 423 | -------------------------------------------------------------------------------- /Hydrogen.Entities.Hybrid.Tests/ConvertScriptableObjectToBlobTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e6a015b30f0777a459acc3a0a6bf2c67 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Hydrogen.Entities.Hybrid.Tests/Hydrogen.Entities.Hybrid.Tests.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Hydrogen.Entities.Hybrid.Tests", 3 | "rootNamespace": "", 4 | "references": [ 5 | "GUID:734d92eba21c94caba915361bd5ac177", 6 | "GUID:8e2f79f713f5a47dcb69903037d4bc0e", 7 | "GUID:8819f35a0fc84499b990e90a4ca1911f", 8 | "GUID:bd9484a338da1458bb1d27afe56e6f90", 9 | "GUID:27619889b8ba8c24980f49ee34dbb44a", 10 | "GUID:0acc523941302664db1f4e527237feb3", 11 | "GUID:44ab9bb22c816394bb1625d8e2ca2fd6" 12 | ], 13 | "includePlatforms": [], 14 | "excludePlatforms": [], 15 | "allowUnsafeCode": false, 16 | "overrideReferences": true, 17 | "precompiledReferences": [ 18 | "nunit.framework.dll" 19 | ], 20 | "autoReferenced": false, 21 | "defineConstraints": [ 22 | "UNITY_INCLUDE_TESTS" 23 | ], 24 | "versionDefines": [], 25 | "noEngineReferences": false 26 | } -------------------------------------------------------------------------------- /Hydrogen.Entities.Hybrid.Tests/Hydrogen.Entities.Hybrid.Tests.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 073cb90ce0e3ee34caae66aba0367551 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Hydrogen.Entities.Hybrid.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 757dcd622743f3440a093973156c8719 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Hydrogen.Entities.Hybrid/Hydrogen.Entities.Hybrid.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Hydrogen.Entities.Hybrid", 3 | "rootNamespace": "", 4 | "references": [ 5 | "GUID:734d92eba21c94caba915361bd5ac177", 6 | "GUID:8819f35a0fc84499b990e90a4ca1911f", 7 | "GUID:e0cd26848372d4e5c891c569017e11f1", 8 | "GUID:5f3cf485eb0554709a8abbeace890c86" 9 | ], 10 | "includePlatforms": [], 11 | "excludePlatforms": [], 12 | "allowUnsafeCode": true, 13 | "overrideReferences": false, 14 | "precompiledReferences": [], 15 | "autoReferenced": true, 16 | "defineConstraints": [], 17 | "versionDefines": [], 18 | "noEngineReferences": false 19 | } -------------------------------------------------------------------------------- /Hydrogen.Entities.Hybrid/Hydrogen.Entities.Hybrid.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 44ab9bb22c816394bb1625d8e2ca2fd6 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Hydrogen.Entities.Hybrid/IConvertScriptableObjectToBlob.cs: -------------------------------------------------------------------------------- 1 | using Unity.Entities; 2 | 3 | namespace Hydrogen.Entities 4 | { 5 | /// 6 | /// Interface that defines a contract for converting a to a . 7 | /// 8 | /// The struct type our Blob Asset Reference will point to. 9 | public interface IConvertScriptableObjectToBlob 10 | where T0 : struct 11 | { 12 | /// 13 | /// Defines the Conversion function to convert this to a . 14 | /// 15 | /// The doing the converting. Allows us to build reference chains to other converted blobs. 16 | /// The constructed 17 | BlobAssetReference Convert(ScriptableObjectConversionSystem conversion); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Hydrogen.Entities.Hybrid/IConvertScriptableObjectToBlob.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a47df094a25347a7a212c8ce3af2ad06 3 | timeCreated: 1563759840 -------------------------------------------------------------------------------- /Hydrogen.Entities.Hybrid/ScriptableObjectConversionSystem.cs: -------------------------------------------------------------------------------- 1 | #define DETAIL_MARKERS 2 | using System; 3 | using Unity.Collections; 4 | using Unity.Collections.LowLevel.Unsafe; 5 | using Unity.Entities; 6 | using Unity.Profiling; 7 | using UnityEngine; 8 | using UnityEngine.Assertions; 9 | 10 | namespace Hydrogen.Entities 11 | { 12 | /// 13 | /// Defines a delegate that takes a and returns a 14 | /// 15 | /// The SO to convert. 16 | /// The , allowing us to get references to other converted blobs. 17 | /// The concrete type of the SO to be converted. 18 | /// The struct type our Blob asset reference points to. 19 | public delegate BlobAssetReference ScriptToBlobFunc( 20 | T0 src, 21 | ScriptableObjectConversionSystem convert) 22 | where T0 : ScriptableObject 23 | where T1 : struct; 24 | 25 | // TODO: Handle Acyclic graphs? Someone will try to do that eventually. Probably me... 26 | 27 | /// 28 | /// A System similar to the , but helps with converting to . 29 | /// 30 | [DisableAutoCreation] 31 | public class ScriptableObjectConversionSystem : ComponentSystem 32 | { 33 | private unsafe struct BlobData 34 | { 35 | [NativeDisableUnsafePtrRestriction] private byte* m_blobRef; 36 | 37 | public static BlobData Create(BlobAssetReference reference, int identifier) 38 | where T0 : struct 39 | { 40 | BlobData blobData = default; 41 | 42 | UnsafeUtility.CopyStructureToPtr(ref reference, &blobData.m_blobRef); 43 | 44 | return blobData; 45 | } 46 | 47 | public BlobAssetReference AsReference() 48 | where T0 : struct 49 | { 50 | Assert.IsTrue(m_blobRef != null); 51 | 52 | fixed (void* data = &m_blobRef) 53 | { 54 | UnsafeUtility.CopyPtrToStructure(data, out BlobAssetReference reference); 55 | 56 | return reference; 57 | } 58 | } 59 | } 60 | 61 | private NativeHashMap m_scriptableToBlob; 62 | 63 | private GameObjectConversionSystem m_goConversionSystem; 64 | 65 | public GameObjectConversionSystem GoConversionSystem 66 | { 67 | get 68 | { 69 | if (m_goConversionSystem != null) 70 | return m_goConversionSystem; 71 | 72 | m_goConversionSystem = World.GetExistingSystem(); 73 | Assert.IsNotNull( 74 | m_goConversionSystem, 75 | "Null GO Conversion system, did you mean to Get this System from the GameObject conversion world instead of the Destination World?"); 76 | 77 | return m_goConversionSystem; 78 | } 79 | } 80 | 81 | protected override void OnCreate() => 82 | m_scriptableToBlob = new NativeHashMap(100 * 1000, Allocator.Persistent); 83 | 84 | protected override void OnDestroy() 85 | { 86 | m_scriptableToBlob.Dispose(); 87 | } 88 | 89 | #if DETAIL_MARKERS 90 | private ProfilerMarker m_createBlob = new ProfilerMarker("ScriptableObjectConversion.CreateBlob"); 91 | 92 | private ProfilerMarker m_createBlobWithFunc = 93 | new ProfilerMarker("ScriptableObjectConversion.CreateBlobWithFunc"); 94 | #endif 95 | 96 | private BlobData ConvertBlob(IConvertScriptableObjectToBlob src, int identifier) 97 | where T0 : struct 98 | { 99 | #if DETAIL_MARKERS 100 | using (m_createBlob.Auto()) 101 | #endif 102 | { 103 | BlobAssetReference assetReference = src.Convert(this); 104 | 105 | return BlobData.Create(assetReference, identifier); 106 | } 107 | } 108 | 109 | private BlobData ConvertBlob(T0 obj, ScriptToBlobFunc func, int identifier) 110 | where T0 : ScriptableObject 111 | where T1 : struct 112 | { 113 | #if DETAIL_MARKERS 114 | using (m_createBlobWithFunc.Auto()) 115 | #endif 116 | { 117 | BlobAssetReference assetReference = func.Invoke(obj, this); 118 | 119 | return BlobData.Create(assetReference, identifier); 120 | } 121 | } 122 | 123 | protected override void OnUpdate() { } 124 | 125 | /// 126 | /// Converts a of to a blob reference of . 127 | /// The SO must implement 128 | /// 129 | /// The ScriptableObject to convert 130 | /// Concrete type of ScriptableObject 131 | /// Type of the struct our Blob asset will reference 132 | /// The constructed 133 | public BlobAssetReference GetBlob(T0 obj) 134 | where T0 : ScriptableObject, IConvertScriptableObjectToBlob 135 | where T1 : struct 136 | { 137 | int identifier = new Vector3Int(obj.GetInstanceID(), typeof(T0).GetHashCode(), typeof(T1).GetHashCode()) 138 | .GetHashCode(); 139 | 140 | if (PreCheck(obj, identifier, out BlobAssetReference blob)) 141 | return blob; 142 | 143 | BlobData data = ConvertBlob(obj, identifier); 144 | 145 | return PostCheck(identifier, data); 146 | } 147 | 148 | /// 149 | /// Converts a of to a blob reference of . 150 | /// The user must provide a manual conversion function. 151 | /// The SO need not implement , making it useful 152 | /// for converting pre-existing SO that are out of your control. 153 | /// 154 | /// The SO to convert. 155 | /// A delegate of . The concrete types must match. 156 | /// The concrete type of the SO. 157 | /// Type of the struct our Blob asset will reference. 158 | /// The constructed 159 | public BlobAssetReference GetBlob(T0 obj, ScriptToBlobFunc func) 160 | where T0 : ScriptableObject 161 | where T1 : struct 162 | { 163 | int identifier = new Vector2Int(obj.GetInstanceID(), func.GetHashCode()).GetHashCode(); 164 | 165 | if (PreCheck(obj, identifier, out BlobAssetReference blob)) 166 | return blob; 167 | 168 | BlobData data = ConvertBlob(obj, func, identifier); 169 | 170 | return PostCheck(identifier, data); 171 | } 172 | 173 | private BlobAssetReference PostCheck(int instanceId, BlobData data) 174 | where T0 : struct 175 | { 176 | if (m_scriptableToBlob.TryAdd(instanceId, data)) 177 | return data.AsReference(); 178 | 179 | data.AsReference().Dispose(); 180 | 181 | throw new InvalidOperationException(); 182 | } 183 | 184 | private bool PreCheck(T0 obj, int identifier, out BlobAssetReference blobAssetReference) 185 | where T0 : ScriptableObject 186 | where T1 : struct 187 | { 188 | blobAssetReference = default; 189 | 190 | if (obj == null) 191 | throw new NullReferenceException(); 192 | 193 | if (!m_scriptableToBlob.TryGetValue(identifier, out BlobData data)) 194 | return false; 195 | 196 | blobAssetReference = data.AsReference(); 197 | 198 | return true; 199 | } 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /Hydrogen.Entities.Hybrid/ScriptableObjectConversionSystem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 78ff4fc2117d41acadecd86568e68fe6 3 | timeCreated: 1559771196 -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Thomas Key 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ce6cf71b8a235bb40a6d70c96f455bca 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hydrogen.Entities 2 | 3 | A collection of helpers for working with Unity's ECS framework, particularly in setup and configuration authoring. 4 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 97f35be212c3095409434003d55730aa 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Samples~/ConfigFileLoading/Contents.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 24972df7c033c6a44be48d093c79802f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Samples~/ConfigFileLoading/Contents/ConfigFileLoading.unity: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!29 &1 4 | OcclusionCullingSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_OcclusionBakeSettings: 8 | smallestOccluder: 5 9 | smallestHole: 0.25 10 | backfaceThreshold: 100 11 | m_SceneGUID: 00000000000000000000000000000000 12 | m_OcclusionCullingData: {fileID: 0} 13 | --- !u!104 &2 14 | RenderSettings: 15 | m_ObjectHideFlags: 0 16 | serializedVersion: 9 17 | m_Fog: 0 18 | m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} 19 | m_FogMode: 3 20 | m_FogDensity: 0.01 21 | m_LinearFogStart: 0 22 | m_LinearFogEnd: 300 23 | m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} 24 | m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} 25 | m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} 26 | m_AmbientIntensity: 1 27 | m_AmbientMode: 0 28 | m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} 29 | m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} 30 | m_HaloStrength: 0.5 31 | m_FlareStrength: 1 32 | m_FlareFadeSpeed: 3 33 | m_HaloTexture: {fileID: 0} 34 | m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} 35 | m_DefaultReflectionMode: 0 36 | m_DefaultReflectionResolution: 128 37 | m_ReflectionBounces: 1 38 | m_ReflectionIntensity: 1 39 | m_CustomReflection: {fileID: 0} 40 | m_Sun: {fileID: 0} 41 | m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} 42 | m_UseRadianceAmbientProbe: 0 43 | --- !u!157 &3 44 | LightmapSettings: 45 | m_ObjectHideFlags: 0 46 | serializedVersion: 11 47 | m_GIWorkflowMode: 1 48 | m_GISettings: 49 | serializedVersion: 2 50 | m_BounceScale: 1 51 | m_IndirectOutputScale: 1 52 | m_AlbedoBoost: 1 53 | m_EnvironmentLightingMode: 0 54 | m_EnableBakedLightmaps: 1 55 | m_EnableRealtimeLightmaps: 1 56 | m_LightmapEditorSettings: 57 | serializedVersion: 12 58 | m_Resolution: 2 59 | m_BakeResolution: 40 60 | m_AtlasSize: 1024 61 | m_AO: 0 62 | m_AOMaxDistance: 1 63 | m_CompAOExponent: 1 64 | m_CompAOExponentDirect: 0 65 | m_ExtractAmbientOcclusion: 0 66 | m_Padding: 2 67 | m_LightmapParameters: {fileID: 0} 68 | m_LightmapsBakeMode: 1 69 | m_TextureCompression: 1 70 | m_FinalGather: 0 71 | m_FinalGatherFiltering: 1 72 | m_FinalGatherRayCount: 256 73 | m_ReflectionCompression: 2 74 | m_MixedBakeMode: 2 75 | m_BakeBackend: 1 76 | m_PVRSampling: 1 77 | m_PVRDirectSampleCount: 32 78 | m_PVRSampleCount: 512 79 | m_PVRBounces: 2 80 | m_PVREnvironmentSampleCount: 256 81 | m_PVREnvironmentReferencePointCount: 2048 82 | m_PVRFilteringMode: 1 83 | m_PVRDenoiserTypeDirect: 1 84 | m_PVRDenoiserTypeIndirect: 1 85 | m_PVRDenoiserTypeAO: 1 86 | m_PVRFilterTypeDirect: 0 87 | m_PVRFilterTypeIndirect: 0 88 | m_PVRFilterTypeAO: 0 89 | m_PVREnvironmentMIS: 1 90 | m_PVRCulling: 1 91 | m_PVRFilteringGaussRadiusDirect: 1 92 | m_PVRFilteringGaussRadiusIndirect: 5 93 | m_PVRFilteringGaussRadiusAO: 2 94 | m_PVRFilteringAtrousPositionSigmaDirect: 0.5 95 | m_PVRFilteringAtrousPositionSigmaIndirect: 2 96 | m_PVRFilteringAtrousPositionSigmaAO: 1 97 | m_ExportTrainingData: 0 98 | m_TrainingDataDestination: TrainingData 99 | m_LightingDataAsset: {fileID: 0} 100 | m_UseShadowmask: 1 101 | --- !u!196 &4 102 | NavMeshSettings: 103 | serializedVersion: 2 104 | m_ObjectHideFlags: 0 105 | m_BuildSettings: 106 | serializedVersion: 2 107 | agentTypeID: 0 108 | agentRadius: 0.5 109 | agentHeight: 2 110 | agentSlope: 45 111 | agentClimb: 0.4 112 | ledgeDropHeight: 0 113 | maxJumpAcrossDistance: 0 114 | minRegionArea: 2 115 | manualCellSize: 0 116 | cellSize: 0.16666667 117 | manualTileSize: 0 118 | tileSize: 256 119 | accuratePlacement: 0 120 | debug: 121 | m_Flags: 0 122 | m_NavMeshData: {fileID: 0} 123 | --- !u!1 &401652032 124 | GameObject: 125 | m_ObjectHideFlags: 0 126 | m_CorrespondingSourceObject: {fileID: 0} 127 | m_PrefabInstance: {fileID: 0} 128 | m_PrefabAsset: {fileID: 0} 129 | serializedVersion: 6 130 | m_Component: 131 | - component: {fileID: 401652033} 132 | - component: {fileID: 401652034} 133 | m_Layer: 0 134 | m_Name: FileLoadingDriver 135 | m_TagString: Untagged 136 | m_Icon: {fileID: 0} 137 | m_NavMeshLayer: 0 138 | m_StaticEditorFlags: 0 139 | m_IsActive: 1 140 | --- !u!4 &401652033 141 | Transform: 142 | m_ObjectHideFlags: 0 143 | m_CorrespondingSourceObject: {fileID: 0} 144 | m_PrefabInstance: {fileID: 0} 145 | m_PrefabAsset: {fileID: 0} 146 | m_GameObject: {fileID: 401652032} 147 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 148 | m_LocalPosition: {x: 0, y: 0, z: 0} 149 | m_LocalScale: {x: 1, y: 1, z: 1} 150 | m_Children: [] 151 | m_Father: {fileID: 0} 152 | m_RootOrder: 0 153 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 154 | --- !u!114 &401652034 155 | MonoBehaviour: 156 | m_ObjectHideFlags: 0 157 | m_CorrespondingSourceObject: {fileID: 0} 158 | m_PrefabInstance: {fileID: 0} 159 | m_PrefabAsset: {fileID: 0} 160 | m_GameObject: {fileID: 401652032} 161 | m_Enabled: 1 162 | m_EditorHideFlags: 0 163 | m_Script: {fileID: 11500000, guid: 5feedfb56761f0c4ab76171409ced649, type: 3} 164 | m_Name: 165 | m_EditorClassIdentifier: 166 | m_fileName: TestConfig.ini 167 | m_iniContents: 'foo=42 168 | 169 | bar="hello world" 170 | 171 | baz=12.34 172 | 173 | qux=Slow 174 | 175 | ' 176 | -------------------------------------------------------------------------------- /Samples~/ConfigFileLoading/Contents/ConfigFileLoading.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 378a0283481a92c42af83964cb124948 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Samples~/ConfigFileLoading/README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | This sample demonstrates a simple mapping of ini properties to a blob asset, 4 | and usage of the conversion framework without matching Authoring/SO components. 5 | 6 | # The MonoBehaviour Components 7 | 8 | ## IniFileExample 9 | 10 | This script parses the provided IniContents string field, and sets the "file" name for the ini file data. 11 | It then matches the fields from the file to the [IniFile](#inifile) described below. 12 | 13 | # The DOTS Components 14 | 15 | ## IniFile 16 | 17 | This struct is the Blob Asset and contains the corresponding fields. 18 | - Name (BlobString) - the name of the ini file. 19 | - Bar (BlobString) 20 | - Foo (int) 21 | - Baz (float) 22 | - Qux (Speed) - uses the Speed Enum described below. 23 | 24 | ## Speed 25 | An enum to demonstrate enum parsing and conversion has 3 values. 26 | - Slow 27 | - Medium 28 | - Fast 29 | 30 | # The DOTS Systems 31 | 32 | ## IniFileConvertSystem 33 | 34 | Derives from ```SingletonBlobConvertSystem``` to handle the boilerplate for us. 35 | 36 | ## IniFileChangedSystem 37 | 38 | Derives from ```SingletonBlobChangedComponentSystem``` to report the converted singleton data and verify success. 39 | Handles the boilerplate for us. -------------------------------------------------------------------------------- /Samples~/ConfigFileLoading/README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 59e56f2411362bf48b2ab4ed1fdc560a 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Samples~/ConfigFileLoading/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 379543cd9c3636d4da12fda904e719b4 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Samples~/ConfigFileLoading/Scripts/IniFileExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using Hydrogen.Entities; 5 | using Unity.Collections; 6 | using Unity.Entities; 7 | using UnityEngine; 8 | using UnityEngine.Assertions; 9 | 10 | [assembly: RegisterGenericComponentType(typeof(BlobRefData))] 11 | [assembly: RegisterGenericComponentType(typeof(SingletonConverter>))] 12 | 13 | namespace Hydrogen.Entities 14 | { 15 | public class IniFileExample : MonoBehaviour 16 | { 17 | private const string kFileName = "TestConfig.ini"; 18 | private const string kIniContents = "foo=42\nbar=\"hello world\"\nbaz=12.34\nqux=Slow\n"; 19 | 20 | [SerializeField] private string m_fileName = kFileName; 21 | [SerializeField, Multiline(8)] private string m_iniContents = kIniContents; 22 | 23 | private void Start() 24 | { 25 | using (var reader = new StringReader(m_iniContents)) 26 | { 27 | var builder = new BlobBuilder(Allocator.Temp); 28 | BlobAssetReference configReference; 29 | 30 | try 31 | { 32 | ref IniFile root = ref builder.ConstructRoot(); 33 | 34 | builder.AllocateString(ref root.Name, m_fileName); 35 | 36 | string line; 37 | while ((line = reader.ReadLine()) != null) 38 | { 39 | string[] pairStr = line.Split('='); 40 | if(pairStr.Length != 2 || string.IsNullOrEmpty(pairStr[0])) continue; 41 | 42 | switch (pairStr[0]) 43 | { 44 | case "foo": 45 | int.TryParse(pairStr[1], out root.Foo); 46 | break; 47 | case "bar": 48 | if (root.Bar.Length != 0) continue; 49 | builder.AllocateString(ref root.Bar, pairStr[1]); 50 | break; 51 | case "baz": 52 | float.TryParse(pairStr[1], out root.Baz); 53 | break; 54 | case "qux": 55 | Enum.TryParse(pairStr[1], true, out root.Qux); 56 | break; 57 | } 58 | } 59 | 60 | configReference = builder.CreateBlobAssetReference(Allocator.Persistent); 61 | } 62 | finally 63 | { 64 | builder.Dispose(); 65 | } 66 | 67 | Assert.IsTrue(configReference.IsCreated); 68 | 69 | BlobRefData blobRef = configReference; 70 | SingletonConverter> converter = blobRef; 71 | 72 | EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager; 73 | Entity entity = entityManager.CreateEntity(typeof(SingletonConverter>)); 74 | entityManager.SetComponentData(entity, converter); 75 | } 76 | } 77 | } 78 | 79 | public sealed class IniFileConvertSystem : SingletonBlobConvertSystem { } 80 | 81 | public sealed class IniFileChangedSystem : SingletonBlobChangedComponentSystem 82 | { 83 | protected override void OnUpdate() 84 | { 85 | ref IniFile iniFile = ref GetSingleton>().Resolve; 86 | 87 | var strBuilder = new StringBuilder(1024); 88 | strBuilder.AppendLine($"Ini File Name: {iniFile.Name.ToString()}"); 89 | strBuilder.AppendLine($"Foo: {iniFile.Foo:D}"); 90 | strBuilder.AppendLine($"Bar: {iniFile.Bar.ToString()}"); 91 | strBuilder.AppendLine($"Baz: {iniFile.Baz:N}"); 92 | strBuilder.AppendLine($"Qux Speed is: {iniFile.Qux.ToString()}"); 93 | 94 | Debug.Log(strBuilder.ToString()); 95 | } 96 | } 97 | 98 | public struct IniFile 99 | { 100 | public BlobString Name; 101 | public BlobString Bar; 102 | public int Foo; 103 | public float Baz; 104 | public Speed Qux; 105 | } 106 | 107 | public enum Speed 108 | { 109 | Slow, 110 | Medium, 111 | Fast 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /Samples~/ConfigFileLoading/Scripts/IniFileExample.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5feedfb56761f0c4ab76171409ced649 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.periodyc.hydrogen.entities", 3 | "version": "0.2.2-preview.1", 4 | "displayName": "Hydrogen Entities", "description": "A collection of helpers for working with Unity's ECS framework.", 5 | "unity": "2019.3", 6 | "dependencies": { 7 | "com.unity.entities": "0.3.0-preview.4", 8 | "com.unity.collections": "0.3.0-preview.0", 9 | "com.unity.jobs": "0.2.1-preview.3", 10 | "com.unity.test-framework": "1.1.3" 11 | }, 12 | "samples": [ 13 | { 14 | "displayName": "Simple World Converters", 15 | "description": "Shows how to implement and use the basic Converters.", 16 | "path": "Samples~/SimpleWorldConverter" 17 | }, 18 | { 19 | "displayName": "Config File Loading", 20 | "description": "Shows how to load an ini file from disk and store it in a blob singleton.", 21 | "path": "Samples~/ConfigFileLoading" 22 | }, 23 | { 24 | "displayName": "Simple Database Example", 25 | "description": "Shows how to implement a simple Key-value database with Blob Assets and NativeHashMap.", 26 | "path": "Samples~/SimpleDatabaseExample" 27 | } 28 | ], 29 | "keywords": [ 30 | "entities", 31 | "utility" 32 | ], 33 | "author": { 34 | "name": "Thomas Key", 35 | "email": "thomas.key@periodyc.com", 36 | "url": "https://www.periodyc.com" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7b8f06830791a274691969c3f9deac77 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------